1. 环境配置
cve链接:https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-27021
为什么是br0这个我还不太清楚,因为在ida反汇编过程中,也只搜索到了br0一次,但是看了https://xz.aliyun.com/t/13506?time__1311=mqmxnQiQi%3DDQ0%3DGODlcIEHqGTkmcP%3DK4D&alichlgref=https%3A%2F%2Fxz.aliyun.com%2Ft%2F11817%3Ftime__1311%3Dmqmx0DBD9AYrD%252FQiiQGkbIhbLYGODfrD%26alichlgref%3Dhttps%253A%252F%252Fcn.bing.com%252F 这个链接中教程是需要添加br0,如果不添加连接网络过程会有问题。
这其中还遇到一个检测函数过程,最后是利用ida的patch bytes讲mov r3,r0改为了mov r3,1跳过检查修改二进制文件越过检查的。
环境配置过程中,chroot命令是切换根目录命令,因为该固件解包得到的内容如下,是一个类linux环境,所以使用chroot切换根目录。
$ ls
bin dev etc_ro init mnt qemu-arm-static sbin tmp var webroot_ro
cfg etc home lib proc root sys usr webroot
$ sudo chroot ./qemu-arm-static ./bin/httpd
这里的qemu-arm-static是启动qemu去模拟arm的软件,用file查看httpd能看到这是arm32架构的软件,然后后面接启动的软件
这里发现启动后会卡着不动,使用ida反汇编查看下看看问题在哪里,可以通过去搜索WeLoveLinux这句话去找具体的函数代码位置。
搜索到后查找引用找到函数位置
这个时候我们可以发现就在puts函数下面,有一个check_network命令,现在卡主不动,说明这个函数的返回值始终满足这个while循环,可以去看一下函数的返回值。
这是一个import函数,所以需要找函数的实现位置。这里我的方法比较笨拙,就是通过查看二进制链接相关的so库,通过搜索每个so库查找函数名是否匹配存在。
这里是我的写的一个代码,可以用这个代码去快速匹配。
https://github.com/JohenanLi/ExtractImportFunctionAndMatchLibrary
匹配结果:
使用grep搜索,得到匹配的库
$ grep -R "check_network" libcommon.so
grep: libcommon.so: binary file matches
使用ida或者ghidra打开libcommon.so,查看check_network的实现。
bool check_network(undefined4 param_1)
{
undefined4 uVar1;
int iVar2;
uVar1 = getLanIfName();
iVar2 = getIfIp(uVar1,param_1);
return -1 < iVar2;
}
undefined4 getLanIfName(void)
{
undefined4 uVar1;
uVar1 = get_eth_name(0);
return uVar1;
}
到这里可以看到有一个get_eth_name函数,在libcommon.so也是没有实现的。按着刚才的方法去找找
这三个so库中都没有,然后在httpd的strings中能够搜索到get_eth_name,那从httpd的so库中去搜索。
匹配到了 ,继续反汇编打开看实现
从刚刚上文来看,param_1的值为0,也就是最后需要一个"br0"返回,uVar1=“br0”
再进入getIfIp函数
undefined4 getIfIp(char *param_1,char *param_2)
{
int iVar1;
char *__src;
undefined4 uVar2;
char acStack_2c [20];
in_addr local_18;
int local_c;
local_c = 0;
local_c = socket(2,2,0);
if (local_c < 0) {
uVar2 = 0xffffffff;
}
else {
strncpy(acStack_2c,param_1,0x10);
iVar1 = ioctl(local_c,0x8915,acStack_2c);
if (iVar1 < 0) {
close(local_c);
uVar2 = 0xffffffff;
}
else {
__src = inet_ntoa(local_18);
strcpy(param_2,__src);
close(local_c);
uVar2 = 0;
}
}
return uVar2;
}
getIfIp函数分析,这里让chatgpt分析这个函数。
总结下分析:
1.调用ioctl函数和参数0x8915(SIOCGIFADDR)获取网络接口的ip地址,返回值为iVar1
2.如果调用失败iVar1<0就使得uVar2=0xfffffff实际上就是-1
3.如果调用成功就会返回ip地址,并返回0。
再看到check_network函数的返回值后半部分,如果iVar2=-1就会返回0,如果iVar2=1时就会返回1,返回1才能不sleep
所以需要建立一个网卡,使用以下命令建立一个br0的网桥
sudo brctl addbr br0
sudo brctl addif br0 ens32
sudo ifconfig br0 up
sudo dhclient br0
brctl - ethernet bridge administration ,就是管理网桥的工具,addbr添加br0网桥,addif br0 ens32是将br0和ens32串起来,现在br0是网桥,ens32是本机的网卡,通过ifconfig就可以查看自己的网卡
$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.31.20.128 netmask 255.255.240.0 broadcast 172.31.31.255
inet6 fe80::215:5dff:febc:bedb prefixlen 64 scopeid 0x20<link>
ether 00:15:5d:bc:be:db txqueuelen 1000 (Ethernet)
RX packets 165739 bytes 220586833 (220.5 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 115683 bytes 8934103 (8.9 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0