看我如何破解OpenNMS哈希密码?首席安全官频道

背景

在最近的一次渗透测试中,首席安全官频道我拿下了一台运行OpenNMS的服务器,并获取了该服务器的root访问权限。在后利用阶段我提取了几个本地用户的哈希密码,我想尝试破解这些哈希值因为这些密码可能会被重复用在其他重要认证上。但对于OpenNMS的哈希密码我几乎一无所知,通过在Google上的一番搜索也并未发现任何有价值的资源。为此,我决定发布一款Python工具以帮助那些OpenNMS服务器的渗透测试者。具初步了解这些哈希密码是base64编码的字符串,前16个字节是盐,剩余的32个字节是sha256(salt.password)的100,000次迭代。

百疏一漏

我们发现了一个服务器当前正运行着一个老旧的OpenNMS版本,而该版本曾被曝出存在一个已知的Java反序列化漏洞。漏洞详情可以参考FoxGlove Security发布的这篇文章。

Metasploit模块的利用并不容易。我们将模块指向了端口为1099的RMI接口,将payload设置为linux/x86/shell_reverse_tcp,并给予了以root权限运行的shell:

OpenNMS哈希密码

OpenNMS哈希密码

OpenNMS被安装在/opt/opennms中,我通过shell浏览了该目录,并找到了一个定义OpenNMS的本地用户帐户的文件。通过对一些用户名的观察,我意识到其中一些账户很可能是该组织的超级管理员账户,这更激起了我的破解欲望。

哈希被存储在/opt/opennms/etc/users.xml中,如下所示:

<?xml version="1.0"?>  
<userinfo xmlns="http://xmlns.opennms.org/xsd/users">  
  <header>
    <rev>.9</rev>
    <created>Wednesday, February 6, 2002 10:10:00 AM EST</created>
    <mstation>master.nmanage.com</mstation>
  </header>
<users>  
<user>  
      <user-id>ropnop</user-id>
      <full-name>Rop Nop</full-name>
      <user-comments></user-comments>
      <password salt="true">L5j2hiVX4B+LTHnY3Mwq5m5dBZzNdHhiBpvBjyCerBsBqqJcxRUsRAxaDQtjRkcn</password>
      <role>ROLE_RTC</role>
    </user>

...(more users)...

  </users>
</userinfo>  

以上XML中被加盐的这串字符引起了我的注意:

L5j2hiVX4B+LTHnY3Mwq5m5dBZzNdHhiBpvBjyCerBsBqqJcxRUsRAxaDQtjRkcn

我首先想到了john和hashcat并查看了它们的帮助页面,看是否有OpenNMS哈希模式,但可惜的是并没有发现任何有用的信息。然后我又使用Google进行了查询,仍然没有找到任何有关OpenNMS哈希是如何盐化和/或计算的解释。因此我决定自己来分析和破解它。

散列识别

大多数密码破解程序都会使用十六进制来表示哈希,因此我将XML中的base64值转换为十六进制:

>>> "L5j2hiVX4B+LTHnY3Mwq5m5dBZzNdHhiBpvBjyCerBsBqqJcxRUsRAxaDQtjRkcn".decode('base64').encode('hex')
'2f98f6862557e01f8b4c79d8dccc2ae66e5d059ccd747862069bc18f209eac1b01aaa25cc5152c440c5a0d0b63464727'  

接着,我使用了一个基于Python的HASH加密方式识别工具hashID来帮助我进行初步的hash判断:

OpenNMS哈希密码

OpenNMS哈希密码

从以上结果可以看到这可能是SHA-384加密,但这种加密是非常罕见的,因此我对其准确性持怀疑态度。

明文识别

即便我知道了它正确的哈希算法,但我仍然不知道它是如何加的盐,更不用说它加的盐是什么。我首先想到的是,盐可能被存储在OpenNMS使用的PostgresQL数据库中。由于我当前的权限为root,因此我可以连接数据库并查看表数据。经过一番查找并没有发现任何与密码或盐有关的数据。据此我断定,它一定被存储在应用程序的某个位置。

OpenNMS是一个开源的系统,因此我来到了它的Github页面并搜索了关键字“salt”。我获取到了一些用于测试的users.xml文件示例。

通过对源代码的检索,我发现了一处哈希密码加盐的断言测试:

@Test
    public void testAuthenticateRtc() {
        org.springframework.security.core.Authentication authentication = new UsernamePasswordAuthenticationToken("rtc", "rtc");
        org.springframework.security.core.Authentication authenticated = m_provider.authenticate(authentication);
        assertNotNull("authenticated Authentication object not null", authenticated);
        Collection<? extends GrantedAuthority> authorities = authenticated.getAuthorities();
        assertNotNull("GrantedAuthorities should not be null", authorities);
        assertEquals("GrantedAuthorities size", 1, authorities.size());
        assertContainsAuthority(Authentication.ROLE_RTC, authorities);
    }

经过对上述测试代码中的“rtc”用户哈希加盐计算后我们发现,其结果与我们之前发现的users.xml中的加盐密码哈希值相同。这意味着我们成功获取到了一个本地用户的明文密码。

    明文:rtc

    加盐哈希:L5j2hiVX4B+LTHnY3Mwq5m5dBZzNdHhiBpvBjyCerBsBqqJcxRUsRAxaDQtjRkcn

虽然我们仍然无法获知它是如何加的盐以及盐是什么,但是这为我们提供了一个很好的判断依据。

哈希算法识别

现在让我们把视线从Github上转回到我们的root shell。虽说Github上的源代码为我们提供了一个很好的参考依据,但服务器上代码可能会有所不同。因此,如果在服务器上找到源码会获得更准确的信息。

我进入到了opennms目录,并通过搜索关键字“salt”来定位:

$ find . -type f -exec grep -i -l salt {} \;
./etc/users.xml
./jetty-webapps/opennms/includes/angular.js
./jetty-webapps/opennms/RemotePollerMap/openlayers/lib/OpenLayers/Layer/HTTPRequest.js
./jetty-webapps/opennms/RemotePollerMap/openlayers/lib/OpenLayers/Tile/Image/IFrame.js
./jetty-webapps/opennms/RemotePollerMap/openlayers/OpenLayers.js
./jetty-webapps/opennms-remoting/webstart/jasypt-1.9.0.jar
./jetty-webapps/opennms-remoting/webstart/snmp4j-1.11.1.jar
./jetty-webapps/opennms-remoting/webstart/spring-security-config-3.1.0.RELEASE.jar
./jetty-webapps/opennms-remoting/webstart/spring-security-core-3.1.0.RELEASE.jar
./lib/bcprov-jdk14-1.38.jar
./lib/jasypt-1.9.0.jar
./lib/joda-time-2.1.jar
./lib/snmp4j-1.11.1.jar
./lib/spring-security-config-3.1.0.RELEASE.jar
./lib/spring-security-core-3.1.0.RELEASE.jar
./system/joda-time/joda-time/1.6.2/joda-time-1.6.2.jar
./system/org/apache/servicemix/bundles/org.apache.servicemix.bundles.jasypt/1.6_1/org.apache.servicemix.bundles.jasypt-1.6_1.jar

可以看到搜索出了大量包含”salt”关键字的JAR库文件,这里我们尤其关注./lib/jasypt-1.9.0.jar这个文件。

从他们的官方主页上我们了解到,Jasypt是一个java库,它允许开发人员不需要深入了解加密技术的工作原理,就可以轻松的为自己项目添加基本的加密功能。

通过对文档的进一步挖掘,我发现了一个让我看到有希望的东西:一个名为StrongPasswordEncryptor的类,它使用另一个被称为StandardStringDigester的类。以下是文档中关于StrongPasswordEncryptor类的简单描述:

OpenNMS哈希密码

OpenNMS哈希密码

Jasypt同样是开源的,因此我在Github上找到了这两个类的源码(StrongPasswordEncryptor和StandardStringDigester)。通过StandardStringDigester源码中的注释信息,我终于弄明白了digest是如何构建的。

create_digest.png

create_digest.png

至此,我已经获取到了所有我需要的信息:

    明文: ”rtc”

    Digest: L5j2hiVX4B+LTHnY3Mwq5m5dBZzNdHhiBpvBjyCerBsBqqJcxRUsRAxaDQtjRkcn

    盐长度: 16字节

    Digest格式: (salt.password)

    算法:sha256

    迭代:100,000

混合计算

现在让我们来验证一下算法,我们需要将盐的字节与明文连接,然后计算一个sha256摘要100,000次。我写了一个Python脚本来帮助我们验证明文和密码:

#!/usr/bin/env python

import sys
from hashlib import sha256

def checkPassword(encrypted, plaintext, iterations=100000, verbose=False):
    hexstring = encrypted.decode('base64').encode('hex') # i hate working with bytes
    salt = hexstring[:32]
    correct = hexstring[32:]
    if verbose:
        print "[+] plaintext: {}".format(plaintext)
        print "[+] salt: {}".format(salt)
        print "[+] target hash: {}".format(correct)
    testinput = salt.decode('hex')+plaintext
    
    for i in range(1,iterations+1):
        s = sha256(testinput)
        h = s.hexdigest()
        if h == correct:
            if verbose:
                print "{} iterations".format(i)
            return True
        else:
            testinput = s.digest()
    return False

def run():
    if len(sys.argv) < 3:
        print "Usage: {} base64value plaintext".format(sys.argv[0])
        sys.exit(1)
    
    if checkPassword(sys.argv[1], sys.argv[2], verbose=True):
        print "Correct!"
    else:
        print "Nope"

if __name__=='__main__':
    run()

 并用已知的明文进行测试,可以看到10万次迭代后我们得到了正确的结果!

plaintext_check.png

plaintext_check.png

编写一个破解器

为了方便大家对opennms哈希密码的额破解,我在Github上发布了一款Python编写的爆破脚本。你可以通过以下链接获取到:

https://github.com/ropnop/opennms_hash_cracker

该脚本首先会提取users.xml文件中的哈希值,然后使用我们提供的字典对散列进行爆破。此外,该脚本也包含了一些逻辑来解析和测试OpenNMS的无盐哈希(也就是MD5摘要)。以下是它的运行示例:

OpenNMS哈希密码

OpenNMS哈希密码

虽然这个脚本的速度和成功率可能都不太理想。但是如果你使用的爆破字典较小或爆破对象使用的是弱密码,那么它将非常的有用。如果你懂得编程开发,你还可以将这个脚本移植到hashcat。

*参考来源:ropnop,FB小编 secist 编译,转载请注明来自FreeBuf.CO

2017-07-15 12:03 阅读:1070