需解密IPMI协议的流量,此协议运行在服务器的BMC(Baseboard Management Controller)上,可理解为独立的小核,可能实现为arm:linux等,用于带外管理,如远程装机等操作。虽然通信过程中,有认证,有加密,有完整性保护,但此协议本身设计的并不足够安全,导致在捕获到合法用户的认证流量后,可对其登录口令进行离线破解,最终解密其通信流量。
破解口令
找到了一篇非常好的关于BMC漏洞整理文章:BMC 历史漏洞汇总,其中看起来能用的上的就是CVE-2013-4786:
这个密码hash泄露的漏洞还被实现到了msf中:Intelligent Platform Management Interface - Information Disclosure,不过能用的现成的方法都是需要此协议服务端在线,而不是给一个流量文件,所以要自己分析了,根据上文的漏洞分析,以及文档:
破解hash所需要的字段在RAKP Message 1、RAKP Message 2中:
从数据包中找到这些字段:
然后按照CVE-2013-4786的利用方法组合好这些数据:
remote id (4) a4 a3 a2 a0
manage id (4) 03 88 f4 9b
the remote console's random number (16) a5 42 74 3a 4f 19 46 30 ca 69 a7 d1 14 ad cf ec
the managed system's random number (16) eb 30 89 13 03 f4 b3 a6 c0 cb 99 9e 37 3a b2 40
the managed system's GUID (16) e4 7b d0 5c ab 77 00 10 8e 2c a8 1e 84 66 85 65
the priv level (1) 14
the length of the user name (1) 05
name (5) 61 64 6d 69 6e
Hmac (20) 2b 76 e1 98 a9 6c aa 24 bd 1d 6f f5 df e3 91 0e e6 27 d9 e8
之前的文章提到过可以直接用hashcat,其优点是灵活,这也意味着参数多:
使用7300模式:
➜ hashcat --help | grep 7300
7300 | IPMI2 RAKP HMAC-SHA1 | Network Protocols
将拼好的数据送进hashcat,用法示例:example_hashes
➜ ~ hashcat -m 7300 -a 3 -w 3 -O a4a3a2a00388f49ba542743a4f194630ca69a7d114adcfeceb30891303f4b3a6c0cb999e373ab240e47bd05cab7700108e2ca81e84668565140561646d696e:2b76e198a96caa24bd1d6ff5dfe3910ee627d9e8
hashcat (v6.1.1) starting...
...
a4a3a2a00388f49ba542743a4f194630ca69a7d114adcfeceb30891303f4b3a6c0cb999e373ab240e47bd05cab7700108e2ca81e84668565140561646d696e:2b76e198a96caa24bd1d6ff5dfe3910ee627d9e8:admin
Session..........: hashcat
Status...........: Cracked
结果为admin,破解一次后可以直接用 –show 参数打印之前的结果,不需第二次计算:
➜ hashcat -m 7300 -a 3 -w 3 -O a4a3a2a00388f49ba542743a4f194630ca69a7d114adcfeceb30891303f4b3a6c0cb999e373ab240e47bd05cab7700108e2ca81e84668565140561646d696e:2b76e198a96caa24bd1d6ff5dfe3910ee627d9e8 --show
a4a3a2a00388f49ba542743a4f194630ca69a7d114adcfeceb30891303f4b3a6c0cb999e373ab240e47bd05cab7700108e2ca81e84668565140561646d696e:2b76e198a96caa24bd1d6ff5dfe3910ee627d9e8:admin
故用户名口令为:admin:admin
解密通信
然后就是继续看文档,可见此流量协商的加密方案为AES-CBC-128,秘钥的计算方法如图:
其中KG就是刚才破出来的口令:admin,尝试用此法验证hmac,并恢复一组数据fab1bd3339463a9aadb3ad28b4c961bf:
import hmac
import hashlib
from Crypto.Cipher import AES
mode = AES.MODE_CBC
key = b'admin'
sidm = 'a4a3a2a0'
sidc = '0388f49b'
rm = 'a542743a4f194630ca69a7d114adcfec'
rc = 'eb30891303f4b3a6c0cb999e373ab240'
guidc = 'e47bd05cab7700108e2ca81e84668565'
rolem = '14'
ulenm = '05'
unamem = '61646d696e'
m1 = sidm + sidc + rm + rc + guidc + rolem + ulenm + unamem
m2 = rm + rc + rolem + ulenm + unamem
m1 = bytes.fromhex(m1)
m2 = bytes.fromhex(m2)
sig = hmac.new(key,msg=m1,digestmod=hashlib.sha1).digest()
sik = hmac.new(key,msg=m2,digestmod=hashlib.sha1).digest()
print(sig.hex())
print(sik.hex())
m3 = b'\x02'*20
k2 = hmac.new(sik,msg=m3,digestmod=hashlib.sha1).digest()
print(k2.hex())
aeskey = k2[:16]
print(aeskey.hex())
iv=bytes.fromhex('829c999137e535bf944ad9f7fddd3a16')
da=bytes.fromhex('fab1bd3339463a9aadb3ad28b4c961bf')
cryptos = AES.new(aeskey, mode, iv)
msg = cryptos.decrypt(da)
print(msg.hex())
结果如下:
➜ python3 exp.py
2b76e198a96caa24bd1d6ff5dfe3910ee627d9e8
9e7e1f6d2dd5a874c40b56965e440182e882b929
0d2dc563f8caf165a73d706938a1255bf8c96608
0d2dc563f8caf165a73d706938a1255b
2018c881043b043c0102030405060707
其中2018c881043b043c0102030405060707即为结果,最后的递增字节为aes分组的padding,证明恢复正确,故尝试恢复第三组的sol的udp流量,可通过wireshark追踪udp流提取出来:3.pcapng,最后对恢复的明文做一些分析以及处理:
- 明文内容是登录服务器过程的输入输出
- 明文前的有16字节的hash
- 明文后有aes分组的padding
- 区分开请求和响应的结果
- flag是请求报文中的登录密码
- 登录密码是逐个字节传递的
最后脚本如下:
import pyshark
import hmac
import hashlib
from Crypto.Cipher import AES
from pwn import *
sidm = 'a4a3a2a0' # package2
sidc = 'dfb7427d' # package1
rm = '6a3a75275c5fe60dce8a680d2b54fc78' # package1
rc = 'ea9ba3e57dd990cd709cfae894ff7ac2' # package2
guidc = 'e47bd05cab7700108e2ca81e84668565' # package2
rolem = '14' # package1
ulenm = '05' # package1
unamem = '61646d696e' # package1
m2 = rm + rc + rolem + ulenm + unamem
m2 = bytes.fromhex(m2)
m3 = b'\x02'*20
key = b'admin'
sik = hmac.new(key,msg=m2,digestmod=hashlib.sha1).digest()
print(sik.hex())
k2 = hmac.new(sik,msg=m3,digestmod=hashlib.sha1).digest()
print(k2.hex())
aeskey = k2[:16]
print(aeskey.hex())
flag = b''
cap = pyshark.FileCapture('./3.pcapng')
for pkt in cap:
if(pkt.ipmi_session.get_field('trailer')):
data = bytes.fromhex(pkt['DATA'].data)
i = data[:16]
c = data[16:]
cryptos = AES.new(aeskey, AES.MODE_CBC, i)
msg = cryptos.decrypt(data)
pad = u8(msg[-1:])+1
msg = msg[16:-pad]
if(msg[0]==0): continue
flag += msg[-1:]
print(msg)
print(flag)
#L3HCTF{BAdCrYpt0GrAph1cPRact1ce138295}