QNX是一种商用的类Unix实时操作系统,遵从POSⅨ规范,目标市场主要是嵌入式系统。QNX成立于1980年,是加拿大一家知名的嵌入式系统开发商。QNX的应用范围极广,包含了:控制保时捷跑车的音乐和媒体功能、核电站和美国陆军无人驾驶Crusher坦克的控制系统,还有RIM公司的BlackBerry PlayBook平板电脑。QNX系统将/usr/bin/passwd中的二进制以可输出的格式到/etc/shadow文件中。它包含了生成和解析这些hash值的所有逻辑数据,这是逆向这个格式的最好资源。

这个文件支持好几种hash加密方法:MD5,SHA-{256,512},以及QNX遗留的不安全加密实现(参见CVE-2000-0250)。他们分别命名为md5_crypt,sha2_crypt,qnx_crypt。

另外,其同时还支持解析明文密码的plain_crypt方法,但是这个你需要手动修改/etc/shadow。 有趣的是,SHA-1支持比较老的版本,但是由于没有链接库调用路径,所以没有办法使用。

QNX Neutrino 6.6.0默认的hash方法是SHA-512,1000轮计算,并附带16字节的盐值。用SHA-512对用户账号密码附加8字节的盐值做1000轮的计算生成的结果如下:

这是MD5和SHA-{256,512}的通用格式。QNX的hash加密方法,格式上很像传统的Linux DES加密字符串。

1.Shadowed密码文件用冒号(:)分割得到下面接个段:

2.username – 用户名

3.@S,100@386d...truncated...da5d@129b6761 –可输出的hash字符串(根据使用hash方法的不同而不同)

4.1448613322 – 设置密码时产生的时间戳

5.0 – 未知

6.0 – 未知

面我还未找到最后两个值是用来干嘛的,但这两个值总为0也许跟不可使用的账户有关。

可输出的hash字符串又被@符号分割成下面这几个段:

S,100 –前面表示使用的hash方法,后面表示加密计算轮数

S -- SHA-512

s -- SHA-256

m -- MD5

p – 明文密码

386d...truncated...da5d – 使用hash方法计算出的16进制结果

129b6761 – 16进制盐值

Hash密码例子

下面所有的例子都是密码的hash值

SHA-512加密, 1000轮, 16字节盐值

username:@S@60653c9f515eb8480486450c82eaad67f894e2f4828b6340fa28f47b7c84cc2b8bc451e37396150a1ab282179c6fe4ca777a7c1a17511b5d83f0ce23ca28da5d@caa3cc118d2deb23:1448585812:0:0

SHA-512加密, 1000轮, 8字节盐值

username:@S@386d4be6fe9625c014b2486d8617ccfc521566be190d8a982b93698b99e0e3e3a18464281a514d5dda3ec5581389086f42b5dde023e934221bbe2e0106674cf7@129b6761:1448585864:0:0

SHA-256加密, 1000轮,16字节盐值

username:@s@1de2b7922fa592a0100a1b2b43ea206427cc044917bf9ad219f17c5db0af0452@36bdb8080d25f44f:1448585954:0:0

MD5加密, 1000轮, 16字节盐值

username:@m@bde10f1a1119328c64594c52df3165cf@6e1f9a390d50a85c:1448585838:0:

内部二进制代码

从QNX Neutrino 6.6.0系统得到的/usr/bin/passwd 二进制并不很令人兴奋。 这是一个32位的可执行文件,没有剪去符号表和libc,ld-linux,linux-gate的动态链接,能够找到shadowed密码文件的所有hash加密实现。

文件/etc/default/passwd会影响二进制的行为,只有个QNXCRYPT指令存在于文件中时QNX加密方法才会被使用。另外一些有趣的指令,比如STRICTPASSWORD确保密码使用至少两个字符集、NOPASSWORDOK允许使用空白密码。

函数gensalt使用系统时间初始化一个随机算法来生成一个随机值,如果想要深入挖掘可以使用initstate,setstate,random,srandom函数。我没有很详细看这几个函数,但是聚合熵少于8字节随机操作会失败。 该盐值是16进制字符串,如果设置为16字节就是16个字符。

qnx_crypt 已经有说明文档,并且没有修改。

md5_crypt 使用函数MD5Init, MD5Update, MD5Transform。

sha2_crpyt 使用函数shaXXX_init, shaXXX_update,shaXXX_done,XXX指的是位,如512。

QNX的hash函数是按位偏移的。 Hash函数初始化之后,更新过程如下所示:

digest = update(salt), update(password) * rounds, update(password)

最后一次轮数置为0时,是使用密码来更新hash函数的。 所以摘要被计算出来的时候,1000轮的设置,其实是被计算了1001轮。 除此之外,其他都是标准的。

浅析QNX系统的密码Hash格式

浅析QNX系统的密码Hash格式

浅析QNX系统的密码Hash格式

浅析QNX系统的密码Hash格式

QNX 密码hash值爆破

John the Ripper (即使用了jumbo补丁)和其他通用的工具都不支持QNX shadowed密码的hash格式。

我尝试用python的hashlib和passlib模块重新实现hash函数的逻辑。但是我得到的输出跟/usr/bin/passwd产生的二进制结果无法匹配。 所用方法的实现都是一致的,所以我意识到QNX的hash函数有一些特有的实现。这是QNX自己实现的代码,并不依赖于通用的扩展库, 比如OpenSSL。

如果你想暴力破解hash值,你可以直接在GDB调试中调用它。另一个优雅的实现就是使用dlopen(3) 和dlsym(3)去从C的封装调用这个函数。