工控安全的学习进入了新的阶段,老师给我们发了三篇文章,一篇是常见漏洞发生情况,比较偏理论,另外两篇是对路由器漏洞的分析和复现,比较偏实践。我比较不喜欢理论,更喜欢动手,所以先从路由器漏洞复现开始了。参考文章
需要用到的工具
- ghidra
- binwalk
- qemu
获取固件
按照文章说的下载RAX30-V1.0.7.78.zip,并解压得到RAX30-V1.0.7.78_1.img
镜像文件和一份说明书,我们主要关注这个镜像文件。
首先,先用binwalk
把镜像拆了。
binwalk
命令我也才刚接触,大概就是用来从二进制文件里面拆出文件,通常拆img或者bin等镜像文件,对于file
查不出是什么文件类型的二进制文件都可以用来试一试,听说也能用于分离某些数据隐写
1 | binwalk -Me RAX30-V1.0.7.78_1.img |
之后可以看见当前目录下生成了一个_RAX30-V1.0.7.78_1.img.extracted
目录,
这些压缩文件我都试过了,都打不开,squashfs-root
则是路由器的文件系统,之后主要研究这个。
找到入口函数
出于好奇心,我先chroot进去跑了一下pucfu
,貌似要加参数,但是不知道加什么,
不知道怎么跑,继续看文章。
命令注入漏洞出现在/lib/libpu_util.so中定义的SetFileValue()函数中,该函数由/bin/pucfu导入。此函数将传递一个用户控制的值,该值将附加到已执行的execve shell命令中。
然后文章还给出了调用关系图,
为了方便操作,我们先新建个项目目录,再把涉及到的库和程序复制到项目目录里,再对复制出来的进行反编译。
先用ghidra对/bin/pucfu
进行反编译,然后我在函数列表中并没找到main
,但是找到了个疑似入口函数的,
查查__libc_start_main
是什么,参考了一下这篇文章:入口函数与程序初始化浅析
1 | int __libc_start_main( |
这是__libc_start_main的函数头部,可见和_start函数里的调用一致,一共有7个参数,其中main由第一个参数传入,紧接着是argc和argv(这里称为ubp_av,因为其中还包含了环境变量表)。除了main的函数指针外,外部还要传入3个函数指针,分别是:
- init:main调用前的初始化工作。
- fini:main结束后的收尾工作。
- rtld_fini:和动态加载有关的收尾工作,rtld是RunTime LoaDer。
所以FUN_FUN0010dfc
就是我们要找的主函数
阅读反编译代码
跳转之后,超长if和多重if嵌套使人无法阅读,
把代码复制到现代的代码编辑器里面,稍微折叠一下,使代码稍微可读一点,
稍微正常了一点,前面一堆编号命名的变量没有截图,接下来看一下主函数的流程。
首先前面两个fopen
打开了一个控制台和一个日志文件,应该是用于调试时输出信息还有输出日志的,没有什么好说的。
param_1
和param_2
分别对应argc
和argv
,如果参数个数大于1,就用getopt
来获取控制台参数的,如果参数读取完,则返回-1,未知参数返回'?'
,将获取到的参数保存在iVar1
内。
if(iVar1==-1)
,是个超长的语句块,而且里面有多重if嵌套,目测是用于在参数读取完毕之后进行初始化的,我们最后再看这个。
if(iVar1==0x49)
,0x49对应的ASCII是I
大写字母i,就是修改了puVar6=0x4
,然后跳到getopt
前的那个标签,不知道为什么不放在switch里面。
switch(iVar1)
,很显然就是对对每个参数进行的操作,且几乎对每个参数的操作里面都有个goto
,跳到getopt
前的那个标签。
0x68那个对应的字符是h
也就是help,会跳到LAB_00010f3c
处理pcVar5
之后跳到LAB_00010e74
输出帮助信息然后退出程序,返回-1。
还有一个特例是0x72,对应字符r
,
将iVar1
设为了随机数,之后传递给了FUN_FUN0001189c
,修改了local_local1830
,break之后执行local_1834=1
,然后跳到getopt
前的那个标签。
然后看看FUN_FUN0001189c
这样调用显然直接跳到了FUN_FUN000117c8
,它的两个参数一并传过去了,然后执行了一系列我看不懂的计算,先暂时不管
接下来看看之前的超长if的前面一段,
它首先调用了DBG_DBGPRINT
,从名字还有之前运行的结果也能猜到,这是个在debug模式下输出信息用的函数,并且我们也知道了这几个变量分别是什么意思,去试试参数。
可以看见输出的信息有在变化,但是不知道为什么依然跑不起来,继续往下看。
日志输出模式时,将fw_debug
设为一个函数的地址
这个显然就是用于写入日志文件的,前情回顾
再往下看,之后调用了fw_check_init
,这个函数在libfwcheck.so
里面,用ghidra打开看一下。
显然,如果开了日志模式,到这里肯定会写入日志的,跑一下看看,
日志文件是创建了,但是并没有向日志写入任何内容,而且文件有写入权限,看来是在fw_check_init
附近出现了段错误,这次暂时止步于此,之后我再去学习用gdb调试程序。
后续
第二天我没开电脑,用手机连着服务器调试的时候,发现好像意外的运行了一下,但是换成电脑上复现不出来,不知道为什么会报段错误,等有时间再去看看。