一、模拟运行固件
二、程序调试
三、漏洞分析
四、执行exp,获取shell
一、模拟运行固件
1.环境搭建
使用attifyos 中的环境进行模拟时可能会出现各种问题,后来自己搭建环境,可以正常运行。
- firmadyne 环境搭建:
https://github.com/firmadyne/firmadyne
- qemu 编译安装:
https://download.qemu.org/qemu-2.5.0.tar.bz2
qemu 建议使用 qemu-2.5.0 版本进行编译安装
在安装之前,请修复 linux-user/elfload.c 中elf_check_ehdr 函数的一个 bug:
插入 && ehdr->e_shentsize == sizeof(struct elf_shdr)
这个条件
修改之前:
/* Verify the portions of EHDR outside of E_IDENT for the target.
This has to wait until after bswapping the header. */
static bool elf_check_ehdr(struct elfhdr *ehdr)
{
return (elf_check_arch(ehdr->e_machine)
&& ehdr->e_ehsize == sizeof(struct elfhdr)
&& ehdr->e_phentsize == sizeof(struct elf_phdr)
&& (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
}
修改后:
static bool elf_check_ehdr(struct elfhdr *ehdr)
{
return (elf_check_arch(ehdr->e_machine)
&& ehdr->e_ehsize == sizeof(struct elfhdr)
&& ehdr->e_phentsize == sizeof(struct elf_phdr)
&& ehdr->e_shentsize == sizeof(struct elf_shdr)
&& (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN));
}
编译:
./configure --target-list="mips-linux-user mipsel-linux-user arm-linux-user" --static
sudo make -j8
2.模拟运行固件
-
将 DIR859Ax_FW105b03.bin 固件复制到 firmadyne 目录下
-
在firmadyne 目录下执行以下命令:
sudo su rm -rf images* sh ./reset.sh sudo -u postgres createdb -O firmadyne firmware sudo -u postgres psql -d firmware < ./database/schema ./sources/extractor/extractor.py -b Dlink -sql 127.0.0.1 -np -nk "DIR859Ax_FW105b03.bin" images ./scripts/getArch.sh ./images/1.tar.gz # 获取架构信息并保存到数据库中 ./scripts/makeImage.sh 1 # 制作镜像文件成文件系统 ./scripts/inferNetwork.sh 1 # 自动生成配置仿真环境网卡信息 ./scratch/1/run.sh # 运行仿真环境
ip 信息:
配置网卡信息是,本地会生成一个与 ip 同网段的网卡:
运行固件:./scratch/1/run.sh
可以看出路由器固件 ip为: 192.168.0.1
浏览器中输入 192.168.0.1 访问仿真路由器:
至此,固件模拟运行成功。
二、程序调试
1. 启动 mips 系统
run-mips-sys.sh
脚本信息如下:
oit@ubuntu:/home/qemu-vmsys/mips$ cat run-mips-sys.sh
sudo qemu-system-mips -M malta -kernel vmlinux-3.2.0-4-4kc-malta -hda debian_wheezy_mips_standard.qcow2 -append "root=/dev/sda1 console=ttyS0" -net nic,macaddr=00:0c:29:d4:72:11 -net tap -nographic
其中, msb_mips_gdbserver 是静态的 gdbserver, 之后用于 固件系统中程序的调试。信息如下:
oit@ubuntu:/home/qemu-vmsys/mips$ file ./msb_mips_gdbserver
./msb_mips_gdbserver: ELF 32-bit MSB executable, MIPS, MIPS-I version 1 (SYSV), statically linked, not stripped
执行脚本启动 mips 系统: run-mips-sys.sh
输入 longin:root Password:root
2. 挂载固件跟文件系统
-
解包固件:binwalk -Me DIR859Ax_FW105b03.bin
oit@ubuntu:~/tools/Template/dir_859$ binwalk -Me ./DIR859Ax_FW105b03.bin
oit@ubuntu:~/tools/Template/dir_859$ cd _DIR859Ax_FW105b03.bin.extracted/ -
将跟文件系统 squashfs-root 和 msb_mips_gdbserver 传到 debian-mips系统中:
-
将 msb_mips_gdbserver 复制到 squashfs-root 目录下:
cp ./msb_mips_gdbserver ./squashfs-root -
挂载跟文件系统并启动
root@debian-mips:~#mount -o bind /dev/ ./squashfs-root/dev/
root@debian-mips:~#mount -t proc /proc/ ./squashfs-root/proc/
root@debian-mips:~#chroot ./squashfs-root sh
查看文件系统中运行的进程:chroot ./squashfs-root shroot@debian-mips:~# chroot ./squashfs-root/ sh BusyBox v1.14.1 (2016-06-28 10:53:08 CST) built-in shell (msh) Enter 'help' for a list of built-in commands. # ps PID USER VSZ STAT COMMAND 1 0 2660 S init [2] 2 0 0 SW [kthreadd] 3 0 0 SW [ksoftirqd/0] 6 0 0 SW [watchdog/0] 7 0 0 SW< [cpuset] 8 0 0 SW< [khelper] 9 0 0 SW [kdevtmpfs] 10 0 0 SW< [netns] 11 0 0 SW [sync_supers] 12 0 0 SW [bdi-default] 13 0 0 SW< [kintegrityd] 14 0 0 SW< [kblockd] 15 0 0 SW< [ata_sff] 16 0 0 SW< [rpciod] 18 0 0 SW [khungtaskd] 19 0 0 SW [kswapd0] 20 0 0 SWN [ksmd] 21 0 0 SW [fsnotify_mark] 22 0 0 SW< [nfsiod] 23 0 0 SW< [crypto] 26 0 0 SW [scsi_eh_0] 27 0 0 SW [scsi_eh_1] 28 0 0 SW [kworker/u:1] 31 0 0 SW [kworker/u:3] 32 0 0 SW [jbd2/sda1-8] 33 0 0 SW< [ext4-dio-unwrit] 157 0 3408 S udevd --daemon 221 0 0 SW< [kpsmoused] 222 0 0 SW [khubd] 636 0 3344 S udevd --daemon 637 0 3344 S udevd --daemon 1631 0 5160 S dhclient -v -pf /run/dhclient.eth0.pid -lf /var/lib/d 1633 0 3012 S /sbin/rpcbind -w 1677 102 3400 S /sbin/rpc.statd 1689 0 3412 S /usr/sbin/rpc.idmapd 1960 0 29752 S /usr/sbin/rsyslogd -c5 2009 1 2800 S /usr/sbin/atd 2021 0 4536 S /usr/sbin/cron 2167 0 7664 S /usr/sbin/sshd 2345 101 8924 S /usr/sbin/exim4 -bd -q30m 2372 0 2812 S /sbin/getty 38400 tty1 2373 0 2812 S /sbin/getty 38400 tty2 2374 0 2812 S /sbin/getty 38400 tty3 2375 0 2812 S /sbin/getty 38400 tty4 2376 0 2812 S /sbin/getty 38400 tty5 2377 0 2812 S /sbin/getty 38400 tty6 2378 0 4520 S /bin/login -- 2379 0 6120 S -bash 2389 0 11144 S sshd: root@pts/0 2391 0 6108 S -bash 2399 0 2588 S /usr/lib/openssh/sftp-server 2583 0 0 SW [kworker/0:1] 2896 0 11012 S sshd: root@notty 2898 0 2588 S /usr/lib/openssh/sftp-server 2937 0 0 SW [kworker/0:0] 3036 0 0 SW [flush-8:0] 3052 0 0 SW [kworker/0:2] 3057 0 856 S sh 3058 0 748 R ps #
查看网络:
由此可知,跟文件系统在mips系统中成功挂载并运行。
3. 程序调试测试:msb_mips_gdbserver、IDA
这里测试 /htdocs/cgibin 文件的远程调试( /htdocs/cgibin 后面会用到)
- 执行
./msb_mips_gdbserver 192.168.126.150:1234 /htdocs/cgibin
远程ip: 192.168.126.150
监听端口:1234
/htdocs/cgibin:调试程序
- 将 /htdocs/cgibin 复制到 pc下,用ida打开
在main 函数处下断点,按 F9运行->选择Remote GDB debuger
点击OK,输入Hostname 和 Port:(启动gdbserver 时设置的 )
Hostname: 192.168.126.150
Port:1234
点击OK,出现调试界面
F9 运行,执行到刚才main 函数断点处
由此可以看到,一切正常,说明环境配置及远程调试没有问题。
三、漏洞分析
对于漏洞分析,参考原文:
https://blog.csdn.net/NOSEC2019/article/details/103823845
根据纰漏,可知远程代码执行漏洞在UPnP请求的代码中。
1. UPnP协议栈
UPnP是实现智能设备端到端网络连接的结构。它也是一种架构在TCP/IP和HTTP技术之上的,分布式、开放的网络结构,以使得在联网的设备间传递控制和数据。UPnP 技术实现了 控制点、 设备和 服务之间通讯的支持,并且设备和相关服务的也使用XML定义并且公布出来。使用UPnP,设备可以动态加入网络,自动获得一个IP地址,向其他设备公布它的能力或者获知其他设备的存在和服务,所有这些过程都是自动完成的,此后设备能够彼此直接通讯。
UPnP不需要设备驱动程序,因此使用UPnP建立的网络是介质无关的。同时UPnP使用标准的TCP/IP和网络协议,使它能够无缝的融入现有网络。构造UPnP应用程序时可以使用任何语言,并在任何操作系统平台上编译运行。对于设备的描述,使用HTML表单表述设备控制界面。它既允许设备供应商提供基于浏览器的用户界面和编程控制接口,也允许开发人员定制自己的设备界面。
2. 漏洞所在位置
在满足一定前置条件情况下,二进制可执行文件/htdocs/cgibin中的genacgi_main()函数包含了可远程执行代码的漏洞。
使用 ghidra 查看 genacgi_main() 函数的反编译代码:
undefined4 genacgi_main(void)
{
char *pcVar1;
char *env_http_callback;
char *__s1;
char *env_http_nt;
char *env_REMOTE_ADDR;
size_t sVar2;
__pid_t pid;
__pid_t _Var3;
char *pcVar4;
undefined4 uVar5;
int iVar6;
int iVar7;
int iVar8;
char buf8 [8];
char acStack528 [500];
undefined *local_18;
local_18 = &_gp;
pcVar4 = getenv("REQUEST_METHOD");
if (pcVar4 == (char *)0x0) {
return 0xffffffff;
}
/* getenv */
uVar5 = (**(code **)(local_18 + -0x7c90))("REQUEST_URI");
/* strchr */
iVar6 = (**(code **)(local_18 + -0x7f78))(uVar5,0x3f);
if (iVar6 == 0) {
return 0xffffffff;
}
/* strncmp */
iVar7 = (**(code **)(local_18 + -0x7d44))(iVar6,"?service=",9);
if (iVar7 != 0) {
return 0xffffffff;
}
/* strcasecmp */
iVar7 = (**(code **)(local_18 + -0x7d30))(pcVar4,"SUBSCRIBE");
uri_service <