美文网首页
dnscat2协议

dnscat2协议

作者: jinx1663 | 来源:发表于2018-08-12 11:19 被阅读0次

    简介

    本文描述dnscat2 协议

    我称之为dnscat2协议,尽管严格来讲,它不仅仅局限于dnscat或DNS。我需要一种逻辑连接协议,它可以在不确保可靠性且带宽被极度限制的多种底层连接、数据报之上建立。

    本协议是为dnscat设计的,采用轮询机制——客户端发送数据包,服务器作出回应,服务器无法知道是哪个客户端发送的数据包,也无法知道如何初始化一个连接,因此这些问题在dnscat2协议中都要考虑。

    本协议基于数据报,包含一个16bits的session_id, 可用于追踪多种底层链路之上的连接,并处理底层的丢包、重复和乱序问题。

    以下我会给出一些细节——我们需要什么来完成这些工作、连接如何工作的描述、消息中使用的常量和消息本身的结构

    挑战

    借助DNS协议很有挑战性!下面列举了一些问题:

    • 每个消息都需要某种类型的回复
    • 重传、丢包和乱序非常普遍
    • DNS数据包中只能包含数字和字母,不一定区分大小写

    DNS传输协议和dnscat协议都将这些考虑在内,不像其它DNS隧道协议,我不依赖于使用TCP传输层来保证可靠性——dnscat协议有能力在DNS协议之上建立原始连接。

    DNS运送协议

    dnscat协议是一个独立的协议,可以被应用在任何轮询协议之上,例如DNS、HTTP、ICMP/Ping等——我将这些协议都看作运送协议。在这些不同的协议之上需要将数据稍稍包装一下。本节主要介绍如何将DNS协议作为一个运送通道。

    编码

    所有的数据被编码成字符串的16进制表示,例如: "AAA" 变为"414141"

    域名中的所有点号都应被忽略,因此,"41.4141"、"414.141"和"414141"是完全一样的。

    除此之外,不区分大小写,因此"5b"和"5B"也是相同的。客户端和服务器都要处理大小写的不敏感性,因为有些软件会改变请求的大小写!

    发送/接收

    客户端可以选择是否扩展域名(用户必须有此域名的权威DNS服务器)或者加一个"dnscat."前缀,消息格式如下:

    <encoded data>.<domain>
    or
    
    <tag>.<encoded data>
    

    任何不符合上述形式的数据,或者是不支持的记录类型,或者dnscat服务器无法识别的扩展域名,服务器可以丢弃或者转发至上层DNS服务器。

    dnscat2服务器必须用正确格式的DNS应答报文回复,置位无错误位,并包含一个或多个answer。如果有多个answer,每个answer的每一个字节必须是一字节的序列号(中间DNS服务器很可能会改变记录的顺序)

    应答记录类型必须和请求记录类型一致,应答的具体的编码方式取决于记录类型。

    DNS记录类型

    dnscat服务器支持绝大多数DNS消息类型:TXT, MX, CNAME, A和AAAA,这些类型的请求消息都被封装为DNS记录,不同类型的应答报文格式稍有不同。

    TXT应答报文就是16进制编码的数据。理论上,TXT记录可以包含二进制数据,但是Windows DNS客户端会NULL字符截断,因此需要编码。

    CNAME和MX记录在请求时是相同编码的:都有一个tag前缀或者域名后缀。这是必要的,因为中间DNS服务器不会转发不正确的域名。MX记录类型在DNS中也有额外的区域——优先级区域,可以随机设置,客户端应该忽略。

    最后,A记录和AAAA记录,有点像TXT,就是原始数据,没有前缀后缀。但有两点补充:一是应答报文长度很短(A记录4B,AAAA记录16B),因此需要多个answer,不幸的是,DNS层次体系会
    重新排列answer, 因此每个记录必须包含一个字节的序号作为前缀,数值并不重要,只要可以排列得到原始的顺序即可。

    二是没有明确的方法可以获取应答报文的长度,因为应答报文实际上是分块的。因此,数据本身的长度也要用一个字节来存储,放在消息头部。如果消息结尾不够一个块的大小,需要填充。

    A记录应答报文格式:

    0.9.<byte1>.<byte2> 1.<byte3><byte4><byte5> 2.<byte6><byte7><byte8> 3.<byte9>.<pad>.<pad>
    

    0表示块序号, 9表示数据长度, 2和3表示块序号

    Errors

    如果server遇到错误,根据严重性会采取以下措施:

    • 可以忽略的错误(重复的SYN包),回复一个空消息;对于TXT/A/AAAA, 显然是不回复;对于CNAME/MX/NS,因为域名是必须的,所以只回复一个域名。
    • 致命错误(例如未处理的异常), 应该回复带有描述信息的FIN包。

    dnscat协议

    在上面我定义了一种DNS运送协议,这个协议解决了如何通过DNS报文传送数据。下面我正式介绍dnscat协议。

    dnscat 协议

    连接

    这里的"连接"指的是客户端和服务器之间的逻辑会话。一个连接以SYN包开始,之后包含若干个MSG包,最后以FIN包结束。每个连接用一个唯一的16bits的session_id标识,注意不要将SYN/FIN和tcp连接中的概念混淆,这里指的完全是dnscat中的概念。

    总结一下:客户端发送SYN包给server, server回复SYN包,这样一个连接就建立了。客户端发送MSG包给server, server回复MSG包。当客户端决定终止连接,客户端发送FIN,server回复之;当server决定终止连接,它使用FIN包回复来自客户端的MSG包,客户端不再回复。

    SYN包中的flags区域在client和server之间交换,这些flag影响整个会话过程。

    大部分情况下,意外的数据包会被忽略.

    client和server都允许处理多个会话,client经常和server同时展开多个会话;server则可以和不同的client同时展开会话。

    一个完整的连接过程如图:

    +----------------+
    | Client  Server |
    +----------------+
    |  SYN -->  |    |
    |   |       v    |
    |   |  <-- SYN   |
    |   v       |    |
    |  MSG -->  |    |
    |   |       v    |
    |   |  <-- MSG   |
    |   v       |    |
    |  MSG -->  |    |
    |   |       v    |
    |   |  <-- MSG   |
    |  ...     ...   |
    |  ...     ...   |
    |  ...     ...   |
    |   |       |    |
    |   v       |    |
    |  FIN -->  |    |
    |           v    |
    |      <-- FIN   |
    +----------------+
    

    server决定终止连接:

    +----------------+
    | Client  Server |
    +----------------+
    |  SYN -->  |    |
    |   |       v    |
    |   |  <-- SYN   |
    |   v       |    |
    |  MSG -->  |    |
    |   |       v    |
    |   |  <-- MSG   |
    |   v       |    |
    |  MSG -->  |    |
    |   |       v    |
    |   |  <-- FIN   |
    |   v            |
    | (nil)          |
    +----------------+
    

    收到意外的MSG,server回复FIN:

    +----------------+
    | Client  Server |
    +----------------+
    |  MSG -->  |    |
    |   |       v    |
    |   |  <-- FIN   |
    |   v            |
    | (nil)          |
    +----------------+
    

    server收到意外的FIN,忽略之。

    +----------------+
    | Client  Server |
    +----------------+
    |  FIN -->  |    |
    |           v    |
    |         (nil)  |
    +----------------+
    

    SEQ/ACK号

    SEQ(sequence 序列)和ACK(acknowledgement确认)号和TCP中的概念十分相似。在连接初始阶段,client和server都选择一个随机的ISN(initial sequence number初始序列号),并发送给对方。

    client的SEQ号就是server的ACK号,反之亦然。这样双方都知道下一个应收到的序号是多少。

    在一个会话过程中,双方会相互发送数据,当更多的数据排队等待发送,想像你正在将这些数据移动到已发送数据列表中,当消息发送出去之后,系统应当注意自己的序列号和字符队列来决定应该发送什么。如果有还未被对方确认的数据在等待,这些数据应该被重传,直到和当前的序列号匹配。

    当收到消息后,接收方必须将消息中的序列号和自己的确认号进行对比,如果序列号比确认号小,说明收到的是重复数据,ACK可能丢失了,没有被对方收到,必须重新发送ACK。如果序列号比确认号大,数据应该被缓存或是悄悄丢弃(当对方发送多个数据包进行测速时),如果相等,则进一步处理。

    当消息进一步处理时,接收方根据收到的字节数增加ACK号,并将新的ACK、SEQ和等待的数据发送出去。

    当发送方收到对方的ACK,会增加自己的SEQ,从新的SEQ处开发发送数据。

    你要知道双方都会持续确认对方发送的数据(通过增加对方的SEQ号),同时发送自己的数据并更新自己的SEQ(通过对方的ACK)

    命令协议

    在dnscat协议之上有一个称为命令协议的协议。如果在SYN头部设置了OPT_COMMAND位,所有的消息都会被当作命令消息,必须遵循命令协议。

    关于命令协议的详细信息请查看command_protocol.md.

    加密/签名

    待完成

    常量

    /* Message types */
    #define MESSAGE_TYPE_SYN    (0x00)
    #define MESSAGE_TYPE_MSG    (0x01)
    #define MESSAGE_TYPE_FIN    (0x02)
    #define MESSAGE_TYPE_ENC    (0x03)
    #define MESSAGE_TYPE_PING   (0xFF)
    
    /* Encryption subtypes */
    #define ENC_SUBTYPE_INIT    (0x00)
    #define ENC_SUBTYPE_AUTH    (0x01)
    
    /* Options */
    #define OPT_NAME            (0x01)
    #define OPT_COMMAND         (0x20)
    
    

    Messages

    本节解释了如何为消息类型编码,所有的区域采用大端编码方式,整个数据包通过DNS运送协议传送。运送协议负责处理数据包大小,数据包大小是已知的。

    所有的消息包含一个16位的packet_id, 每个packet_id应该不同,这是为了缓存而设置的。

    数据类型

    正如上面提到的,所有的区域大端编码(网络字节序)。以下数据类型被用到:

    • uint8_t - an 8-bit (one-byte) value
    • uint16_t - a 16-bit (two-byte) value
    • uint32_t - a 32-bit (four-byte) value
    • uint64_t - a 64-bit (eight-byte) value
    • ntstring - a null-terminated string (that is, a series of bytes with a NUL byte ("\0") at the end
    • byte[] - an array of bytes - if no size is specified, then it's the rest of the packet

    MESSAGE_TYPE_SYN [0x00]

    • (uint16_t) packet_id
    • (uint8_t) message_type [0x00]
    • (uint16_t) session_id
    • (uint16_t) initial sequence number
    • (uint16_t) options
    • If OPT_NAME is set: (ntstring) 7.
    Notes
    • 每个连接的初始化,都是通过一个客户端发送SYN开始,包含一个随机的session_id和随机的初始化序列号,以及请求选项。

    • 以下选项被定义:

      • OPT_NAME - 0X01[C->S]

        • 数据包包含一个额外的区域:session名,一个自由区域,可以包含可读数据
      • OPT_COMMAND - 0X20[C->S]

        • 命令会话,表示是一个命令隧道消息
      • OPT_ENCRYPTED - 0x40 [C-<S and S->C]

        • 协商加密方式
        • crypto_flags 未定义,为0
        • 公钥x和y为大数,直接转为16进制值,左侧填充0
    • 服务器回复SYN,包含初始序列号和选项

      • 如果客户端请求中包含OPT_ENCRYPTED,服务员也必须包含
    • session_id和初始号必须随机化,使得连接劫持攻击更加困难(两个序列号和session_id每个连接给我们大约48bits的熵)

    • packet_id对每个packet来说都应该不同,完全是为了阻止缓存。可以是递增的,双方都应该忽略这个值。

    • 如果服务器收到多个完全相同的SYN,则每个都要回复。

    • 如果服务器收到了有相同session_id的不同SYN,应该忽略。

    错误状态
    • 如果客户端没有收到SYN应答,意味着请求包或者应答包丢失了,客户端可以选择重传或者生成新的SYN包或会话。

    • 如果客户端在收到MSG消息之前收到第二个相同session的SYN,需要当作有效来回复。

      • 有效意味着包含相同选项、序列号、相同名称、相同密钥。
    • 如果客户端和服务器在建立连接时收到SYN,应该丢弃。

    MESSAGE_TYPE_MSG: [0x01]

    • (uint16_t) packet_id
    • (uint8_t) message_type [0x01]
    • (uint16_t) session_id
    • (uint16_t) seq
    • (uint16_t) ack
    • (byte[]) data
    Notes

    如果SYN包含OPT_COMMAND,数据区域使用命令协议

    MESSAGE_TYPE_FIN: [0x02]

    • (uint16_t) packet_id
    • (uint8_t) message_type [0x02]
    • (uint16_t) session_id
    • (ntstring) reason
    Notes

    一旦FIN发送,client or server就不太回应任何消息。

    MESSAGE_TYPE_ENC: [0x03]

    • (uint16_t) packet_id
    • (uint8_t) message_type [0x03]
    • (uint16_t) session_id
    • (uint16_t) subtype
    • (uint16_t) flags
    • If subtype is ENC_SUBTYPE_INIT:
      • (byte[32]) public_key_x
      • (byte[32]) public_key_y
    • If subtype is ENC_SUBTYPE_AUTH:
      • (byte[32]) authenticator
    Notes
    • 如果要使用加密连接,客户端应该立即发送ENC|INIT数据包
    • 服务器必须用包含相同子类型的ENC包回复ENC请求
      • 如果客户端选择加密,服务器也必须加密;客户端选择认证,服务器也必须认证。
    • 服务器必须用相同的密钥回复ENC|INIT包
    • 公钥和认证器编码为32字节的16进制字符串,左侧填充0

    下面的Ruby代码用于转换整数到字符串:

    [bn.to_s(16).rjust(32*2, "\0")].pack("H*")
    

    反之:

    [bn.to_s(16).rjust(32*2, "\0")].pack("H*")
    

    MESSAGE_TYPE_PING: [0xFF]

    • (uint16_t) packet_id
    • (uint8_t) message_type [0xFF]
    • (uint16_t) ping_id
    • (ntstring) data

    Notes

    ping_id应该和请求一致

    相关文章

      网友评论

          本文标题:dnscat2协议

          本文链接:https://www.haomeiwen.com/subject/rzmqbftx.html