固件模拟 Case Study (3)

Catalpa 网络安全爱好者

模拟 DIR-815 固件。

改造 firmadyne

剥离数据库

firmadyne 默认会创建并使用数据库,用于记录和统计固件信息,然而我们在模拟固件的过程中通常无需这一功能,所以可以修改其代码取消数据库依赖。

修改 firmadyne/scripts/getArch.sh,删除操作数据库的代码

1
2
注释掉下面这句
# psql -d firmware -U firmadyne -h 127.0.0.1 -q -c "UPDATE image SET arch = '$ARCHEND' WHERE id = $IID;"

修改 firmadyne/scripts/makeImage.sh

1
2
3
4
5
6
注意
原脚本中以下这段代码
TARBALL_SIZE=$(tar ztvf "${TARBALL_DIR}/${IID}.tar.gz" --totals 2>&1 |tail -1|cut -f4 -d' ')
如果你使用的 tar 会输出中文信息,那么默认 cut -f4 获取到的 IMAGE_SIZE 将是错误的,需要修改为
TARBALL_SIZE=$(tar ztvf "${TARBALL_DIR}/${IID}.tar.gz" --totals 2>&1 |tail -1|cut -f2 -d' ')
请根据你的实际情况进行修改
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
#!/bin/bash

set -e
set -u

if [ -e ./firmadyne.config ]; then
source ./firmadyne.config
elif [ -e ../firmadyne.config ]; then
source ../firmadyne.config
else
echo "Error: Could not find 'firmadyne.config'!"
exit 1
fi

if check_number $1; then
echo "Usage: makeImage.sh <image ID> [<architecture]"
exit 1
fi
IID=${1}

if check_root; then
echo "Error: This script requires root privileges!"
exit 1
fi

if [ $# -eq 1 ]; then
echo "Error: No arch selected!"
exit 1
fi

if check_arch "${2}"; then
echo "Error: Invalid architecture!"
exit 1
fi
ARCH=${2}

echo "----Running----"
WORK_DIR=`get_scratch ${IID}` # no need to change
IMAGE=`get_fs ${IID}` # no need to change
IMAGE_DIR=`get_fs_mount ${IID}` # no need to change
CONSOLE=`get_console ${ARCH}`
LIBNVRAM=`get_nvram ${ARCH}`

echo "----Creating working directory ${WORK_DIR}----"
mkdir -p "${WORK_DIR}"
chmod a+rwx "${WORK_DIR}"
chown -R "${USER}" "${WORK_DIR}"
chgrp -R "${USER}" "${WORK_DIR}"

if [ ! -e "${TARBALL_DIR}/${IID}.tar.gz" ]; then
echo "Error: Cannot find tarball of root filesystem for ${IID}!"
exit 1
fi


TARBALL_SIZE=$(tar ztvf "${TARBALL_DIR}/${IID}.tar.gz" --totals 2>&1 |tail -1|cut -f2 -d' ')
MINIMUM_IMAGE_SIZE=$((TARBALL_SIZE + 10 * 1024 * 1024))
echo "----The size of root filesystem '${TARBALL_DIR}/${IID}.tar.gz' is $TARBALL_SIZE-----"
IMAGE_SIZE=8388608
while [ $IMAGE_SIZE -le $MINIMUM_IMAGE_SIZE ]
do
IMAGE_SIZE=$((IMAGE_SIZE*2))
done

echo "----Creating QEMU Image ${IMAGE} with size ${IMAGE_SIZE}----"
qemu-img create -f raw "${IMAGE}" $IMAGE_SIZE
chmod a+rw "${IMAGE}"

echo "----Creating Partition Table----"
echo -e "o\nn\np\n1\n\n\nw" | /sbin/fdisk "${IMAGE}"

echo "----Mounting QEMU Image----"
DEVICE=$(get_device "$(kpartx -a -s -v "${IMAGE}")")
sleep 1
echo "----Device mapper created at ${DEVICE}----"

echo "----Creating Filesystem----"
mkfs.ext2 "${DEVICE}"
sync

echo "----Making QEMU Image Mountpoint at ${IMAGE_DIR}----"
if [ ! -e "${IMAGE_DIR}" ]; then
mkdir "${IMAGE_DIR}"
chown "${USER}" "${IMAGE_DIR}"
fi

echo "----Mounting QEMU Image Partition 1----"
mount "${DEVICE}" "${IMAGE_DIR}"

echo "----Extracting Filesystem Tarball to Mountpoint----"
tar -xf "${TARBALL_DIR}/${IID}.tar.gz" -C "${IMAGE_DIR}"

echo "----Creating FIRMADYNE Directories----"
mkdir "${IMAGE_DIR}/firmadyne/"
mkdir "${IMAGE_DIR}/firmadyne/libnvram/"
mkdir "${IMAGE_DIR}/firmadyne/libnvram.override/"

echo "----Patching Filesystem (chroot)----"
cp $(which busybox) "${IMAGE_DIR}"
cp "${SCRIPT_DIR}/fixImage.sh" "${IMAGE_DIR}"
chroot "${IMAGE_DIR}" /busybox ash /fixImage.sh
rm "${IMAGE_DIR}/fixImage.sh"
rm "${IMAGE_DIR}/busybox"

echo "----Setting up FIRMADYNE----"
cp "${CONSOLE}" "${IMAGE_DIR}/firmadyne/console"
chmod a+x "${IMAGE_DIR}/firmadyne/console"
mknod -m 666 "${IMAGE_DIR}/firmadyne/ttyS1" c 4 65

cp "${LIBNVRAM}" "${IMAGE_DIR}/firmadyne/libnvram.so"
chmod a+x "${IMAGE_DIR}/firmadyne/libnvram.so"

cp "${SCRIPT_DIR}/preInit.sh" "${IMAGE_DIR}/firmadyne/preInit.sh"
chmod a+x "${IMAGE_DIR}/firmadyne/preInit.sh"

echo "----Unmounting QEMU Image----"
sync
umount "${DEVICE}"
echo "----Deleting device mapper----"
kpartx -d "${IMAGE}"
losetup -d "${DEVICE}" &>/dev/null
dmsetup remove $(basename "$DEVICE") &>/dev/null

修改 inferNetwork.sh

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
#!/bin/bash

set -e
set -u

if [ -e ./firmadyne.config ]; then
source ./firmadyne.config
elif [ -e ../firmadyne.config ]; then
source ../firmadyne.config
else
echo "Error: Could not find 'firmadyne.config'!"
exit 1
fi

if check_number $1; then
echo "Usage: inferNetwork.sh <image ID> [<architecture>]"
exit 1
fi
IID=${1}

if [ $# -eq 1 ]; then
echo "Error: No arch selected!"
exit 1
fi

if check_arch "${2}"; then
echo "Error: Invalid architecture!"
exit 1
fi

ARCH=${2}

echo "Running firmware ${IID}: terminating after 60 secs..."
timeout --preserve-status --signal SIGINT 60 "${SCRIPT_DIR}/run.${ARCH}.sh" "${IID}"
sleep 1

echo "Inferring network..."
"${SCRIPT_DIR}/makeNetwork.py" -i "${IID}" -q -o -a "${ARCH}" -S "${SCRATCH_DIR}"

echo "Done!"

模拟固件

按照 firmadyne 官方给出的步骤,先尝试对固件进行模拟。

下载 DIR-815 固件,放在 firmadyne 目录下,先对固件解包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
python3 ./sources/extractor/extractor.py -np -nk ./DIR815A1_FW104b03.bin

输出信息

/home/iot/Tools/firmadyne/DIR815A1_FW104b03.bin
>> MD5: 34b013a393503d9b9d0734ecd2ee28dd
>> Tag: DIR815A1_FW104b03.bin_34b013a393503d9b9d0734ecd2ee28dd
>> Temp: /tmp/tmpc9h97s71
>> Status: Kernel: True, Rootfs: False, Do_Kernel: False, Do_Rootfs: True
>> Recursing into archive ...
>>>> Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 2680303 bytes, 1515 inodes, blocksize: 524288 bytes, created: 2013-05-15 10:04:17
>>>> Found Linux filesystem in /tmp/tmpc9h97s71/_DIR815A1_FW104b03.bin.extracted/squashfs-root!
>> Skipping: completed!
>> Cleaning up /tmp/tmpc9h97s71...

解包后在 images 目录下能够看到一个压缩包文件,我们把它的名字修改为 1.tar.gz

1
mv ./images/DIR815A1_FW104b03.bin_34b013a393503d9b9d0734ecd2ee28dd.tar.gz ./images/1.tar.gz

获取固件架构

1
2
3
4
5
./scripts/getArch.sh ./images/1.tar.gz

输出信息

./bin/busybox: mipsel

构建镜像

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
sudo ./scripts/makeImage.sh 1 mipsel

输出信息

----Running----
----Creating working directory /home/iot/Tools/firmadyne//scratch//1/----
----The size of root filesystem '/home/iot/Tools/firmadyne//images//1.tar.gz' is 14008320-----
----Creating QEMU Image /home/iot/Tools/firmadyne//scratch//1//image.raw with size 33554432----
Formatting '/home/iot/Tools/firmadyne//scratch//1//image.raw', fmt=raw size=33554432
----Creating Partition Table----

欢迎使用 fdisk (util-linux 2.34)。
更改将停留在内存中,直到您决定将更改写入磁盘。
使用写入命令前请三思。

设备不包含可识别的分区表。
创建了一个磁盘标识符为 0x75dcd7ac 的新 DOS 磁盘标签。

命令(输入 m 获取帮助): 创建了一个磁盘标识符为 0xd763342d 的新 DOS 磁盘标签。

命令(输入 m 获取帮助): 分区类型
p 主分区 (0个主分区,0个扩展分区,4空闲)
e 扩展分区 (逻辑分区容器)
选择 (默认 p): 分区号 (1-4, 默认 1): 第一个扇区 (2048-65535, 默认 2048): Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-65535, 默认 65535):
创建了一个新分区 1,类型为“Linux”,大小为 31 MiB。

命令(输入 m 获取帮助): 分区表已调整。
正在同步磁盘。

----Mounting QEMU Image----
----Device mapper created at /dev/mapper/loop12p1----
----Creating Filesystem----
mke2fs 1.45.5 (07-Jan-2020)
丢弃设备块: 完成
创建含有 7936 个块(每块 4k)和 7936 个inode的文件系统

正在分配组表: 完成
正在写入inode表: 完成
写入超级块和文件系统账户统计信息: 已完成

----Making QEMU Image Mountpoint at /home/iot/Tools/firmadyne//scratch//1//image/----
----Mounting QEMU Image Partition 1----
----Extracting Filesystem Tarball to Mountpoint----
----Creating FIRMADYNE Directories----
----Patching Filesystem (chroot)----
Creating /etc/TZ!
Creating /etc/hosts!
Creating /etc/passwd!
Warning: Recreating device nodes!
----Setting up FIRMADYNE----
----Unmounting QEMU Image----
----Deleting device mapper----
loop deleted : /dev/loop12

此时在 scratch/1/ 目录下可以找到构建好的 image.raw 镜像。

模拟网络环境

1
2
3
4
5
6
7
8
9
./scripts/inferNetwork.sh 1 mipsel

输出信息

Running firmware 1: terminating after 60 secs...
qemu-system-mipsel: terminating on signal 2 from pid 30275 (timeout)
Inferring network...
Interfaces: [('br0', '192.168.0.1')]
Done!

可以看到 firmadyne 获取到镜像的网卡 br0 的 ip 地址为 192.168.0.1,并且在 ./scratch/1/ 目录下生成了 run.sh 启动脚本,我们执行这个脚本看看能否访问到固件的 web 界面。

1
./scratch/1/run.sh

启动后进入 shell,看一下网卡信息

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
br0       Link encap:Ethernet  HWaddr 00:DE:FA:1A:01:00  
inet addr:192.168.0.1 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::2de:faff:fe1a:100/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:46 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:10386 (10.1 KiB)

eth0 Link encap:Ethernet HWaddr 52:54:00:12:34:56
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

eth1 Link encap:Ethernet HWaddr 52:54:00:12:34:57
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

eth2 Link encap:Ethernet HWaddr 00:DE:FA:1A:01:00
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:33 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:200
RX bytes:0 (0.0 B) TX bytes:9348 (9.1 KiB)

eth3 Link encap:Ethernet HWaddr 00:DE:FA:3A:01:00
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:200
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

ip6tnl0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
NOARP MTU:1452 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

sit0 Link encap:IPv6-in-IPv4
NOARP MTU:1480 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

tunl0 Link encap:UNSPEC HWaddr 00-00-00-00-B5-7F-00-00-00-00-00-00-00-00-00-00
NOARP MTU:1480 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

只有 br0、eth2、lo 三个网卡被启用,且只有 br0 拥有 IP 地址,此时宿主机和虚拟机之间网络是不通的。

(ctrl-a x 退出虚拟机)

配置网络

既然自动配置的网络无法正常使用,我们尝试手动配置。(参考)

创建网桥

1
2
3
4
5
6
7
8
9
10
11
ifconfig <你的网卡名称(能上网的那张)> down    # 首先关闭宿主机网卡接口
brctl addbr br0 # 添加名为 br0 的网桥
brctl addif br0 <你的网卡名称> # 在 br0 中添加一个接口
brctl stp br0 off # 如果只有一个网桥,则关闭生成树协议
brctl setfd br0 1 # 设置 br0 的转发延迟
brctl sethello br0 1 # 设置 br0 的 hello 时间
ifconfig br0 0.0.0.0 promisc up # 启用 br0 接口
ifconfig <你的网卡名称> 0.0.0.0 promisc up # 启用网卡接口
dhclient br0 # 从 dhcp 服务器获得 br0 的 IP 地址
brctl show br0 # 查看虚拟网桥列表
brctl showstp br0 # 查看 br0 的各接口信息

创建 TAP 虚拟网卡

1
2
3
4
tunctl -t tap0 -u root              # 创建一个 tap0 接口,只允许 root 用户访问
brctl addif br0 tap0 # 在虚拟网桥中增加一个 tap0 接口
ifconfig tap0 0.0.0.0 promisc up # 启用 tap0 接口
brctl showstp br0 # 显示 br0 的各个接口

配置无误的话网桥信息应该如下

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
br0
bridge id 8000.000c29e5d458
designated root 8000.000c29e5d458
root port 0 path cost 0
max age 20.00 bridge max age 20.00
hello time 1.00 bridge hello time 1.00
forward delay 1.00 bridge forward delay 1.00
ageing time 300.00
hello timer 0.00 tcn timer 0.00
topology change timer 0.00 gc timer 151.22
flags


ens33 (1)
port id 8001 state forwarding
designated root 8000.000c29e5d458 path cost 4
designated bridge 8000.000c29e5d458 message age timer 0.00
designated port 8001 forward delay timer 0.00
designated cost 0 hold timer 0.00
flags

tap0 (2)
port id 8002 state disabled
designated root 8000.000c29e5d458 path cost 100
designated bridge 8000.000c29e5d458 message age timer 0.00
designated port 8002 forward delay timer 0.00
designated cost 0 hold timer 0.00
flags

启动命令

将启动命令中网卡部分替换为我们自己配置的信息,得到新的启动命令

1
qemu-system-mipsel -m 256 -M malta -kernel /home/iot/Tools/firmadyne/binaries/vmlinux.mipsel -drive if=ide,format=raw,file=/home/iot/Tools/firmadyne/scratch/1/image.raw -append "root=/dev/sda1 console=ttyS0 nandsim.parts=64,64,64,64,64,64,64,64,64,64 rdinit=/firmadyne/preInit.sh rw debug ignore_loglevel print-fatal-signals=1 user_debug=31 firmadyne.syscall=0" -nographic -net nic -net tap,ifname=tap0,script=no,downscript=no

虚拟机启动后在宿主机查看 br0 信息

1
2
3
4
5
6
7
tap0 (2)
port id 8002 state forwarding
designated root 8000.000c29e5d458 path cost 100
designated bridge 8000.000c29e5d458 message age timer 0.00
designated port 8002 forward delay timer 0.00
designated cost 0 hold timer 0.00
flags

其中 tap0 的状态应该由 disabled 变成 forwarding。

在虚拟机中 ping 宿主机,发现还是无法连通,尝试启用 eth0 网卡,并赋予和宿主机 br0 相同网段的 IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ifconfig eth0 up
ifconfig eth0 192.168.37.150 netmask 255.255.255.0

配置后虚拟机 eth0 信息

eth0 Link encap:Ethernet HWaddr 52:54:00:12:34:56
inet addr:192.168.37.150 Bcast:192.168.37.255 Mask:255.255.255.0
inet6 addr: fe80::5054:ff:fe12:3456/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:11 errors:0 dropped:0 overruns:0 frame:0
TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3355 (3.2 KiB) TX bytes:408 (408.0 B)
Interrupt:10 Base address:0x1020

配置好之后 ping 宿主机

1
2
3
4
5
6
ping 192.168.37.145

输出信息

ping 192.168.37.145
192.168.37.145 is alive!

至此我们成功解决了网络互通问题,但是在宿主机尝试访问 web 服务时,发现还是无法连接。

配置分析

首先查看默认环境下虚拟机开放的端口

1
2
3
4
5
6
7
8
9
10
11
12
netstat -tnlp

输出信息

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 192.168.0.1:49152 0.0.0.0:* LISTEN 2105/httpd
tcp 0 0 192.168.0.1:80 0.0.0.0:* LISTEN 2105/httpd
tcp 0 0 0.0.0.0:53 0.0.0.0:* LISTEN 2118/dnsmasq
tcp 0 0 0.0.0.0:63481 0.0.0.0:* LISTEN 224/fakedns
tcp 0 0 :::53 :::* LISTEN 2118/dnsmasq
tcp 0 0 :::63481 :::* LISTEN 224/fakedns

可以看到 httpd 服务默认监听地址 192.168.0.1:80,然而 192.168.0.1 网段无法访问,所以访问 web 服务失败。

ps 看看 httpd 服务的启动命令

1
2
3
4
5
ps | grep 2105

输出信息

2105 root 1564 S httpd -f /var/run/httpd.conf

发现 httpd 具有一个 httpd.conf 的配置文件,内容如下

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
Umask 026
PIDFile /var/run/httpd.pid
#LogGMT On
#ErrorLog /dev/console

Tuning
{
NumConnections 15
BufSize 12288
InputBufSize 4096
ScriptBufSize 4096
NumHeaders 100
Timeout 60
ScriptTimeout 60
}

Control
{
Types
{
text/html { html htm }
text/xml { xml }
text/plain { txt }
image/gif { gif }
image/jpeg { jpg }
text/css { css }
application/octet-stream { * }
}
Specials
{
Dump { /dump }
CGI { cgi }
Imagemap { map }
Redirect { url }
}
External
{
/usr/sbin/phpcgi { php }
}
}

Server
{
ServerName "Linux, HTTP/1.1, DIR-815 Ver 1.04"
ServerId "LAN-1"
Family inet
Interface br0
Address 192.168.0.1
Port 80
Virtual
{
AnyHost
Control
{
Alias /
Location /htdocs/web
IndexNames { index.php }
External
{
/usr/sbin/phpcgi { txt }
}
External
{
/usr/sbin/phpcgi { router_info.xml }
/usr/sbin/phpcgi { post_login.xml }
}
}
Control
{
Alias /smart404
Location /htdocs/smart404
}
Control
{
Alias /HNAP1
Location /htdocs/HNAP1
External
{
/usr/sbin/hnap { hnap }
}
IndexNames { index.hnap }
}
}
}
Server
{
ServerName "Linux, HTTP/1.1, DIR-815 Ver 1.04"
ServerId "LAN-1"
Family inet
Interface br0
Port 1900
Address 239.255.255.250
Datagrams On
Virtual
{
AnyHost
Control
{
Alias /
Location /htdocs/upnp/docs/LAN-1
External
{
/htdocs/upnp/ssdpcgi { * }
}
}
}
}

Server
{
ServerName "Linux, UPnP/1.0, DIR-815 Ver 1.04"
ServerId "LAN-1"
Family inet
Interface br0
Address 192.168.0.1
Port 49152
Virtual
{
AnyHost
Control
{
Alias /
Location /htdocs/upnp/docs/LAN-1
}
}
}

设备的 web 服务被绑定在 br0 网卡上,我们需要修改配置文件,将 web 服务绑定在 eth0 网卡,监听地址 0.0.0.0:80。

修改 images/1.tar.gz 在根目录下创建一个 fake.conf,内容如下

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
Umask 026
PIDFile /var/run/httpd.pid
#LogGMT On
#ErrorLog /dev/console

Tuning
{
NumConnections 15
BufSize 12288
InputBufSize 4096
ScriptBufSize 4096
NumHeaders 100
Timeout 60
ScriptTimeout 60
}

Control
{
Types
{
text/html { html htm }
text/xml { xml }
text/plain { txt }
image/gif { gif }
image/jpeg { jpg }
text/css { css }
application/octet-stream { * }
}
Specials
{
Dump { /dump }
CGI { cgi }
Imagemap { map }
Redirect { url }
}
External
{
/usr/sbin/phpcgi { php }
}
}

Server
{
ServerName "Linux, HTTP/1.1, DIR-815 Ver 1.04"
ServerId "LAN-1"
Family inet
Interface eth0
Address 0.0.0.0
Port 80
Virtual
{
AnyHost
Control
{
Alias /
Location /htdocs/web
IndexNames { index.php }
External
{
/usr/sbin/phpcgi { txt }
}
External
{
/usr/sbin/phpcgi { router_info.xml }
/usr/sbin/phpcgi { post_login.xml }
}
}
Control
{
Alias /smart404
Location /htdocs/smart404
}
Control
{
Alias /HNAP1
Location /htdocs/HNAP1
External
{
/usr/sbin/hnap { hnap }
}
IndexNames { index.hnap }
}
}
}
Server
{
ServerName "Linux, HTTP/1.1, DIR-815 Ver 1.04"
ServerId "LAN-1"
Family inet
Interface eth0
Port 1900
Address 239.255.255.250
Datagrams On
Virtual
{
AnyHost
Control
{
Alias /
Location /htdocs/upnp/docs/LAN-1
External
{
/htdocs/upnp/ssdpcgi { * }
}
}
}
}

Server
{
ServerName "Linux, UPnP/1.0, DIR-815 Ver 1.04"
ServerId "LAN-1"
Family inet
Interface eth0
Address 0.0.0.0
Port 49152
Virtual
{
AnyHost
Control
{
Alias /
Location /htdocs/upnp/docs/LAN-1
}
}
}

修改后重新制作镜像,并启动虚拟机。

启动后可以在根目录下看到 fake.conf,先 kill 掉 httpd 服务,之后以我们的配置文件重新启动 httpd。

1
2
kill 2107
httpd -f /fake.conf

启动 httpd 后可看到它被绑定在 0.0.0.0:80

1
2
3
4
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:49152 0.0.0.0:* LISTEN 3858/httpd
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 3858/httpd

此时从宿主机访问 web 服务

至此固件模拟成功。

  • Title: 固件模拟 Case Study (3)
  • Author: Catalpa
  • Created at : 2021-08-15 00:00:00
  • Updated at : 2024-10-17 08:48:26
  • Link: https://wzt.ac.cn/2021/08/15/firmadyne3/
  • License: This work is licensed under CC BY-NC-SA 4.0.