赞
踩
今日我们开一个新坑,——路由器固件的分析与漏洞挖掘。
尽管网上文章分析不少,但我还是感觉缺少点什么........虽然本人实力有限,比不上那些逆向大佬。我还是喜欢把自己的思路分享给大家。
固件的分析不同与常规的web网站。我们没有这款固件开发的原始的.c代码,只能利用工具提取固件的文件系统,使用逆向软件分析固件的可执行程序。如ida pro 在逆向界面中我们只能看到的是一条条指令操作着寄存器,栈空间地址。使用软件的反汇编功能F5查看程序的伪代码,这种代码在功能上与源码无差,但实际上代码阅读性上可谓是差了大节。
二进制安全底层的知识,我从来不觉的有很复杂。只是现在的书籍资料经常把一些知识讲的非常晦涩且庞大。这点尤其是在计算机底层原理这块,满篇大论让人云里雾里.....,而且它们总是在说是什么,没有从初设计者的想法出发思考为什么要这么做,做的过程中遇到了什么问题,是如何解决的.最终才形成这样的一个庞大的系统.....
在开始本章前我希望您具备或者说你有这样的理念
1.什么是固件?可以用来干什么?开发的大致流程?
2.指令是什么?指令的分类 ? 为什么这样分类?-----引出架构
3.程序执行内存是怎么分布的?或者说可以怎么分布?
4.栈的原理及调用(很重要)函数调用栈的变化!
5.socket编程c语言版,如何使用c开发自己的web服务器?
推荐一个项目---一键模拟仿真固件
项目的安装,看项目介绍,有很多坑要安装很多的依赖包。本人也是纯小白,待熟练后考虑出一期专门的踩坑教程
必使用功——binwalk 这个工具在上面的项目依赖中已经有了。如果要单独安装ubuntu官方源apt get就可以直接装。
本次测试的固件下载地址
我们下载固件版本B03
binwalk -Me xxxxx.bin 可提取固件的文件系统
在提取的过程中我们可以从固件中得到一些信息,压缩信息 地址信息 文件系统 大小端 等
在提取后的squashfs-root文件夹中,我们会得到一个liunx的系统文件目录,也侧面说说明最初的开发就是在这样的系统上运行的
固件仿真,在firmware-analysis-plus中执行命令
./fap.py -q /qemu-builds/2.5.0/ DIR823GA1_FW102B03.bin
访问192.168.0.1,仿真模拟成功。
固件分析解决方案
IDA pro 网上搜索下载
binwalk -Me xxxxx.bin 可提取固件的文件系统
SOAPAction
SOAPAction
是一个 HTTP 头部(Header),用于指定在 SOAP(Simple Object Access Protocol)请求中要调用的 Web 服务操作。SOAP 是一种基于 XML 的协议,它允许网络上的计算机通过 HTTP 通信并交换结构化信息。尽管 SOAP 可以使用不同的传输协议,但最常见的是通过 HTTP 或 HTTPS 进行通信。
SOAPAction 的作用
当客户端向服务器发送一个 SOAP 请求时,SOAPAction
头部指明了要执行的特定操作。这有助于 Web 服务框架理解请求的目的,并将请求路由到正确的服务方法或操作处理程序。
在某些情况下,SOAPAction
头部也可以用来实现一定级别的网络安全策略,例如,通过检查 SOAPAction
来限制对敏感操作的访问。
示例
假设你有一个 Web 服务,它提供了一个名为 GetUserInfo
的操作,客户端在发送请求时,HTTP 头部可能包括类似以下内容的 SOAPAction
:
SOAPAction: "http://example.com/webservices/GetUserInfo"
这告诉服务器,该请求意图调用 GetUserInfo
操作。
在 HTTP 请求中的位置
SOAPAction
头部直接包含在 HTTP 请求中,紧跟在其他标准 HTTP 头部之后,例如 Content-Type
。一个典型的 SOAP 请求可能看起来像这样:
POST /service.svc HTTP/1.1 Host: example.com Content-Type: text/xml; charset=utf-8 Content-Length: length SOAPAction: "http://example.com/webservices/GetUserInfo" <?xml version="1.0"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetUserInfo xmlns="http://example.com/webservices"> <!-- 请求数据 --> </GetUserInfo> </soap:Body> </soap:Envelope>
注意事项
在 SOAP 1.1 中,SOAPAction
头部是必需的,但在 SOAP 1.2 规范中,它被定义为可选,并且其用途和行为有所不同。在 SOAP 1.2 中,操作信息通常通过其他机制,如 WS-Addressing 标准中的 Action 头部来指定。
虽然 SOAPAction
头部可以增强 Web 服务的自描述性,但它也可能暴露服务的内部结构,因此在设计 Web 服务时应考虑到安全性问题。
确保客户端和服务器对 SOAPAction
头部的使用达成一致,特别是在使用第三方服务时,需要注意遵循服务提供者的指导和规范。
GoAhead 是一款轻量级、高性能、可嵌入的 Web 服务器,它被设计用于小型到中型的设备和应用,例如家庭网关、路由器、打印机、家庭自动化设备和其他嵌入式设备。GoAhead 被广泛用于工业和消费级产品中,因为它非常适合资源受限的环境。
主要特点
轻量级:GoAhead 设计紧凑,内存占用小,适合嵌入式系统。
跨平台:支持多种操作系统,包括 Windows、Linux、macOS 以及各种嵌入式操作系统。
易于扩展:提供了简单的 API,使得开发者可以容易地添加自定义的动态内容处理器。
安全:支持基本的安全特性,如 SSL/TLS 加密、基本认证和摘要认证等。
支持标准:支持 HTTP/1.1、CGI/1.1、WebSocket 等网络通信标准。
使用场景
GoAhead 常用于那些需要内置 Web 服务器功能的设备或应用中,例如:
嵌入式设备的配置界面
控制面板和监控系统
小型 Web 应用
IoT 设备和网关
官方手册
在 GoAhead Web 服务器中,您可以使用 websUrlHandlerDefine
函数来自定义路由。以下是一个示例
- #include <stdio.h>
- #include "goahead.h"
-
- // 自定义路由处理函数
- static bool myCustomHandler(Webs *wp)
- {
- // 处理请求逻辑
- printf("Received request for path: %s\n", wp->path);
-
- // 发送响应
- websHeader(wp);
- websWrite(wp, "Hello, World!");
- websFooter(wp);
-
- return true;
- }
-
- int main(int argc, char **argv)
- {
- // 初始化 GoAhead Web 服务器
- if (websOpen(argc, argv) < 0) {
- fprintf(stderr, "Failed to initialize GoAhead Web Server\n");
- return -1;
- }
-
- // 定义自定义路由
- websUrlHandlerDefine("/myroute", NULL, WEBS_DEFAULT, myCustomHandler, 0);
-
- // 启动 Web 服务器
- websListen(NULL);
-
- // 清理资源
- websClose();
-
- return 0;
- }
位于liunx目录etc/init.d下为启动脚本,每次系统开始会执行(这也说明路由器的设置出厂模式 其实就是重启了设备而已)
本次固件分析的启动脚本如下
- #!/bin/sh
-
- ifconfig lo 127.0.0.1
-
- CINIT=1
-
- hostname rlx-linux
-
- mount -t proc proc /proc
- mount -t ramfs ramfs /var
- if [ -d "/hw_setting" ];then
- mount -t yaffs2 -o tags-ecc-off -o inband-tags /dev/mtdblock1 /hw_setting
- fi
-
- mkdir /var/tmp
- mkdir /var/web
- mkdir /var/log
- mkdir /var/run
- mkdir /var/lock
- mkdir /var/system
- mkdir /var/dnrd
- mkdir /var/avahi
- mkdir /var/dbus-1
- mkdir /var/run/dbus
- mkdir /var/lib
- mkdir /var/lib/misc
- mkdir /var/home
- mkdir /var/root
- mkdir /var/tmp/net
- ###for tr069
- mkdir /var/cwmp_default
- mkdir /var/cwmp_config
-
- if [ ! -f /var/cwmp_default/DefaultCwmpNotify.txt ]; then
- cp -p /etc/DefaultCwmpNotify.txt /var/cwmp_default/DefaultCwmpNotify.txt 2>/dev/null
- fi
-
- ##For miniigd
- mkdir /var/linuxigd
- cp /etc/tmp/pics* /var/linuxigd 2>/dev/null
-
- ##For pptp
- mkdir /var/ppp
- mkdir /var/ppp/peers
-
- #smbd
- mkdir /var/config
- mkdir /var/private
- mkdir /var/tmp/usb
-
- #snmpd
- mkdir /var/net-snmp
-
- cp /bin/pppoe.sh /var/ppp/true
- echo "#!/bin/sh" > /var/ppp/true
- #echo "PASS" >> /var/ppp/true
-
- #for console login
- cp /etc/shadow.sample /var/shadow
-
- #for weave
- cp /etc/avahi-daemon.conf /var/avahi
-
- #extact web pages
- cd /web
- #flash extr /web
- cd /
-
- mkdir -p /var/udhcpc
- mkdir -p /var/udhcpd
- cp /bin/init.sh /var/udhcpc/eth0.deconfig
- echo " " > /var/udhcpc/eth0.deconfig
- cp /bin/init.sh /var/udhcpc/eth1.deconfig
- echo " " > /var/udhcpc/eth1.deconfig
- cp /bin/init.sh /var/udhcpc/br0.deconfig
- echo " " > /var/udhcpc/br0.deconfig
- cp /bin/init.sh /var/udhcpc/wlan0.deconfig
- echo " " > /var/udhcpc/wlan0.deconfig
-
- if [ "$CINIT" = 1 ]; then
- startup.sh
- fi
-
- # for wapi certs related
- mkdir /var/myca
- # wapi cert(must done before init.sh)
- cp -rf /usr/local/ssl/* /var/myca/ 2>/dev/null
- # loadWapiFiles >/dev/null 2>&1
-
- # for wireless client mode 802.1x
- mkdir /var/1x
- cp -rf /usr/1x/* /var/1x/ 2>/dev/null
- mkdir /var/openvpn
- cp -rf /usr/share/openvpn/* /var/openvpn 2>/dev/null
-
- # Start system script
- init.sh gw all
-
- # modify dst-cache setting
- echo "24576" > /proc/sys/net/ipv4/route/max_size
- echo "180" > /proc/sys/net/ipv4/route/gc_thresh
- echo 20 > /proc/sys/net/ipv4/route/gc_elasticity
- # echo 35 > /proc/sys/net/ipv4/route/gc_interval
- # echo 60 > /proc/sys/net/ipv4/route/secret_interval
- # echo 10 > /proc/sys/net/ipv4/route/gc_timeout
-
- # echo "4096" > /proc/sys/net/nf_conntrack_max
- echo "12288" > /proc/sys/net/netfilter/nf_conntrack_max
- echo "600" > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_established
- echo "20" > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_time_wait
- echo "20" > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_close
- echo "90" > /proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout
- echo "120" > /proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout_stream
- echo "90" > /proc/sys/net/ipv4/netfilter/ip_conntrack_generic_timeout
- # echo "1048576" > /proc/sys/net/ipv4/rt_cache_rebuild_count
- echo "32" > /proc/sys/net/netfilter/nf_conntrack_expect_max
-
- # modify IRQ Affinity setting
- echo "3" > /proc/irq/33/smp_affinity
-
- #echo 1 > /proc/sys/net/ipv4/ip_forward #don't enable ip_forward before set MASQUERADE
- #echo 2048 > /proc/sys/net/core/hot_list_length
-
- # start web server
- ls /bin/watchdog > /dev/null && watchdog 1000&
- #boa
-
- goahead &
-
- #Turn off the power led of orange
- echo "29" > /sys/class/gpio/export
- echo "out" > /sys/class/gpio/gpio29/direction
- echo "1" > /sys/class/gpio/gpio29/value
- #Turn on the power led of green
- echo "30" > /sys/class/gpio/export
- echo "out" > /sys/class/gpio/gpio30/direction
- echo "0" > /sys/class/gpio/gpio30/value
-
- cp /etc/passwd_orig /var/passwd
- cp /etc/group_orig /var/group
- MODE=`flash get HW_FACTORY_MODE`
- if [ "$MODE" = "HW_FACTORY_MODE=1" ];then
- telnetd&
- fi
- speedcheck&
除了一些基本的操作,如创建一些文件夹,写入一些配置项,配置下看门狗
还有重要的是服务器起了goahead服务
用IDA pro打开goahead服务。
目的—— 信息搜集 收集当前服务的有关接口,查看存在的接口的执行逻辑,是否可利用的参数可利用的方法调用、除此之外搜集接口信息还可以分析前端发出的包。
CTRL + E 选择主函数main进入, F5进入伪代码
if条件调用了很多函数,猜想这些函数是什么...... 。那一定有绑定服务的函数,建立socket客户端的函数,线程函数......如果这些代码执行错误那这个服务一定不可执行。之后while循环,这一定是阻塞等待客户端的连接,去处理用户的请求。
厂商既然用了goahead这个项目,就大概率配置了自己的接口,我们可以在while循环前,寻找相关信息
进入sub_423F90函数
注意下面类似路径接口的函数
和示例中的 定义自定义路由多像啊! websUrlHandlerDefine("/myroute", NULL, WEBS_DEFAULT, myCustomHandler, 0);
根据原理第四个参数就是接口的处理函数,我们追进去sub_42383c
一眼望去 有一个很危险的行为 echo '%s' > 之后执行了system,首先这条语句在liunx一定是可以命令注入的,那么后面就是看参数a7是否可控了!
因为是伪代码,对比正向代码示例
// 自定义路由处理函数 static bool myCustomHandler(Webs *wp) {
a1 到 a7 一定是结构体webs的成员,那么a7就大概率是我们可控的参数。
不过执行system前,我们得先进入if条件语句中,判断for 与 if 的逻辑
循环遍历dword_58E084空间,每次循环将地址空间+8个字节,所指向的字符串与a1+1316的空间的字符串做对比,有则进入if执行代码
先看看dword_58E084空间有什么,+8就是一个字符串,+4就是一个函数(后面执行的函数也可判断出)(猜想 这函数一定是对应字符串的函数 的确是)
那么a1+1316指向的空间是什么 ?
有些漏洞的发现无需逆向,凭经验与模糊测试就可以挖掘成功。
就像本次的a1+1316的空间 我们无需纠结那么多的细节,我们可以确定的是在路由器登录的时候一定执行了login方法, 那么a1+1316这个空间就一定符合程序预期的。我们前端抓包一探究竟。
登录页面
我们请求的url是POST /HNAP1 但最终处理的不一定不是HNAP1。header请求头中有SOAPAction 这个字段,网上收集资料学习下这种技术,最终明白了它强请求数据为什么是xml这种,为什么请求/HNAP 后端却是调用login函数。那么,a1+1316就大概率是SOAPAction 这个值了。
a7也被传输了相关方法如login,我们就可以大胆的猜测 这个a7就是xml数据 是我们可控的。
此外我们还可以执行命令查看/var/hnaplog 到底被写入了什么作为日志信息,是请求的url还是请求的数据 是请求端的ip 还是请求的ugent
cat /var/hnaplog 将这条命令 在仿真的界面尝试执行(会有很多日志信息输出 手速快点 目前我没有找到一个干净的shell方法 如果有望告知)
en.....的确是请求的post数据。
接下来我们就可以进行rce执行了 ,(实际测试本次固件无法发起连接请求,所以用写入文件的方法验证此漏洞)
抓包 输入我们的payload (web_mtn目录是web的根目录 在提取文件系统时可以大致判断出来)
`echo 123test > /web_mtn/1.txt`
- POST /HNAP1/ HTTP/1.1
- Host: 192.168.0.1
- Content-Length: 29
- Accept: */*
- X-Requested-With: XMLHttpRequest
- SOAPAction: "http://purenetworks.com/HNAP1/Login"
- User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36
- Content-Type: text/xml; charset=UTF-8
- Origin: http://192.168.0.1
- Referer: http://192.168.0.1/Login.html
- Accept-Encoding: gzip, deflate
- Accept-Language: en-US,en;q=0.9
- Connection: close
-
- '`echo 123 > /web_mtn/1.txt`'
之后访问路径 /1.txt 漏洞复现成功
除此之外本次固件还有一系列的接口未授权,前端登录等同于虚设。除此之外貌似还有一些缓冲区溢出。 可以说是后端写的时非常随意了各种函数滥用,不考虑认证等问题。
其他说明 :本人纯小白,如有分析不对的地方或者有更好的分析方法 望大佬指出。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。