记一次全设备通杀未授权RCE的挖掘经历
想来上一次挖洞还在一年前的大一下,然后就一直在忙活写论文,感觉挺枯燥的(可能是自己不太适合弄学术吧QAQ),所以年初1~2月的时候,有空的时候就又会挖一挖国内外各大知名厂商的设备,拿了几份思科、小米等大厂商的公开致谢,也分配到了一些CVE
和CNVD
编号,之后就没再挖洞,继续忙活论文了QAQ。
某捷算是国内挺大的厂商了,我对其某系统进行了漏洞挖掘,并发现了一个可远程攻击的未授权命令执行漏洞,可以通杀使用该系统的所有路由器、交换机、中继器、无线接入点AP
以及无线控制器AC
等众多设备,危害还是相当严重的。
根据厂商的要求,在修补后的固件未发布前,我对该漏洞细节进行了保密。如今新版本固件都已经发布,在这里给大家分享一下这一次的漏洞挖掘经历(包括固件解密、仿真模拟、挖掘思路等),希望能给各位师傅带来些许启发(大师傅们请绕道QAQ)。
声明: 本文仅供用于安全技术的交流与学习,文中涉及到的敏感内容都进行了删减或脱敏处理,仅分析了漏洞链。若读者将本文内容用作其他用途,由读者承担全部法律及连带责任,文章作者不承担任何法律及连带责任。
固件解密
可以从厂商官网下载到最新固件,然而可以发现其中的固件大多都是加密的,用binwalk
是无法解开的:
这大概是想要分析该固件所需迈过的第一道坎了,不过好在还是比较容易解密的。原因在于,只是大部分固件都被加密了,但是仍有少部分固件(或过渡版本的固件)并未加密,很容易想到这些固件升级的过程中肯定也会使用到解密的程序,因此可以通过解开这些未加密固件,找到解密程序,并逆向分析出相关算法,这也是固件解密最常用的一种手段。并且,一般一个厂商的固件加密算法都是相同的,故这样所有的固件我们都能够解开了。
此时,我们惊喜地发现xxx
系列产品的xxx
型号固件并没有被加密,可以成功解开。然而,如何找到固件的解密程序呢?显然,固件的解密操作肯定是在刷固件之前进行的,因此我们可以查找OpenWrt
中用于刷固件的mtd
命令进行定位:
很显然,此处的rg-upgrade-crypto
自然就是我们所要找到固件解密程序,并找到它的路径/usr/sbin/rg-upgrade-crypto
,对其逆向分析。
(由于该加解密算法仍然被广泛应用于某捷的各类核心产品中,故这里不放出具体逆向分析的过程,此处省略xxx字........)
因此,我们只需要根据rg-upgrade-crypto
写出解密脚本,即可成功解开固件了:
之后,解开不同类别、不同型号设备的固件,可以发现众多设备均使用的是该系统,因此只要挖出一个洞,就可通杀所有设备了。由于授权洞的实际影响并不算太大,所以我们期望挖出未授权远程命令执行漏洞。
漏洞分析
此部分以xxx
固件为例进行分析,该固件是aarch64
架构的。其他固件也许架构或部分字段的偏移不同,但均存在该漏洞。
找到无鉴权的API接口
显然,此类固件的cgi
部分是用Lua
所写的。我们既然想要挖未授权的漏洞,那么首先就要找到无鉴权的API
接口,定位到/usr/lib/lua/luci/controller/eweb/api.lua
文件。
可以看到,只有对/cgi-bin/luci/api/auth
发送请求的时候,不需要权限验证:
1 |
|
根据调用的rpc_auth
函数,可见此处对应的处理文件是/usr/lib/lua/luci/modules/noauth.lua
:
1 2 3 4 5 6 |
|
进一步分析/usr/lib/lua/luci/utils/jsonrpc.lua
中的handle
及其相关函数,可以得知这里通过JSON
数据的method
字段定位并调用noauth.lua
中对应的函数,同时将Json
数据的params
字段内容作为参数传入(由于与该漏洞原理关系不大,此处不展开分析)。
寻找可能存在漏洞的入口
在noauth.lua
中,有login
,singleLogin
,merge
和checkNet
四个方法。其中,singleLogin
函数无可控制的参数,不用看;checkNet
函数中参数可控的字段只有params.host
,并拼接入了命令字符串执行,但是在之前有tool.checkIp(params.host)
对其的合法性进行了检查,无法绕过。
再来看到login
登录验证函数,这里可控的字段乍一看比较多,比如params.password
,params.encry
,params.limit
等字段。其中,对params.password
字段用tool.includeXxs
函数过滤了危险字符,故大概率之后会有相关的命令执行点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
再来看到继续调用的tool.checkPasswd
函数(在/usr/lib/lua/luci/utils/tool.lua
中),其中检测了传入的encry
和limit
字段的真假值,并在这两个字段中写入了相应的固定字符串,checkStat.username
又是传入的固定用户名admin
,因此真正可控的只有password
字段,并调用了cmd.devSta.get
函数进一步处理。
1 2 3 4 5 6 7 8 9 10 11 |
|
然而,虽然password
字段用includeXxs
函数(同样在tool.lua
中)过滤了危险字符,但是并没有过滤\n
这个命令分隔符。因此,若之后当真存在命令执行点的话,似乎还是有希望完成命令注入的。
1 2 3 4 |
|
继续往下看到/usr/lib/lua/luci/modules/cmd.lua
,devSta.get
对应着如下处理函数,其中opt[i]
循环匹配到get
方式,会通过doParams
函数对传入的Json
参数进行解析,将其中的data
等字段分离出来,传入fetch
函数做进一步处理。
1 2 3 4 5 6 |
|
然而,注意到doParams
函数中对data
字段进行提取的时候,用到了luci.json.encode
函数。这里的data
字段就是上述checkPasswd
函数中传入devSta.get
作为Json
参数的_data
的内容,我们的疑似注入点password
字段就在其中。此处的luci.json.encode
函数会对\n
(即\u000a
)类字符进行转义,也就不会被解析成换行符了,不论我们后续再如何传参,这个疑似的漏洞点已经被封堵住了。
1 2 3 4 |
|
因此,我们只能将目光聚焦于noauth.lua
中最后一个可能的入口merge
方法了。这个函数比较简单,调用了devSta.set
函数,其Json
参数中的data
字段就是传入的POST
报文中params
的内容。
1 2 3 4 |
|
这里merge
方法的入口处没有任何过滤,不过之后是否存在字符过滤和命令执行点还需要进一步分析。
进一步分析参数传递过程
在noauth.lua
的merge
函数中,调用了devSta.set
函数,同样是对应着cmd.lua
中的如下位置,此时opt[i]
循环到了set
方式。此时,由于之前没有任何过滤,无需使用换行符作为命令分隔符,最简单的分号、反引号之类的即可,故doParams
函数中的encode
不会造成影响。
1 2 3 4 5 6 |
|
接着,我们可控的data
字段将被传入cmd.lua
的fetch
函数中。其中,会将从第四个开始的参数(包括data
字段),均传递到第一个参数所指向的函数中,即/usr/lib/lua/dev_sta.lua
中的fetch
函数。
1 2 3 4 5 |
|
在/usr/lib/lua/dev_sta.lua
的fetch
函数中,这里的cmd
是set
方式,module
是networkId_merge
,而此处的param
就是我们可控的data
字段(即最初POST
报文中params
的内容)。可见,对一些字段赋予了真假值后,最终将参数都传递给了/usr/lib/lua/libuflua.so
中的client_call
函数。接下来,就是对二进制文件逆向分析并寻找是否存在命令执行点了。
1 2 3 4 5 6 |
|
然而,分析libuflua.so
可以发现,Lua
中所调用的client_call
函数,其实是uf_client_call
函数,这是在其他共享库中定义的函数。查找对比一下,不难发现这个函数定义在/usr/lib/libunifyframe.so
中。
在/usr/lib/libunifyframe.so
的uf_client_call
函数中,先将传入的data
等字段转为Json
格式的数据,作为param
字段的内容。然后将Json
数据通过uf_socket_msg_write
用socket
套接字(分析可知,此处采用的是本地通信的方式)进行数据传输。
1 2 3 4 5 6 7 8 9 10 |
|
既然这里采用uf_socket_msg_write
进行数据发送,那么肯定有某个地方会使用uf_socket_msg_read
进行数据接收,再进一步处理。匹配一下,一共三个文件,很容易锁定/usr/sbin/unifyframe-sgi.elf
文件。又发现在初始化脚本/etc/init.d/unifyframe-sgi
中,启动了unifyframe-sgi.elf
,即说明unifyframe-sgi.elf
一直挂在进程中。因此,我们可以确定unifyframe-sgi.elf
就是接收libunifyframe.so
所发数据的文件(这里采用了Ubus
总线进行进程间通信)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
接下来就是最核心的部分,对unifyframe-sgi.elf
二进制文件进行逆向分析并寻找命令执行点了。
逆向分析并寻找命令执行点
由于篇幅限制,笔者无法对所有细节都做到详细分析,故建议读者在复现此部分内容之前,自己先逆向分析一遍,体会一下。
在unifyframe-sgi.elf
中,对uf_socket_msg_read
函数交叉引用,找到socket
数据接收点。如下方代码段,v6 = 0x432000
,简单计算一下,可知v57
即为uf_socket_msg_read
函数,其中接收到的数据存储在v56[1]
中。接收到的Json
数据形如{"method":"devSta.set", "params":{"module":"networkId_merge", "async":true, "data":"xxx"}}
(可结合上文,自行分析得出),其中data
字段可控。
1 2 3 4 5 6 |
|
接下来就是根据调试等级向日志写入相关信息的部分,不需要管。之后,会调用parse_content
函数,从这个名字就可以看出是对v56
中的Json
数据进行解析的。解析成功后,就会将处理后的v56
作为参数传入add_pkg_cmd2_task
函数。
1 2 3 4 5 6 |
|
我们先来看parse_content
函数,显然method
字段不包含cmdArr
,因此进入else
分支,其中调用parse_obj2_cmd
函数进行数据解析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
在parse_obj2_cmd
函数中,需要注意记录一下各字段存储位置的偏移,后续逆向过程需要用到。这里暂且只记录两个,from_url
字段的偏移为81
,我们可控的data
字段的偏移为24
(v5
是QWORD
类型,八字节)。
1 2 3 4 5 6 7 8 9 10 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
此外,当async
字段为false
的时候,偏移76
和77
的位置都为1
。但这里的async
字段为true
,故这两个偏移处均为初始值0
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
再来看到add_pkg_cmd2_task
函数,前面部分是一些检查和无关操作,就不仔细分析了。很容易发现最后调用了一个很敏感的函数uf_cmd_call
,看名字应该是命令执行相关的。
1 2 3 4 |
|
在uf_cmd_call
函数中,乍一看,貌似有一个命令执行点,这里的v20
是偏移24
的位置,也就是data
字段内容,之后将data
字段中的数据转成Json
格式存入v24
,然后从中提取url
字段的内容拼接入命令字符串中,并用popen
执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
然而,仔细分析一番,就会发现这是空欢喜一场。因为v20
是偏移81
的from_url
字段,这是我们不可控的。若是该字段为假,会将data
字段内容传给v85[19]
(v85
是int64
类型,八字节),并直接跳转到LABEL_96
处,也就无法执行到上方的程序片段了。
1 2 3 4 5 6 7 |
|
从LABEL_96
处开始是一堆字段的提取,存放入v85
数组中,还有一些关于v85
数组中数据的处理。这里需要关注的是:v85
偏移8
和9
的位置为a1
偏移77
和76
的位置(上文分析过,此时这两个偏移的值均为0
)。
1 2 |
|
既然从LABEL_96
开始都是对v85
数组进行操作的,那么v85
指针肯定会作为参数传递给下一个调用的函数,以这个思路,就很容易定位到下面的ufm_handle(v85)
了。
1 2 3 |
|
在ufm_handle
函数中,由于我们是set
方式,因此会调用到sub_410140
函数。
1 2 3 4 5 6 7 8 9 |
|
进入sub_410140
函数,首先sn
字段为空的条件满足,跳转到LABEL_36
。
1 2 3 |
|
接着,会调用到sub_40DA38
函数。
1 2 3 |
|
在sub_40DA38
函数中,显然前面的部分无关紧要,不过需要注意一下v5
和v6
分别是a3
和a4
,根据传入的值,均为零。因此,进入else
分支,这里会将data
字段的内容(前文分析过,此处偏移19*8
的位置也被赋为了data
字段的内容)拼接入两个单引号内。此处v4
字符串形如/usr/sbin/module_call set networkId_merge 'xxx'
(可自行分析得出),很显然是一个命令,并且单引号内的内容我们可控,所以我们只需要左右分别闭合单引号,中间注入恶意命令,并用分隔符隔开即可完成命令注入。不过,这里还没到命令执行点,由于不确定之后是否会有过滤,我们需要接着往下看。
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 |
|
接着,由之前的分析,此处v7
偏移8
的位置为0
(async
不是false
),故进入else
分支,其中会将v4
传入ufm_commit_add
函数,作为第二个参数。
1 2 3 4 5 6 7 8 9 |
|
然后,继续进入async_cmd_push_queue
函数。
1 2 3 4 |
|
此处,a1
为0
,将a2
存入v4
偏移6*8
字节处,然后跳转到LABEL_28
的位置。
1 2 3 4 5 6 7 8 9 10 |
|
在LABEL_28
处,注意到最后使用sem_post
的原子操作,将信号量加上了1
。因此,应该会有其他地方在检测到信号量发生改变后,对数据进行处理。
1 2 3 4 5 6 7 8 |
|
通过对此处的信号量stru_433670
交叉引用,可以定位到sub_419584
函数。这里偏移56
的位置即为上述代码段中的v7
,对应传入的第三个参数,根据上文分析,其值为0
。因此,会将6*8
字节偏移处的数据(上文分析过,该偏移位置存放着命令字符串)作为popen
的参数执行,且没有任何过滤。此处采用的是异步执行的方式。
1 2 3 4 5 6 |
|
至此,该未授权RCE
漏洞的调用链分析完毕。
PoC
由于该漏洞影响较大,
Poc
暂不公开。各位师傅可根据上文分析,自行复现。
1 |
|
真机演示
对某远程测试靶机攻击后,无需身份验证即得到了该设备的最高控制权:
仿真模拟
此部分仿真采用的是xxx
型号的固件,因为这款是mipsel
架构的,仿真起来方便一些。
由于目前没有很完美的仿真工具,比较常用的FirmAE
,EMUX
,firmware-analysis-plus
等也都存在各种问题(至少直接仿真大多数设备都是不太行的),所以笔者一般都采用qemu-system
自行仿真模拟,再者该系统的固件不涉及到nvram
,采用的是uci
命令完成类似的效果,故也不需要用上述仿真工具来hook
相关函数了。
首先从https://people.debian.org/~aurel32/qemu/mipsel
下载vmlinux-3.2.0-4-4kc-malta
内核与debian_squeeze_mipsel_standard.qcow2
文件系统,这里提供的文件虽然是比较老的了(较新版可以在https://pub.sergev.org/unix/debian-on-mips32
下载),但不影响我们使用。
下面直接给出qemu
的启动脚本:
1 2 3 4 5 6 7 8 9 10 11 |
|
需要特别注意的是,这里设定了cpu
为74kf
,因为若不特别说明,默认是24Kc
,而该固件需要较高版本的cpu
,不然在之后chroot
切换根目录的时候就会出现Illegal instruction
(非法指令)错误。可用qemu-system-mipsel -cpu help
命令查看qemu-system-mipsel
所有支持的cpu
版本。
在正式开始仿真前,需要先进行网络配置。用ip addr
或ifconfig
命令查看一下主机的ip
,如下图为eth0
(或ens33
)对应的192.168.192.129
,若是没有,手动用sudo ifconfig eth0 xx.xx.xx.xx
分配一下即可。
然后,用上面的脚本启动qemu-system
(先需要配置一下/etc/qemu-ifup
),初始账号密码root/root
。在qemu
中,也需要给网卡分配一下ip
,这样主机和qemu
间就能通信了(可以互相ping
通)。
我们将固件打包成rootfs.tar.gz
,再通过scp rootfs.tar.gz root@192.168.192.135:/root/rootfs
传输给qemu
虚拟机,然后在qemu
虚拟机中tar zxvf rootfs.tar.gz
解压即可(打包之后传输更快)。接着,在qemu
中依次执行以下命令:
1 2 3 4 5 |
|
解释一下,这里chmod
给全部文件都赋予所有权限,是为了方便在仿真过程中不用再考虑权限问题的影响了。之后使用mount
将/proc
和/dev
系统目录挂载到rootfs
中的proc
和dev
目录(仿真系统只是切换了根目录,本质还是qemu
虚拟机的系统,故proc
和dev
这两个重要的系统目录仍应该是这个系统本身的目录,即qemu
虚拟机的系统目录,而切换了根目录后,proc
和dev
也被切换,因此需要挂载为原先的目录),最后用chroot
将rootfs
切换为根目录,完成准备工作。
以上都是些用qemu
对设备仿真模拟的基本操作,接下来正式开始对这款设备的固件进行仿真。首先,对于OpenWRT
来说,内核加载完文件系统后,首先会启动/sbin/init
进程,其中会进一步执行/etc/preinit
和/sbin/procd
,进行初步初始化。这当然也是仿真模拟的第一步,在启动/sbin/init
后,会卡住挂在进程中,我们可以再ssh
开一个新窗口进行后续操作,也可以用/sbin/init &
将其作为后台进程执行。
接着,真实系统会根据/etc/inittab
中按编号次序执行/etc/rc.d
中的初始化脚本,而/etc/rc.d
中的文件都是/etc/init.d
中对应文件的软链接。虽然说真实系统会依次执行所有的初始化脚本,但我们此处的仿真只是为了验证我们的漏洞,因此只需要部分仿真即可。
显然,我们最开始肯定是需要启动httpd
服务的,对应/etc/init.d/lighttpd
初始化脚本。用/etc/init.d/lighttpd start
命令启动服务后,发现缺少了/var/run/lighttpd.pid
文件:
这是因为我们是部分仿真的,没有按照次序,故之前没有创建这个文件,而通过查看该初始化脚本,可以发现此处/rom/etc/lighttpd/lighttpd.conf
的缺失并无影响。因此,创建/var/run/lighttpd.pid
文件后,再次/etc/init.d/lighttpd start
启动服务即可。
可以看到,此时进程中已经成功执行lighttpd
程序,并且通过浏览器可以正常访问该漏洞入口的api
。
接着,我们需要启动
unifyframe-sgi.elf
了,对应/etc/init.d/unifyframe-sgi
的初始化脚本。用/etc/init.d/unifyframe-sgi start
直接启动后,报错Failed to connect to ubus
:
是因为unifyframe-sgi.elf
中用到了ubus
总线进行进程间通信,因此需要先执行/sbin/ubusd
启动ubus
通信,才能启动uf_ubus_call.elf
,继而才能再启动unifyframe-sgi.elf
。
按照上述步骤启动后,可以发现进程中有了uf_ubus_call.elf
,但是仍然没有unifyframe-sgi.elf
,同时procd
守护进程收到了一个Segmentation fault
段错误的信号,意味着启动unifyframe-sgi.elf
的时候出现了段错误。
接下来,我们需要分析unifyframe-sgi.elf
为何会出现段错误,大概率是由于缺少一些文件或目录所导致的。首先,发现此时/tmp/uniframe_sgi
中已经存在record
文件夹,但并未创建sgi.log
日志文件,进入unifyframe-sgi.elf
的主函数,容易定位到reserve_core
函数,其中需要打开/tmp/coredump
目录,但这个目录此时是不存在的,因此造成了段错误。
创建/tmp/coredump
目录后,运行/usr/sbin/unifyframe-sgi.elf
程序,因缺少/tmp/rg_device/rg_device.json
文件报错:
这里的rg_device.json
大概率是在某前置操作中从其他位置复制过来的,故搜索同名文件,不过有很多:
为了确定是哪一个,我们定位到ufm_init
函数中,发现此处之后会从rg_device.json
中读取dev_type
字段的内容。 可以发现除了
/sbin/hw/default/rg_device.json
中都有此字段,这里随便复制一个/sbin/hw/60010081/rg_device.json
到/tmp/rg_device
目录下。之后再执行/usr/sbin/unifyframe-sgi.elf
程序,就发现没有新的报错,执行成功了。
此时进程中也有
/usr/sbin/unifyframe-sgi.elf
程序在运行。
最后,我们利用该漏洞注入
telnetd
命令启动相应服务,可以看到代表telnet
服务的23
号端口被成功开启。
至此,利用仿真模拟的环境对该漏洞的验证完成,总体来说对该设备的仿真还是比较容易的。
补丁分析
补丁1
遗憾的是,部分型号设备的固件在第一次修补之后仍存在漏洞,笔者已上报给厂商并修复。这里以xxx
固件为例,使用Diaphora
对新旧版本的unifyframe-sgi.elf
文件进行二进制对比分析。
容易发现,在新版固件的unifyframe-sgi.elf
文件中新增了stringtojson
和is_independ_format
函数:
在stringtojson
函数中,调用了is_independ_format
函数,判断是否存在单引号和反引号。若不存在就返回,而返回的内容无法通过单引号闭合,也就无法执行任意命令。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
1 2 3 4 5 6 7 8 |
|
若是存在单引号,且前面没有转义符,则对其Unicode
编码,即\\u0027
。反引号也同理。
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 |
|
进一步交叉引用,在sub_40DB48
函数中,对可控的数据用stringtojson
函数进行了过滤。然而,这里的过滤并不严谨,接着往下看。
由上述可知,若这里的v74
不为空,则存放着stringtojson
函数过滤后的内容,否则说明不存在单引号或反引号,也就未通过stringtojson
函数进行过滤。又由于stringtojson
函数处理后会带有双引号,故若包含了单引号或反引号,该命令在新版固件中实际为/usr/sbin/module_call set networkId_merge "{...}"
。虽然由于JSON
数据中双引号得是\"
才行(stringtojson
函数也会将双引号编码为\\u0022
),无法闭合绕过双引号,但是在双引号内是可以用反引号或$()
执行命令的,而这里只过滤了反引号,并未过滤$()
,也就给了攻击者可趁之机。
不过,在新版本固件中,也在其他方面加强了一定的安全检查和防护,例如在初始化脚本/etc/init.d/factory
中通过rm usr/sbin/telnetd
命令删除了telnetd
程序,也就无法通过开启远程登录而控制设备了。但是,不难想到还可以通过反弹shell
获取设备权限,这里笔者采用的是telnet
反弹的方式。
请求报文:
1 |
|
演示效果:
补丁2
其实,只要在noauth.lua
的merge
函数中对传入的params
加个过滤即可,如下:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
此处,通过includeXxs
函数过滤了各种危险字符,以及用includeQuote
函数过滤了单引号:
1 2 3 4 |
|
1 2 3 |
|
可见,在新版本固件中,将换行符\n
也过滤了,提高了安全性。
总结
这篇文章是在挖到这个0day
挺久之后写的了。依稀记得当时刚挖到这个漏洞的时候,有着些许兴奋,但更多的是感到不易,因为我当时觉得这条调用链还挺深的,里面也牵涉到了不少东西。但是,当我如今再梳理这个漏洞的相关细节的时候,我觉得这条调用链其实也就那样吧,整个挖掘思路和利用思路都不算难,抛开影响范围,并算不上品相多好的洞QAQ。
在挖这个洞的时候,我遇到的最大挑战就是逆向分析了,我觉得这里的逆向难度还是比较大的(当然我逆向水平也很菜)。在实际逆向分析的过程中,并没有文章中写的那么流畅,当时的挖掘思路也不可能是完全按照文章的流程来的,比如需要多考虑一些东西(例如,文章中一直都在找命令注入的洞,但其实也有可能是可控的params
字段造成的缓冲区溢出等等,这些在初次挖掘的时候也都需要考虑),当然也走了不少弯路,但好在最终是坚持下来了。
当时,我只知道params
字段是可控的,而params
内也是Json
的格式,于是猜测是其中的某个特定的字段可能会造成命令注入或缓冲区溢出等问题,因此就一路挖到底了。不过如今再看来,其实就这个洞而言,是否采用自动化的方式会更简单呢(当然就工业界来说,IoT
的全自动化漏扫我并没有看到过实际效果很好的工具,基本都是半自动化提高效率)?
进一步地从宏观上来看二进制漏洞的挖掘思路,无非就是从危险函数出发和从交互入口出发两种方式,显然前者在筛掉明显无法利用的危险函数点之后,所涉及的支路会更少,挖起来也会更容易,而后者基本是要从交互入口一路挖到中断点甚至挖到底的。然而,该漏洞却是采用后者的思路进行挖掘的,当时主要是考虑到只有一个可能的未授权入口,因此很自然地采用了后者的思路。现在想来,这里若是采用前者的思路,可能并不会那么容易地挖到此漏洞。如何更好地结合上述两种思路,特别是对于自动化漏扫来说,我觉得仍是值得思考的问题。
说了些自己粗浅的理解和感受,就说到这里吧。希望这篇文章能给各位像我一样刚入门IoT
漏洞挖掘的师傅带来些启发,也欢迎各位大师傅与我交流。最后,希望我在不久的将来能挖到在挖掘思路和利用手法上都有所创新的高质量0day
吧。
相关文章:
![](https://img-blog.csdnimg.cn/direct/ae81db65077b4bb99e63473277ec178f.png)
记一次全设备通杀未授权RCE的挖掘经历
想来上一次挖洞还在一年前的大一下,然后就一直在忙活写论文,感觉挺枯燥的(可能是自己不太适合弄学术吧QAQ),所以年初1~2月的时候,有空的时候就又会挖一挖国内外各大知名厂商的设备,拿了几份思科…...
![](https://img-blog.csdnimg.cn/direct/89f230c8f6d04e1997420940fba056a3.png)
【数据库编程-SQLite3(一)】sqlite3数据库在Windows下的配置及测试
学习分析 1、资源准备2、环境配置2.1、将资源包下载解压缩保存。2.2、在QT中创建工程,配置环境 3、测试配置3.1、 sqlite3_open函数3.2、sqlite3_close函数3.3、代码测试 1、资源准备 资源包 2、环境配置 2.1、将资源包下载解压缩保存。 解压缩得到以下文件 2.2、在QT中创建…...
![](https://img-blog.csdnimg.cn/direct/cf86a8e35c8d40e08044da9f112071c7.png)
YOLOv10改进 | 主干篇 | YOLOv10引入华为VanillaNet替换Backbone
1. VanillaNet介绍 1.1 摘要: 基础模型的核心是“越多越好”的理念,计算机视觉和自然语言处理领域取得的惊人成功就是例证。 然而,优化的挑战和变压器模型固有的复杂性要求范式向简单性转变。 在这项研究中,我们介绍了 VanillaNet,一种设计优雅的神经网络架构。 通过避免…...
![](https://www.ngui.cc/images/no-images.jpg)
C++ 迷宫问题
描述 定义一个二维数组 N*M ,如 5 5 数组下所示: int maze[5][5] { 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, }; 它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走…...
![](https://www.ngui.cc/images/no-images.jpg)
【Linux】Linux文件系统中主要文件夹列举_作用说明
在Linux系统中,文件夹(或称为目录)的组织结构是系统功能和用户数据的重要组成部分。以下是Linux系统中一些主要文件夹的列举及其作用说明: / (根目录): 是Linux文件系统的起点。通常只包含其他目录,不建议直接在其中存…...
![](https://img-blog.csdnimg.cn/direct/65e6d218d37b4a3ca456db30ee7b9113.png#pic_center)
移植案例与原理 - HDF驱动框架-驱动配置(1)
HCS(HDF Configuration Source)是HDF驱动框架的配置描述源码,内容以Key-Value为主要形式。它实现了配置代码与驱动代码解耦,便于开发者进行配置管理。应该,类似Linux DTS(Device Tree Source)设备树。 HC-GEN(HDF Configuration Generator)是…...
![](https://img-blog.csdnimg.cn/direct/7ca2491519c84665a5de51baa17bd097.png)
坚持刷题|反转链表
文章目录 题目思考实现1. 迭代方式实现链表翻转2. 递归方式实现链表翻转 Hello,大家好,我是阿月。坚持刷题,老年痴呆追不上我,今天继续链表:反转链表 题目 LCR 024. 反转链表 思考 翻转链表是一个常见的算法问题&a…...
![](https://img-blog.csdnimg.cn/direct/887e4e956e8447c4918abed3f080081d.png)
升级和维护老旧LabVIEW程序
在升级老旧LabVIEW程序至64位环境时,需要解决兼容性、性能和稳定性等问题。本文从软件升级、硬件兼容性、程序优化、故障修复等多个角度详细分析。具体包括64位迁移注意事项、修复页面跳转崩溃、解决关闭程序后残留进程的问题,确保程序在新环境中的平稳运…...
![](https://www.ngui.cc/images/no-images.jpg)
sqlite数据库整体迁移进mysql整个流程并解决中文异常问题
咨询【QQ】 sqlite轻量数据还行,随着数据量增大,不得不迁移进mysql 首先 电脑执行 sqlite3 db.sqlite3 .dump > dump.sql 会把整个sqlite的数据导出进 dump.sql中 紧接着我们把sqlite的sql转换成mysql的sql语句,因为mysql语句和 sq…...
![](https://img-blog.csdnimg.cn/direct/bf098702388d4fcf971dd552117ab72a.png)
Hadoop3:MapReduce中的Partition原理及自定义Partition
一、默认Partition分区配置 以WC案例来进行验证。 1、设置setNumReduceTasks 修改的代码 这行代码,确定了reduceTask的数量,也确定了分区逻辑 在mapper文件中,打上断点 计算分区的代码 这里会对每一个kv进行计算,然后&#…...
![](https://img-blog.csdnimg.cn/direct/fe5dd2492fe342bd9b5fa850b5ca14e5.png)
就因为没在大屏项目加全屏按钮,早上在地铁挨了领导一顿骂
“嗯嗯”,“嗯嗯”,“那产品也没说加呀”,“按F11不行吗?”,“嗯嗯”,“好的”。 早上在4号线上,我正坐在地铁里,边上站着的妹子,我看他背着双肩包,打着电话…...
![](https://img-blog.csdnimg.cn/direct/591239417db740f79fe643e9ee5c5678.png)
STM32学习记录(八)————定时器输出PWM及舵机的控制
文章目录 前言一、PWM1.工作原理2.内部运作机制3. PWM工作模式4.PWM结构体及库函数 二、PWM控制舵机 前言 一个学习STM32的小白~ 有错误评论区或私信指出提示:以下是本篇文章正文内容,下面案例可供参考 一、PWM 1.工作原理 以向上计数为例࿰…...
![](https://img-blog.csdnimg.cn/direct/172e258ae79840fbb625ec53280f3065.png)
Vue CLI,Vue Router,Vuex
前言 Vue CLI、Vue Router 和 Vuex 都是 Vue.js 生态系统中的重要组成部分,它们在构建 Vue 应用程序时扮演着关键角色。 Vue CLI Vue CLI 介绍 Vue CLI 是 Vue.js 的官方命令行工具,用于快速搭建 Vue.js 项目。它提供了一个图形界面(通过…...
![](https://www.ngui.cc/images/no-images.jpg)
互联网广告相关概念
互联网广告概念涉及多个关键指标和定价模式,它们帮助广告主和广告平台衡量广告效果、优化广告投放策略,并计算广告成本。以下是互联网广告中一些核心概念的简要概述: 1.ROI (投资回报率) 衡量广告投资的效益,计算公式为ÿ…...
![](https://www.ngui.cc/images/no-images.jpg)
如何在服务器上部署一个java程序
如何在服务器上部署一个java程序? 一、在服务器上安装jdk环境 1.创建目录用于存放jdk文件 cd /usr/local 2.下载最新版oracle jdk22 wget https://download.oracle.com/java/22/latest/jdk-22_linux-x64_bin.tar.gz 3.解压 tar -zxf jdk-22_linux-x64_bin.ta…...
![](https://img-blog.csdnimg.cn/img_convert/99baf5d6e9205b4b6ce020ba6e60b297.jpeg)
白酒:中国的酒文化的传承与发扬
中国,一个拥有五千年文明史的国度,其深厚的文化底蕴孕育出了丰富多彩的酒文化。在这片广袤的土地上,酒不仅仅是一种产品,更是一种情感的寄托,一种文化的传承。云仓酒庄的豪迈白酒,正是这一文化脉络中的一颗…...
![](https://img-blog.csdnimg.cn/img_convert/e4c8b23ee92ac7cd29f12372513cadff.webp?x-oss-process=image/format,png)
算法金 | 再见!!!梯度下降(多图)
大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 接前天 李沐:用随机梯度下降来优化人生! 今天把达叔 6 脉神剑给佩奇了,上 吴恩达:机器…...
![](https://img-blog.csdnimg.cn/direct/2101f9f21b92480aa8714efc21fe0c98.png)
python Django安装及怎么检测是否安装成功
一、winr 输入cmd 进入控制台。输入pip install Django5.0.1 二、如果安装过程没有问题。就进行下一步进行检查是否成功安装。 三、 1.在控制台输入python,进入python环境 2.输入 import django 3.继续输入 django.get_version()。显示版本号表示成功安装。...
![](https://img-blog.csdnimg.cn/direct/043c81437e9d4f249779cbc540de9b0f.png)
Swift开发——存储属性与计算属性
Swift语言开发者建议程序设计者多用结构体开发应用程序。在Swift语言中,结构体具有了很多类的特性(除类的与继承相关的特性外),具有属性和方法,且为值类型。所谓的属性是指结构体中的变量或常量,所谓的方法是指结构体中的函数。在结构体中使用属性和方法是因为:①匹别于结…...
![](https://img-blog.csdnimg.cn/direct/f25c388833eb42e8b1781622a07f020d.png)
如何解决input输入时存在浏览器缓存问题?
浏览器有时会在你输入表单过后缓存你的输入,有时候能提供方便。 但是在某些新建或新页面情况下出现历史的输入信息,用户体验很差。 解决方案 设置 autocomplete关闭 :<input type"text" autocomplete"off">增加…...
![](https://img-blog.csdnimg.cn/direct/fb18af1e9c02410ab67c19655d8633f1.png)
Java基础学习-方法
目录 方法基础概念 方法的格式: 案例:最简单方法的定义 案例:带参数的方法调用 案例:求圆的面积 带有返回值的方法: 方法注意点 方法的重载: 编辑 案例:数组的遍历: 案例…...
![](https://www.ngui.cc/images/no-images.jpg)
Ribbon与Nginx的区别
负载均衡实现的位置不同: Ribbon:负载均衡器位于客户端,不需要单独搭建。Nginx:需要建立一个独立负载均衡服务器,服务端。 负载均衡策略: Ribbon:提供了多种负载均衡策略,如随机策…...
![](https://www.ngui.cc/images/no-images.jpg)
R包开发详细教程
开发一个R包可以帮助你组织和共享代码。以下是一个详细的步骤教程,介绍如何开发一个R包。 步骤 1: 准备工作 确保你已经安装了以下R包: install.packages("devtools") install.packages("roxygen2") install.packages("test…...
![](https://www.ngui.cc/images/no-images.jpg)
图像的高频和低频细节
在图像处理和计算机视觉中,"高频"和"低频"是用来描述图像中不同类型细节的术语。这些术语源自信号处理领域,其中频率的概念用于描述信号随时间变化的,但在图像处理中,它们被用来描述图像随空间变化的…...
![](https://www.ngui.cc/images/no-images.jpg)
PostgreSQL源码分析——常量表达式化简
常量表达式化简 常量表达式可以进行化简,可降低执行器计算表达式的代价。在逻辑优化阶段,会判断是否可以进行常量表达式化简,如果可以,则在执行器执行之前就预先对常量表达式树进行计算,计算出常量后,以新…...
![](https://img-blog.csdnimg.cn/direct/53dc86d39dcc45bfae4e847dbbe168a4.jpeg)
速卖通自养号测评:安全高效的推广手段
在速卖通平台上,卖家们常常寻求各种方法来提升商品的曝光、转化率和店铺权重。其中,自养号测评作为一种低成本、高回报的推广方式,备受关注。然而,若操作不当,也可能带来风险。以下是如何安全有效地进行自养号测评的指…...
![](https://img-blog.csdnimg.cn/direct/a6b52a51d2a14202b1674bbb195772a2.png)
项目监督与控制
1.什么是项目过程度量?其方法有哪些? 项目过程度量是一种对项目执行过程中的活动和性能进行量化测量的方法。它涉及到收集、分析和解释项目数据,以便更好地理解项目的进度、质量和效率。过程度量的目的是提供关于项目健康状况的客观信息&…...
![](https://img-blog.csdnimg.cn/img_convert/276af05882d2d68f39b923180aa6ee77.png)
【LeetCode刷题】面试题 17.19. 消失的两个数字
1. 题目链接2. 题目描述3. 解题方法4. 代码 1. 题目链接 面试题 17.19. 消失的两个数字 2. 题目描述 3. 解题方法 例子假设: 数组A元素为 :1 ,4,5 缺少的元素为:2, 3 那么所有整数就为1 ~ 5ÿ…...
![](https://img-blog.csdnimg.cn/direct/c6183b4482ce42519102b89bbee84560.png)
如何定制Spring的错误json信息
一,前言 相信很多同学都有遇到过这样的spring错误信息。 在我们没有做catch处理时或者做全局的exceptionHandle时,Spring遇到抛出向外的异常时,就会给我们封装返回这么个格式的异常信息。 那么问题来了,我们能否对这个返回增加错…...
![](https://img-blog.csdnimg.cn/direct/a1a88d512cb94e3c915b085cacb7ff78.gif)
【第20章】Vue实战篇之Vue Router(路由)
文章目录 前言一、使用Vue-Router1.安装2. 创建路由器实例3. 注册路由器插件4. 根组件 二、访问路由器1.理论2.使用3. 展示 三、嵌套路由(子路由)1. 准备文件2. 配置路由3. 菜单配置4. 展示 总结 前言 Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成,…...
![](/images/no-images.jpg)
腾讯云建设一个网站要多少钱/东莞百度搜索优化
Day -? 居然还能报上thupc,我在队里唯一的作用大约是cfrating稍微高点方便过审。另外两位是lz和xyy。 Day -2 我夫人生日! Day -1 lz和xyy的家长都来了带我飞。住在去年thusc住的宾馆。晚上开黑打cometoj,好像又有小裙子了。 Day 0 早上九点…...
![](/images/no-images.jpg)
网站开发设计有哪些/推广游戏赚钱的平台
脚手架1. 脚手架是什么2. 为什么要开发脚手架3. 脚手架实现原理4. 脚手架开发4.1 开发流程4.2 安装脚手架4.3 脚手架开发难点1. 脚手架是什么 脚手架本质是一个操作系统的客户端,其通过命令行执行。如: vue create my-vue-app --force此条命令组成&…...
![](https://img-blog.csdnimg.cn/20210808223402783.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L25hbmZlaWJ1eWk=,size_16,color_FFFFFF,t_70)
轻量级wordpress主题/河北网站推广
设计模式 七大原则,UML类图 一、简述 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。问题(problem) --》解决方案(solution) --》效果(consequences),…...
![](/images/no-images.jpg)
网站地址解析/品牌广告视频
【分享】iTOP4412开发板-Bluetooth移植文档 最近须要把Bluetooth移植到iTOP-4412 开发平台。查阅了相关资料,经过一段时间的研究、调试,最终成功的将蓝牙功能移植到了开发板上面。这里笔者记录移植过程及注意事项,方便以后工作须要。iTOP-4412开发板的Bl…...
![](/images/no-images.jpg)
襄阳网站seo公司/seo诊断工具网站
大端和小端(Big-Endian和Little-Endian): 1) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。 2) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。 以…...
![](https://img-blog.csdnimg.cn/20181214010750857.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L015cm9uQ2hhbQ==,size_16,color_FFFFFF,t_70)
有没有做字的网站/网络营销策划书步骤
目录: 3、垃圾收集器以及内存分配 3.1、串行垃圾收集器 3.1.1、编写测试代码 3.1.2、设置垃圾回收为串行收集器 3.2、并行垃圾收集器 3.2.1、ParNew垃圾收集器 3.2.2、ParallelGC垃圾收集器 3.3 、CMS垃圾收集器 3.3.1、测试 3.4、G1垃圾收集器࿰…...