工控固件逆向题,有时会在vxworks上做文章。笔者在啃工匠安全实验室第二道CTF题时(见传送门),在原文的基础上,通过编写程序,计算出了hash为固定值cQwwddSRxS所使用key的解。
正文
对工控固件(一般为vxworks)的分析有固定的步骤,总结如下:
1.用binwalk查看固件基本信息并解压固件;
2.确认解压固件的信息如CPU类型,编译固件使用的大头序;
3.确定固件的加载地址,一般为0×10000(原文中未对如何找加载地址进行解读);
4.用IDA pro反汇编程序,并修复固件中的函数名;
5.找到对应的漏洞函数进行分析。
由于原文中未对如何找出固件加载地址进行说明,也未对最后碰撞hash值的过程进行说明。在这样的疑惑下,本人对这两个问题进行了进一步的解析:
一是找出了靠谱的计算固件加载地址的方法(这里要感谢”工匠安全实验室”的大哥给出的思路);
二是通过编写程序,碰撞出多个同一hash值的多个key解。
一、计算固件加载地址
固件加载地址的计算是通过vxworks固件中的函数符号表计算得出的。在固件中,与函数字符串相关的有两个地址,一个是在固件中字符串的存储地址;另一个是固件中保存的函数字符串的内存地址。这两个地址相减,就能得出固件的加载地址。因此,我们只需要定位到一个固定的字符串,找到它在固件中的位置以及在内存中加载它的地址,就能算出固件的加载地址了。在winhex中搜索APP_STATION这个字符串(该字符串有它的特殊性,它是函数字符表中的最后一个字符串,见下图,如果搜不到该字符串,按照这种方式找到字符表的最后一个字符串也是可以的),记下它在固件中的地址为0x26656c。
下一步还需要找到该字符串在内存中的加载地址,根据函数符号表的特点,它的内存加载地址为符号表的起始位置。在binwalk中可以查看vxworks的字符表的大致起始位置,如下图所示,binwalk计算的符号表的起始位置为0x301E74。
需要说明的是,这个值不一定准确,还需在winhex中进一步确认。在winhex中跳转到0x301E74,如下图所示。图的右侧出现了很规律的”…..’e…”的列。这种规律复合函数符号表的排列方式,因此,根据排列规律,符号表的起始位置应该为0x301E64。
在这个地址存储的是字符串的内存地址为0x27656C,而且可以看到,字符串的地址是倒序排列,所以这个地址就是前面的最后一个字符串的内存地址。
那么,加载地址为字符串的内存地址减去字符串地址有:0x27656C - 0x26656C =0×10000
算出了固件的加载地址,当我们加载固件后,需要修复函数名该怎么办呢?可以利用函数名修复脚本完成这一操作,使用的脚本如下图所示:
在对具体的工控固件进行函数名修复时,脚本中有三个值需要注意下。loadaddres即是刚刚算出的加载地址,eaStart即是函数符号表的起始地址为0x301E64,eaEnd是函数符号表的结束地址,这个地址怎么找,还是只有根据符号表的规律来找。如下图所示,符号表会规律的排列,这种规律排列在0x3293a4结束,因此,这个地址即为符号表的结束地址。
这样,才可以顺利地加载并运行该脚本。
二、暴力碰撞hash值
先通过固件逆向分析loginDefaultEncrypt函数,在IDA Pro中可以看到loginDefaultEncrypt函数的反汇编情况,结合vxworks给出的源码,可重写该函数为:
#p#分页标题#e#
在函数里可以看到,输入的密码key长度有限制,长度得大于8,小于40。而hash值cQwwddSRxS的长度为10。经分析发现,长度为9和10的key都可能会产生长度为10的hash值。因此,本人先通过编写程序随机生成长度为10的密码本,代码如下,为shell脚本。
在大for循环中,共生成了100万个长度为10的密码。在shell中运行该程序:
./10pass.sh > 1.txt #将随机密码输出到1.txt文件中。
再编写程序循环读入密码本中随机生成的密码,采用已经写好的loginDefaultEncrypt函数算出密码对应的hash值;最后,与题目给出的hash值进行比较,如算出的hash与题目hash的值相等,则视为碰撞出了key值。下面是给出程序的main函数,在函数中可以清楚地看到每一步的操作。
用gcc编译:gcc -o guesshash ./guesshash.c,运行,碰撞出的结果如下图所示。
可以看到,这确实是一个很弱的加密算法,100万个随机密码就碰撞出11个hash值相同的结果。
最后,本次实验的所有实验代码见github:https://github.com/scu-igroup/ctf_vxworks
总结
vxworks固件已曝出多个漏洞,要想定位这些漏洞,还需一些固件逆向的知识。本人即是在学习的过程中,发现计算固件加载地址和hash碰撞在现有的资料中,涉及的并不多,因此自己总结出了一套方法,在此分享出来,供大家参考。如有其他思路和建议,欢迎一起讨论。