Windows内网协议学习NTLM篇之Net-NTLM利用

 

作者:daiker@360RedTeam

0x00 前言

在上一篇文章Windows内网协议学习NTLM篇之发起NTLM请求里面,讲了12种发起NTLM请求的方式。这篇文章接着上文,主要讲解拿到NTLM 请求之后的进一步利用。有Net-NTLM Hash的破解(v1 和 v2)以及Relay到支持NTLM SSP的协议,事实上,只要是支持NTLM SSP的协议,都可以Relay过去,本文主要讲的是几种比较常遇到,且能达到命令执行效果的,SMB,EWS,LDAP。

 

0x01 Net-NTLM Hash的破解

1. Net-NTLM v1 的破解

先上结论。只要获取到Net-NTLM v1,都能破解为NTLM hash。与密码强度无关。

具体操作如下。

  1. 修改Responder.conf里面的Challenge为1122334455667788(使用SpiderLabs版本的 话默认是1122334455667788,但该版本已经停止更新了,建议使用lgandx版本,这一版本默认为Random,需要修改)

  1. 将type2里面的NTLMSSPNEGOTIATEEXTENDED_SESSIONSECURITY位置0。

如果知道发来的请求一定是SMB 协议的话,Responder里面加上–lm参数即可,

其他协议就得去找改协议发送type2 处的代码,修改NegoFlags位。

比如Http协议的话,需要修改packets.py里面的NTLM_Challenge类。

原来是NegoFlags的值是\x05\x02\x89\xa2,改成\x05\x02\x81\xa2

  1. 然后获取到Net-NTLM v1。再使用ntlmv1-multi里面的ntlmv1.py转换.

获取到Net-NTLM v1是win10::WIN10-1:F1586DA184365E9431C22EF206F5A2C918659E1B1FD7F64D:F1586DA184365E9431C22EF206F5A2C918659E1B1FD7F64D:1122334455667788

转化完的格式就是NTHASH:F1586DA184365E9431C22EF206F5A2C918659E1B1FD7F64D

  1. 再将转化完的格式用crack.sh破解即可。

 

下面简要探究下原理,如果没有兴趣的可以直接跳过。看下一小节。

之前在NTLM基础介绍里面有简单介绍了下Net-NTLM v1的加密方式

将 16字节的NTLM hash空填充为21个字节,然后分成三组,每组7字节,作为3DES加密算法的三组密钥,加密Server发来的Challenge。 将这三个密文值连接起来得到response。

但是在实践中发现,加密方式的表述是有点问题的,或者说是不完整的。上面的只是Net-NTLM v1的一种加密方式,Net-NTLM v1还有另外一种加密方式。我们下面来探讨下这两种加密方式以及利用

(1)加密方式1

就是前面提到的那种。

  1. 将 16字节的NTLM hash空填充为21个字节,然后分成三组,每组7字节
  2. 将三组(每组7字节)经过运算后作为DES加密算法的密钥

运算的细节是每组七个字节再转化为8小组,每个小组7个比特位。然后7个比特位进行奇偶校验后算出第8个比特位,刚好是1个字节,8个小组,每小组一个字节,凑成8个字节的密钥。

  1. 加密Server Challenge
  2. 将这三个密文值连接起来得到response。

在Responder如果想获取到这种加密方式的话,要加上参数–lm(仅限于smb 协议)

那这种加密方式存在什么问题呢。

总共三组,每组8个字节作为key,加密Server Challenge获取response。

每组可以分开计算,已知加密内容和加密后的密文算key。使用des算法,key是八个字节。

我们控制Server Challenge为1122334455667788,然后建立从key到response的彩虹表。就可以在知道response的情况下获取key。所幸crack.sh这个网站已经帮我们弄好了,在Challenge为1122334455667788的情况下。一分钟之内就能获取ntlm hash,而且是免费的。这也是我们为啥要把Challenge设置为1122334455667788,而不是随机。

具体操作是

使用ntlmv1-multi里面的ntlmv1.py转换.然后复制NTHASH:E0F8C5B5E45247B4175698B99DBB5557CCD9241EA5A55CFB到crack.sh破解,填上邮箱,等到一分钟左右就能收到ntlm hash了。

(2)加密方式2

跟第一种加密方式基本一样。最本质的区别就在于,第一种加密方式的加密内容是Server Challenge。而这种加密方式是拼接8字节Server Challenge和8字节Client Challenge后,求其MD5,然后取MD5值的前8字节做为加密内容。

我们可以控制Server Challenge为固定的值,但是没法控制Client Challenge的值。也就是说我们没法控制加密的内容为固定的值。

第一种是加密的内容为固定的1122334455667788的话,我们只需要建立从key到response的映射就行。而这种加密方式的话。加密的内容也是不固定的,计算的成本高多了。

在Responder默认获取到的就是这种加密方式(没有加–lm)

使用ntlmv1-multi里面的ntlmv1-ssp.py转换.

crack.sh破解。这种方式要钱的,而且还不一定能解的出来。

总而言之,这种加密方式不好破解,其实我们也可以不让客户端不用这种加密方式,就使用第一种加密方式。且看下面的分析。

在我们的Responder加上–lm的情况下获取到的Net-NTLM v1 hash是采用第一种加密方式,但是只针对smb协议有效,在我的测试中,即使加了–lm参数,收到的请求是Http协议的情况底下,拿到的Net-NTLM v1也是采用第二种加密方式,我们不好破解。所以我又去研究了下什么情况底下采用第一种加密方式,什么情况底下采用第二种加密方式。

在这篇文章里面有提及到,当ntlm的flag位NTLMSSPNEGOTIATEEXTENDED_SESSIONSECURITY置为1的情况底下,会采用第二种加密方式,否则就会采用第一种加密方式,我们可以看下impacket里面计算Net-NTLM v1的相关代码

可以很清楚的看到,当NTLMSSPNEGOTIATEEXTENDED_SESSIONSECURITY位置为1的时候,加密的内容不是server challenge,而是md5 hash 运算过的server challeng+client challent的前8位。也就是说是第二种加密方式。

那NTLMSSPNEGOTIATEEXTENDEDSESSIONSECURITY flag来自于哪里呢。我们知道ntlm分为type1,type2,type3。计算response就在type 3里面,NTLMSSPNEGOTIATEEXTENDEDSESSIONSECURITY flag位就来自于type2。而type 2 里面的内容正常就是我们返回给客户端的。

也就是说,客户端选择加密方式1还是加密方式2,这个是由我们可以控制的。只需要我们把NTLMSSPNEGOTIATEEXTENDED_SESSIONSECURITY位置为0,那么客户端就会选择加密方式1.并且Server Challenge为1122334455667788的情况下。我们用crack.sh快速免费有效得破解。获取到用户的NTLM Hash。

那怎么将NTLMSSPNEGOTIATEEXTENDEDSESSIONSECURITY位置为0,我们一般都是使用现成的工具Resonder来获取Net-NTLM Hash。之前说过加上–lm参数就可以将NTLMSSPNEGOTIATEEXTENDEDSESSIONSECURITY位置为0。

这个时候还有一个小问题没有解决,那就是Resonder加上–lm,为什么只针对smb 协议有效。其他协议无效。

我去读了下Responder的代码。

加上–lm参数之后,调用的模块就是SMB1LM

发现她用的是老板本的smb实现。而这个版本的实现是在smb 协商版本的时候就将challenge返回,并且将NTLMSSPNEGOTIATEEXTENDED_SESSIONSECURITY置为0.

而且也仅仅是实现了smb协议,并没有实现其他协议。

但是完全可以不用老板本的smb实现。这里面最本质的地方在于NTLMSSPNEGOTIATEEXTENDED_SESSIONSECURITY置为0.而这个flag位并不一定需要用到旧版本的smb才能置位。只需要修改NTLM SSP里面的flag位就行

在各个协议里面的NTLM SSP里面,修改flag位,我们找到Responder里面type2的NTLM SSP的flag位赋值的地方即可。

Responder里面的NTLM SSP实现没有通用性。比如smb部分的实现,在packets.py里面的SMBSession1Data类里面。

默认是0xe2898215(跟图里面不一样?大端小端)

NTLMSSPNEGOTIATEEXTENDED_SESSIONSECURITY对应的是第13位,改为0,也就是0xe2818215

改下就行

http的话在packets.py里面的NTLM_Challenge类里面

Responder的NTLM SSP没有通用性,这个挺难受的,其他协议的话,大家自己找吧。跟下代码挺快的。

2. Net-NTLM v2的破解

Net-NTLM v2 现在也没有什么比较好用的破解方式,一般就是利用hashcat 离线爆破明文密码,能不能跑出来就看字典里面有没有了。

使用hashcat进行字典破解

hashcat -m 5600  win10::TEST:1122334455667788:622DED0816CFF5A0652209F20A7CF17A:0101000000000000C0653150DE09D201532C07A7DEE654B8000000000200080053004D004200330001001E00570049004E002D00500052004800340039003200520051004100460056000400140053004D00420033002E006C006F00630061006C0003003400570049004E002D00500052004800340039003200520051004100460056002E0053004D00420033002E006C006F00630061006C000500140053004D00420033002E006C006F00630061006C0007000800C0653150DE09D2010600040002000000080030003000000000000000010000000020000067840C88904F15E659858A3CBA35EBEF61A38EC88C5E3D26B968F1C20C9ACAC10A001000000000000000000000000000000000000900220063006900660073002F003100370032002E00310036002E003100300030002E0031000000000000000000 /tmp/password.dic --force

 

0x02 Relay

在Net-NTLM Hash的破解里面,如果是v1的话,拿到Net-NTLM就相当于拿NTLM HASH.这个时候就没有Relay的必要性了,但是在实际中遇到的例子往往不会是v1,而是v2。这个时候密码强度高一点,基本就跑不出来了,这种情况底下,不妨试一试Relay。

1. Relay2SMB

能直接relay到smb服务器,是最直接最有效的方法。可以直接控制该服务器(包括但不限于在远程服务器上执行命令,上传exe到远程命令上执行,dump 服务器的用户hash等等等等)。

主要有两种场景

  1. 工作组环境

这个实用性比较差。在工作组环境里面,工作组中的机器之间相互没有信任关系,每台机器的账号密码Hash只是保存在自己的SAM文件中,这个时候Relay到别的机器,除非两台机器的账号密码一样(如果账号密码一样,我为啥不直接pth呢),不然没有别的意义了,这个时候的攻击手段就是将机器reflect回机子本身。因此微软在ms08-068中对smb reflect到smb 做了限制。这个补丁在CVE-2019-1384(Ghost Potato)被绕过。将在下篇文章里面详细讲。

  1. 域环境

域环境底下域用户的账号密码Hash保存在域控的 ntds.dit里面。如下没有限制域用户登录到某台机子,那就可以将该域用户Relay到别人的机子,或者是拿到域控的请求,将域控Relay到普通的机子,比如域管运维所在的机子。(为啥不Relay到其他域控,因为域内就域控默认开启smb签名)

下面演示使用几款工具在域环境底下,从域控relay到普通机器执行命令

  1. impacket 的底下的smbrelayx.py

  1. impacket 的底下的ntlmrelayx.py

  1. Responder底下的MultiRelay.py

2. Relay2EWS

Exchange的认证也是支持NTLM SSP的。我们可以relay的Exchange,从而收发邮件,代理等等。在使用outlook的情况下还可以通过homepage或者下发规则达到命令执行的效果。而且这种Relay还有一种好处,将Exchange开放在外网的公司并不在少数,我们可以在外网发起relay,而不需要在内网,这是最刺激的。

下面演示通过NtlmRelayToEWS(事实上,工具挺多的。其他的大家可以上github自己找)来实现Relay2ews

配合homepage 能够实现命令执行的效果

homepage的简易demo代码如下

<html>
<head>
<meta http-equiv="Content-Language" content="en-us">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Outlook</title>
<script id=clientEventHandlersVBS language=vbscript>
<!--
Sub window_onload()
Set Application = ViewCtl1.OutlookApplication
Set cmd = Application.CreateObject("Wscript.Shell")
cmd.Run("calc")
End Sub
-->

</script>
</head>

<body>
<object classid="clsid:0006F063-0000-0000-C000-000000000046" id="ViewCtl1" data="" width="100%" height="100%"></object>
</body>
</html>

放置于web服务器。在NtlmRelayToEWS 里面通过-u 参数指定。

3. Relay2LDAP

不管是杀伤力巨大的8581还是1040。Relay到ldap都在里面发挥着巨大的作用。

relay 到ldap的话,能干嘛呢

这里着重介绍三种通用性比较强的利用思路。这三种在impacket里面的ntlmrelayx都有实现。(这三种通用性比较强而已,实际中这个的利用比较灵活,需要通过 nTSecurityDescriptor分析用户在域内对哪些acl有权限,什么权限。关于acl怎么深入利用,这里不再展开,后面在ldap篇会详细说明)

  1. 高权限用户

如果NTLM发起用户在以下用户组

  • Enterprise admins
  • Domain admins
  • Built-in Administrators
  • Backup operators
  • Account operators

那么就可以将任意用户拉进该组,从而使该用户称为高权限用户,比如域管

  1. write-acl 权限

如果发起者对域有write-acl 权限,那么就可以在域内添加两台acl

'DS-Replication-Get-Changes'     = 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2
'DS-Replication-Get-Changes-All' = 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2

acl的受托人可以是任意用户,从而使得该用户可以具备dcsync的权限

这个案例的典型例子就是Exchange Windows Permissions组,我们将在下一篇介绍8581的 时候详细说下这个用户组的权限。

  1. 普通用户权限

在server2012r2之后,如果没有以上两个权限。可以通过设置基于资源的约束委派。

在NTLM发起者属性msDS-AllowedToActOnBehalfOfOtherIdentity里面添加一条ace,可以让任何机器用户和服务用户可以控制该用户(NTLM发起者)。

 

0x03 引用

LM-Hash、NTLM-Hash、Net-NTLMv1、Net-NTLMv2详解

The NTLM Authentication Protocol and Security Support Provider

(完)