Net- NTLM 利用

1.简介

上篇文章中,主要简单的介绍了一下基本的概念,纠正了一下网络上现有文章存在的一些问题,接下来,我们来正视该体系下存在的问题。

2.会话签名 和 身份验证签名(MIC)

在详细说明该体系下存在的问题之前,我们先补充一个概念。
细心的同学们可能会注意到,在上篇文章中的ntml协议的数据包中少了点什么,具体少了什么呢?没错,就是MIC。


image-20220210133638849.png

那么MIC具有什么作用呢?
MIC 保护了 NTLM 不会被修改。什么意思呢?
NTLM身份验证由3种消息类型组成:NTLM_NEGOTIATE,NTLM_CHALLENGE,NTLM_AUTHENTICATE。为了确保恶意行为者不在传输过程中处理消息,在NTLM_AUTHENTICATE消息中添加了一个额外的MIC(消息完整性代码)字段。MIC是使用会话密钥应用于所有3个NTLM消息的串联的HMAC_MD5,该会话密钥仅对启动认证的帐户和目标服务器是已知的。因此,试图篡改其中一条消息的攻击者(例如,修改签名协商)将无法生成相应的MIC,这将导致攻击失败。
翻译一下就是:会话签名决定了验证通过后,通讯会话是否需要加密。若通讯加密,因为无法获得加密的密钥,则无法完成后面的中间人攻击。
具体在认证过程中,数据包中是通过哪些字段来确认是否需要签名呢?
这里我总结了一下:

  1. 在谈判阶段,双方都表明他们的要求:其中之一是否需要签名?
  2. 在身份验证阶段,双方都表明他们支持什么。是否有签名能力?
  3. 在会话阶段,如果功能和要求兼容,则使用已协商的内容进行会话。
    在 NTLM 协商阶段,NEGOTIATE_SIGN 若为 1 则表示有签名能力(但不是一定要签名)。


    image-20220210134204701.png

    是否要启用签名主要取决于两个标志位 Signing enabled 和 Signing required
    Signing enabled 表示是否支持签名
    Signing required 表示是否需要签名
    不同协议判定是否需要签名的条件也不同
    ● SMB:双方有一方的 Signing required 为 1 时,启用签名。也就是如果有一方明确表示了 需要签名 才会被启用。windows PC默认是不需要签名的,只有 server 版本默认需要签名(域控 2012 碰到过不开签名的情况,判断 SMB 是否需要签名,发送一次请求即可判断)。
    ● LDAP:协商签名,双方都支持签名则使用签名。这就是为啥在中继的时候不能从 SMB 中继到 LDAP 的原因。SMB 默认支持签名, 也就是 Signing enabled 字段默认为 1。从 SMB 到 LDAP 会触发 LDAP 签名导致中间人失败。
    ● HTTP:不支持签名。所以 可以从 HTTP 中继 LDAP 完成攻击。server2019 默认域控强制开启 LDAP 签名,让 HTTP 无法再中继到 LDAP,但是仍然可以中继到 LDAPS。

3.相关安全问题

3.1.PTH

pass the hash也叫做hash传递攻击,简称:PTH
根据前一篇文章我们知道,在type3计算response的时候,客户端是使用用户的hash进行计算的,而不是用户密码进行计算的。因此在模拟用户登录的时候。是不需要用户明文密码的,只需要用户hash。
Ps:在此不对pth的工具进行一一展示使用,后续会补上(挖坑),工具根本原理相同,不同的只是使用方法,这里仅选择一款展示效果
pth的效果:


image-20220210140107865.png

说到PTH,就不得不提kb2871997这款补丁了,kb2871997这款补丁仅能暂缓pth,并不能杜绝pth。至于为什么,这里暂不讨论,后续补上(挖坑)

3.2.利用ntlm进行的信息收集

渗透测试的深度取决于信息收集的广度,那么,在打点阶段或者内网渗透阶段,能够有效获取目标主机的信息,就为拿下目标多一层可能。
这里直接看到type2阶段数据包:


image-20220210140901182.png

在type2返回Challenge的过程中,同时返回了操作系统类型,主机名,netbios名等等。这也就意味着如果我们在能跟服务器进行ntlm 交流中,给服务器发送一个type1的请求,服务器返回type2的响应,这一步,我们就可以得到很多信息。

前面我们说过ntlm是一个嵌入式的协议,消息的传输依赖于使用ntlm的上层协议,比如SMB,LDAP,HTTP等。我们以SMB为例。在目标主机开放了445或者139的情况,通过给服务器发送一个type1的请求,然后解析type2的响应。就可以收集到一些信息。

这里直接贴一下网上找到的大牛的代码

using System;
using System.Data;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime;
using System.Runtime.InteropServices;
namespace Zcg.Tests
{
    class smbver
    {
        static byte[] d1 ={
    0x00, 0x00, 0x00, 0x85, 0xFF, 0x53, 0x4D, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x53, 0xC8, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x02, 0x50, 0x43, 0x20, 0x4E, 0x45, 0x54, 0x57, 0x4F, 
    0x52, 0x4B, 0x20, 0x50, 0x52, 0x4F, 0x47, 0x52, 0x41, 0x4D, 0x20, 0x31, 0x2E, 0x30, 0x00, 0x02, 
    0x4C, 0x41, 0x4E, 0x4D, 0x41, 0x4E, 0x31, 0x2E, 0x30, 0x00, 0x02, 0x57, 0x69, 0x6E, 0x64, 0x6F, 
    0x77, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x57, 0x6F, 0x72, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x70, 
    0x73, 0x20, 0x33, 0x2E, 0x31, 0x61, 0x00, 0x02, 0x4C, 0x4D, 0x31, 0x2E, 0x32, 0x58, 0x30, 0x30, 
    0x32, 0x00, 0x02, 0x4C, 0x41, 0x4E, 0x4D, 0x41, 0x4E, 0x32, 0x2E, 0x31, 0x00, 0x02, 0x4E, 0x54, 
    0x20, 0x4C, 0x4D, 0x20, 0x30, 0x2E, 0x31, 0x32, 0x00
};
        static byte[] d2 ={
    0x00, 0x00, 0x01, 0x0A, 0xFF, 0x53, 0x4D, 0x42, 0x73, 0x00, 0x00, 0x00, 0x00, 0x18, 0x07, 0xC8, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 
    0x00, 0x00, 0x40, 0x00, 0x0C, 0xFF, 0x00, 0x0A, 0x01, 0x04, 0x41, 0x32, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0x00, 0x00, 0xA0, 0xCF, 0x00, 0x60, 
    0x48, 0x06, 0x06, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x02, 0xA0, 0x3E, 0x30, 0x3C, 0xA0, 0x0E, 0x30, 
    0x0C, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0A, 0xA2, 0x2A, 0x04, 
    0x28, 0x4E, 0x54, 0x4C, 0x4D, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x82, 0x08, 
    0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x05, 0x02, 0xCE, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6E, 0x00, 
    0x64, 0x00, 0x6F, 0x00, 0x77, 0x00, 0x73, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 
    0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 
    0x20, 0x00, 0x33, 0x00, 0x37, 0x00, 0x39, 0x00, 0x30, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00, 
    0x72, 0x00, 0x76, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x50, 0x00, 0x61, 0x00, 
    0x63, 0x00, 0x6B, 0x00, 0x20, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x69, 0x00, 
    0x6E, 0x00, 0x64, 0x00, 0x6F, 0x00, 0x77, 0x00, 0x73, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00, 
    0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 
    0x33, 0x00, 0x20, 0x00, 0x35, 0x00, 0x2E, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00
};
static byte[] d3={
0x81,0x00,0x00,0x44,0x20,0x43,0x4b,0x46,0x44,0x45,0x4e,0x45,0x43,0x46,0x44,0x45
,0x46,0x46,0x43,0x46,0x47,0x45,0x46,0x46,0x43,0x43,0x41,0x43,0x41,0x43,0x41,0x43
,0x41,0x43,0x41,0x43,0x41,0x00,0x20,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43
,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43,0x41,0x43
,0x41,0x43,0x41,0x43,0x41,0x41,0x41,0x00
};
        static void Main(string[] args)
        {
            Console.WriteLine("SMB Version Detection tool 0.1");
            Console.WriteLine("Part of GMH's fuck Tools, Code By zcgonvh.\r\n");
            if (args.Length < 1) { Console.WriteLine("usage: smbver host [port]"); return; }
            string host = args[0];
            int port = 445;
            try { port = int.Parse(args[1]); }
            catch { }
            try
            {
                byte[] buf = new byte[1024];
                Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                sock.Connect(host, port);
                if(port==139)
                {
                  sock.Send(d3);
                  sock.Receive(buf);
                }
                sock.Send(d1);
                sock.Receive(buf);
                sock.Send(d2);
                sock.Receive(buf);
                int len = BitConverter.ToInt16(buf, 43);
                string[] ss = Encoding.Unicode.GetString(buf, len + 47, buf.Length - len - 47).Split('\0');
                Console.WriteLine("native os: " + ss[0]);
                Console.WriteLine("native lan manager: " + ss[1]);
                int off = 0;
                for (int i = 47; i < len - 7; i++)
                {
                    if (buf[i] == 'N' && buf[i + 1] == 'T' && buf[i + 2] == 'L' && buf[i + 3] == 'M' && buf[i + 4] == 'S' && buf[i + 5] == 'S' && buf[i + 6] == 'P') { off = i; break; }
                }
                byte[] ntlm = new byte[len];
                Array.Copy(buf, off, ntlm, 0, len);
                len = BitConverter.ToInt16(ntlm, 0xc);
                off = BitConverter.ToInt16(ntlm, 0x10);
                Console.WriteLine("negotiate target: " + Encoding.Unicode.GetString(ntlm, off, len));
                Console.WriteLine("os major version: " + ntlm[off - 8]);
                Console.WriteLine("os minor version: " + ntlm[off - 7]);
                Console.WriteLine("os build number: " + BitConverter.ToInt16(ntlm, off - 6));
                Console.WriteLine("ntlm current revision: " + ntlm[off - 1]);
                off += len;
                int type = BitConverter.ToInt16(ntlm, off);
                while (type != 0)
                {
                    off += 2;
                    len = BitConverter.ToInt16(ntlm, off);
                    off += 2;
                    switch (type)
                    {
                        case 1:
                            {
                                Console.WriteLine("NetBIOS computer name: " + Encoding.Unicode.GetString(ntlm, off, len));
                                break;
                            }
                        case 2:
                            {
                                Console.WriteLine("NetBIOS domain name: " + Encoding.Unicode.GetString(ntlm, off, len));
                                break;
                            }
                        case 3:
                            {
                                Console.WriteLine("DNS computer name: " + Encoding.Unicode.GetString(ntlm, off, len));
                                break;
                            }
                        case 4:
                            {
                                Console.WriteLine("DNS domain name: " + Encoding.Unicode.GetString(ntlm, off, len));
                                break;
                            }
                        case 5:
                            {
                                Console.WriteLine("DNS tree name: " + Encoding.Unicode.GetString(ntlm, off, len));
                                break;
                            }
                        case 7:
                            {
                                Console.WriteLine("time stamp: {0:o}", DateTime.FromFileTime(BitConverter.ToInt64(ntlm, off)));
                                break;
                            }
                        default:
                            {
                                Console.Write("Unknown type {0}, data: ", type);
                                for (int i = 0; i < len; i++)
                                {
                                    Console.Write(ntlm[i + off].ToString("X2"));
                                }
                                Console.WriteLine();
                                break;
                            }
                    }
                    off += len;
                    type = BitConverter.ToInt16(ntlm, off);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("err: " + ex);
            }
        }
    }
}

大家也可以仿造代码的形式,自己实现其他上层协议下的信息收集。
网图效果如下:

image-20220210141930430.png

msf底下也有类似的模块auxiliary/scanner/smb/smb_version
image-20220210142549383.png

3.3.ntlm relay

作为一个在上世纪就被提出的安全问题,时至2022的今天,ntlm_relay仍然在远程命令执行。横向扩展,权限提升等方面发挥着巨大的作用。本篇文章剩余部门简单的介绍一些ntlm_relay相关的概念。
工具流程如下:

image-20220210143221495.png

看图已经能够很清晰得理解ntlm_relay的一般过程,作为中间人,攻击者将来自客户端的包(type 1)转发给服务端,将来自服务端的challenge(type 2)转发给客户端,然后客户端计算完response 之后,再把response(type 3) 转发给服务端,服务端验证rsponse通过之后,授予攻击者访问的权限。
局限性:
中继的前提是目标 SMB 签名需要关闭,在 SMB 协议中,需要使用安全机制来保护服务器和客户端之间传输数据的完整性,而这种安全机制就是 SMB 签名和加密,如果关闭 SMB 签名,会允许攻击者拦截认证过程,并且将获得 hash 在其他机器上进行重放,从而获得权限。在工作组环境里面,工作组中的机器之间相互没有信任关系,每台机器的账号密码 Hash 只是保存在自己的 SAM 文件中,这个时候 Relay 到别的机器,除非两台机器的账号密码一样,不然没有别的意义了。
扩展:
由于NTLM协议为嵌入式协议,中继的方式并不局限于SMBtoSMB,也可以HTTPtoSMB,还有一个需要注意的地方就是,不同协议之间的特性,例如上面提到的SMB签名问题,又例如LDAP签名问题。
攻击效果:
image-20220211093313625.png

本次攻击实验利用Inveigh做了一个局域网投毒+中继操作,(局域网投毒还涉及几个协议,这里放到下一篇来讲(挖坑))通过Inveigh监听中间人地址,当被投毒计算机进行某些操作时(可以发起NTLM请求的操作),就会直接将请求发送到中间人,中间人将请求再原封不动的发送给被中继机器。

Ps:局域网环境下,该操作其实并不常用,域环境下会遇到

4.总结

以上部分是针对局域网下的一些常用手法,也简单介绍了一下这些手法下的局限性,下一篇将讲讲本次未涉及的一些其他协议。不可去名上理会。须求其所以然。

©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容