Socket
Gaining Access
Nmap scan:
$ nmap -p- --min-rate 3000 10.129.71.152
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-27 00:57 EDT
Nmap scan report for 10.129.71.152
Host is up (0.17s latency).
Not shown: 65521 closed tcp ports (conn-refused)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
5789/tcp open unknownWe have to add qreader.htb to our /etc/hosts file. I ran a detailed scan on port 80 and found it is a Python based server:
80/tcp open http Apache httpd 2.4.52
| http-server-header:
| Apache/2.4.52 (Ubuntu)
|_ Werkzeug/2.1.2 Python/3.10.6Qreader
Website presents some kind of QR Code maker / reader application:

We can actually download the application below and view the source code:

Additionally, we can submit a report when something goes wrong:

Interesting. When we download the file, we will get a binary and a test image:
We can try to reverse engineer this application. I tried with ghidra but it produced a lot of code that I could not read. Instead, we need to use Python Decompilation as the web server runs the application in Python based on the earlier nmap scan of port 80.
We can decompile this using pyi-archive_viwer qreader, and then convert it into a pyc file via uncompyle6. Then, we can do source code analysis of the app.
Websocket SQL Injection
When reading the source code, we come across this:
This connects to a websocket, which is on port 5789 after running an nmap scan to confirm. It appears to send some information via ws_connect to the /version directory.
We can make a script to communicate with this port via websocket and send a JSON object for the version as per the script above.
The output is as shown:
I tried playing around with the version number, and it would raise an Invalid Version! error each time it wasn't set to 0.0.2. When I appended a ", it would print nothing, indicating that there was an error in the backend since the code catches errors.
I played around with some UNION SQL injection, and found that the payload of 0.0.2"UNION SELECT 1,2,3,4;-- - generated no errors. Changing the number of columns results in an error, indicating that this application is indeed vulnerable to SQL Injection.
We can confirm the DBMS used by trying different version commands, and I found that sqlite_version() works.
With this, we can extract the tables present in sqlite_schema.
There's a users table, and we can try to extract a username and password from it.
Great! The hash can be cracked on crackstation:

Now, we need to find a username. I looked through the other tables of reports and answers.
This was done using group_concat(answers), and it seems that the user is either Mike, Thomas Keller or Json. I tested ssh with a wordlist of possible usernames generated from their names, and found that tkeller is the right user via hydra.
We can then ssh in as tkeller and grab the user flag.

Privilege Escalation
Sudo Pyinstaller
Checking the sudo privileges we have, I found that we can run bash script as root.
Here's the contents of that script:
So this script checks for a .spec file extension, and takes an $action argument from us. It appears that the build option runs pyinstaller on the file we choose. What pyinstaller does is just run the code we specify.
As such, the exploit is simple.

Pretty straightforward machine. The hard part was the SQL injection.