首页
社区
课程
招聘
[原创]boofuzz在二进制IOT漏洞挖掘中的简单运用
发表于: 2024-6-23 23:10 12553

[原创]boofuzz在二进制IOT漏洞挖掘中的简单运用

2024-6-23 23:10
12553

有个未曾谋面的看雪的坛友问我一门关于IOT挖洞的课怎么样,因为课表里写的太笼统,所以我也就没给明确答复,不过我说我愿意免费教教我会的东西,另外之前关于我DIR-645漏洞文章结尾也说了要讲讲怎么fuzz出那个漏洞,于是便有了这篇文章

Ubuntu 20.04

Python、pip、qemu之类的直接用apt-get下载安装就好

IDA pro之前提供过下载链接

binwalk里有需要用到sasquatch程序,需要手动下载一下,命令如下

 使用binwalk解包以后可以在bin文件夹下看到httpd程序,此时如果直接运行的话会卡在欢迎banner信息处

1.png

需要patch一些代码,修改判断逻辑

下图中红框内就是已经patch好的代码,点击Edit > Patch program > Apply pathes to input file > OK 即可保存

patch.png

修改完成后再次运行依然会报错

2.png

这个错误主要是IP地址不正确,需要查看一下httpd服务具体是怎么获取IP的,需要从check_network函数开始查,这个函数是引用了第三方的lib库(至少我在Linux源码里没找到这个函数)

结果会找到libcommon.so文件,用IDA打开后可以看到依然是调用了别的so库代码

需要继续搜get_eth_name函数位置

有四个匹配,事实上是libChipAPI.so文件

从代码里可以看到程序在尝试读网卡信息,因为没有对应的网卡,所以程序IP地址会出错,所以这里需要手动创建一个br0网卡,并给一个IP地址(在创建之前建议先保存一个快照以防万一)

修改好后httpd程序就能正确运行了

此处需要抓包查看协议结构,但是因为只是普通的HTTP协议,我就直接给出boofuzz代码了

在开始之前记得用pip安装一下boofuzz,因为已经知道漏洞点了,所以很快就能跑出结果了

可以看到在password给出了一个非常长的值后程序崩溃了,验证其实也很简单,直接用Python脚本访问之前给br0的地址,端口是80,cookie中给一个超长的值就能复现崩溃了

最后在bLanguage这个字段也有个溢出,大家可以尝试修改上面的fuzz脚本复现一下

这是一个2017年爆出的贼老的栈溢出漏洞,不过用来学习boofuzz的使用还是不错的

首先使用binwalk解包固件后会有不少文件,文件系统在这个目录下

http服务用的是boa

这里有两个点需要修复

首先将宿主机中/etc/hosts文件夹中的内容全部复制到固件文件系统的/etc/hosts文件中去

然后将 _31.extracted/defconf/_CC8160.tar.bz2.extracted/_0.extracted/etc/ 目录直接拷贝到 squashfs-root/mnt/flash/ 目录中去,这一步主要是解决boa的config文件缺失问题

接下来直接用qemu命令运行httpd服务就行了

fuzz这个洞的脚本如下

几乎是一瞬间,boa服务就崩溃了,从输出信息来看,是因为 Content-Length 过长导致的,这也确实是这个洞的成因

boofuzz是个挺不错的对协议的fuzz工具,比AFL好在不需要参与编译过程,也就是说不需要收集代码覆盖率信息;缺点也很明显,需要对协议格式深入分析,且因为没有代码覆盖率信息,所以对未知代码的触发基本靠运气

这里使用这两个IOT固件且只fuzz了HTTP服务是因为这两个固件的环境问题相对好解决且HTTP服务fuzz起来相对简单,所以解决环境问题最好的方式还是直接买硬件

https://xz.aliyun.com/t/5054?time__1311=n4%2BxnD07iti%3Dj2DBqooGkYLwq6DBDYTAD

https://www.anquanke.com/post/id/185336

https://blog.csdn.net/song_lee/article/details/113800058

sudo git clone https://github.com/devttys0/sasquatch
cd sasquatch
sudo apt-get install build-essential liblzma-dev liblzo2-dev zlib1g-dev
./build.sh
sudo git clone https://github.com/devttys0/sasquatch
cd sasquatch
sudo apt-get install build-essential liblzma-dev liblzo2-dev zlib1g-dev
./build.sh
find ./lib/ -name "*" | xargs grep 'check_network'
find ./lib/ -name "*" | xargs grep 'check_network'
find ./lib/ -name "*" | xargs grep 'get_eth_name'
find ./lib/ -name "*" | xargs grep 'get_eth_name'
sudo tunctl -t br0 -u #用户名#        
sudo ifconfig br0 192.168.10.1/24
sudo tunctl -t br0 -u #用户名#        
sudo ifconfig br0 192.168.10.1/24
from boofuzz import *  
 
IP = "10.10.10.1"                #IP地址填自己的IP就好
PORT = 80
 
def check_response(target, fuzz_data_logger, session, *args, **kwargs):
    fuzz_data_logger.log_info("Checking test case response...")
    try:
        response = target.recv(512)
    except:
        fuzz_data_logger.log_fail("Unable to connect to target. Closing...")
        target.close()
        return
 
    #if empty response
    if not response:
        fuzz_data_logger.log_fail("Empty response, target may be hung. Closing...")
        target.close()
        return
 
    #remove everything after null terminator, and convert to string
    #response = response[:response.index(0)].decode('utf-8')
    fuzz_data_logger.log_info("response check...\n" + response.decode())
    target.close()
    return
     
def main():
    '''
    options = {
        "start_commands": [
            "sudo chroot /home/lys/Documents/IoT/firmware/_AC15_V15.03.1.16.bin.extracted/squashfs-root ./httpd"
        ],
        "stop_commands": ["echo stopping"],
        "proc_name": ["/usr/bin/qemu-arm-static ./httpd"]
    }
    procmon = ProcessMonitor("127.0.0.1", 26002)
    procmon.set_options(**options)
    '''
 
    session = Session(
        target=Target(
            connection=SocketConnection(IP, PORT, proto="tcp"),
            # monitors=[procmon]
        ),
        post_test_case_callbacks=[check_response],
    )
 
    s_initialize(name="Request")
    with s_block("Request-Line"):
        # Line 1
        s_group("Method", ["GET"])
        s_delim(" ", fuzzable=False, name="space-1-1")
        s_string("/goform/123", fuzzable=False)    # fuzzable 1
        s_delim(" ", fuzzable=False, name="space-1-2")
        s_static("HTTP/1.1", name="HTTP_VERSION")
        s_static("\r\n", name="Request-Line-CRLF-1")
        # Line 2
        s_static("Host")
        s_delim(": ", fuzzable=False, name="space-2-1")
        s_string("10.10.10.1", fuzzable=False, name="IP address")
        s_static("\r\n", name="Request-Line-CRLF-2")
        # Line 3
        s_static("Connection")
        s_delim(": ", fuzzable=False, name="space-3-1")
        s_string("keep-alive", fuzzable=False, name="Connection state")
        s_static("\r\n", name="Request-Line-CRLF-3")
        # Line 4
        s_static("Cookie")
        s_delim(": ", fuzzable=False, name="space-4-1")
        s_string("bLanguage", fuzzable=False, name="key-bLanguage")
        s_delim("=", fuzzable=False)
        s_string("en", fuzzable=False, name="value-bLanguage")
        s_delim("; ", fuzzable=False)
        s_string("password", fuzzable=False, name="key-password")
        s_delim("=", fuzzable=False)
        s_string("ce24124987jfjekfjlasfdjmeiruw398r", fuzzable=True)    # fuzzable 2
        s_static("\r\n", name="Request-Line-CRLF-4")
        # over
        s_static("\r\n")
        s_static("\r\n")
 
    session.connect(s_get("Request"))
    session.fuzz()
 
if __name__ == "__main__":
    main()
from boofuzz import *  
 
IP = "10.10.10.1"                #IP地址填自己的IP就好
PORT = 80
 
def check_response(target, fuzz_data_logger, session, *args, **kwargs):
    fuzz_data_logger.log_info("Checking test case response...")
    try:
        response = target.recv(512)
    except:
        fuzz_data_logger.log_fail("Unable to connect to target. Closing...")
        target.close()
        return
 
    #if empty response
    if not response:
        fuzz_data_logger.log_fail("Empty response, target may be hung. Closing...")
        target.close()
        return
 
    #remove everything after null terminator, and convert to string
    #response = response[:response.index(0)].decode('utf-8')
    fuzz_data_logger.log_info("response check...\n" + response.decode())
    target.close()
    return
     
def main():
    '''
    options = {
        "start_commands": [
            "sudo chroot /home/lys/Documents/IoT/firmware/_AC15_V15.03.1.16.bin.extracted/squashfs-root ./httpd"
        ],
        "stop_commands": ["echo stopping"],
        "proc_name": ["/usr/bin/qemu-arm-static ./httpd"]
    }
    procmon = ProcessMonitor("127.0.0.1", 26002)
    procmon.set_options(**options)
    '''
 
    session = Session(
        target=Target(
            connection=SocketConnection(IP, PORT, proto="tcp"),
            # monitors=[procmon]
        ),
        post_test_case_callbacks=[check_response],
    )
 
    s_initialize(name="Request")
    with s_block("Request-Line"):
        # Line 1
        s_group("Method", ["GET"])
        s_delim(" ", fuzzable=False, name="space-1-1")
        s_string("/goform/123", fuzzable=False)    # fuzzable 1
        s_delim(" ", fuzzable=False, name="space-1-2")
        s_static("HTTP/1.1", name="HTTP_VERSION")
        s_static("\r\n", name="Request-Line-CRLF-1")

[招生]系统0day安全班,企业级设备固件漏洞挖掘,Linux平台漏洞挖掘!

收藏
免费 4
支持
分享
打赏 + 50.00雪花
打赏次数 1 雪花 + 50.00
 
赞赏  瑞皇   +50.00 2024/06/23 感谢分享~
最新回复 (7)
雪    币: 14685
活跃值: (17789)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
2

等我有空了再上传固件吧


--------------------------我有空了--------------------------------------------------

tengda固件下载链接:https://gitcode.net/pureGavin/photo/-/blob/master/fuzz/CVE-2018-5767/US_AC15V1.0BR_V15.03.1.16_multi_TD01.bin

vivotek固件下载链接:https://gitcode.net/pureGavin/photo/-/blob/master/fuzz/vivotek/CC8160-VVTK-0100d.flash.pkg

没做dir-645是因为那个固件不好模拟,环境问题比较复杂
 

最后于 2024-6-24 09:17 被pureGavin编辑 ,原因: 添加内容
2024-6-23 23:14
0
雪    币: 244
活跃值: (935)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
文章对新手很友好,感谢楼主分享
2024-7-4 23:57
0
雪    币: 426
活跃值: (1919)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
4
boofuzz问题只在于每对应一个页面或功能,都要单独去高重复写。我个人之前有研究用chatgpt来写,但总感觉效果不是很明显
2024-7-5 14:22
0
雪    币: 14685
活跃值: (17789)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
5
p1yang boofuzz问题只在于每对应一个页面或功能,都要单独去高重复写。我个人之前有研究用chatgpt来写,但总感觉效果不是很明显
各种工具配合吧,毕竟纯黑盒的情况下,没有覆盖率信息,qemu模拟不起来,甚至固件代码都拿不到,那就只能测到哪儿算哪儿了
2024-7-5 22:48
0
雪    币: 358
活跃值: (622)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
感谢分享,正好学到qemu仿真时使用ProcessMonitor的方法
2024-7-24 17:49
0
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
师傅我有一个疑问啊,就是qemu仿真有必要用system吗?因为我看到有一些是直接起user的,就是什么情况下只有system可以而user不行的吗?
2024-11-27 16:50
0
雪    币: 14685
活跃值: (17789)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
8
wx_eternity. 师傅我有一个疑问啊,就是qemu仿真有必要用system吗?因为我看到有一些是直接起user的,就是什么情况下只有system可以而user不行的吗?
是否使用system模式取决于你的目标,有时候固件有硬件要求,而qemu-system在启动时可以指定硬件和驱动,对定制化比较友好
另外我这篇文章全文都没有用到qemu-system,你是不是上课又开小差了
2024-11-27 17:36
0
游客
登录 | 注册 方可回帖
返回
// // 统计代码