1. 工具介绍
项目地址:
https://github.com/alex-sector/dns2tcp
原始项目地址找不到了,这里是别人从原始项目地址留存下来的。
使用场景
内网主机只开放了DNS相关端口,只允许DNS相关流量通讯,可通过DNS隧道进行端口数据转发。
2. 流量&逻辑分析
2.1. 环境&测试准备
环境配置
客户端 Ubantu Win10 192.168.2.129
服务端 Kali 192.168.2.139
测试方式
- Ubantu运行命令
dns2tcpc -r ssh -z dns2tcp.com 192.168.2.139 -l 8888 -d 9
其中dns2tcp.com在Ubantu上做了host解析绑定,绑定地址为192.168.2.139,尝试通过本地端口访问192.168.2.139的ssh服务
- Kali上运行dns2tcpd
dns2tcpd -f /etc/dns2tcpd.conf -F -d 9
相关配置如下:
- 在Ubantu上通过ssh连接本地8888端口
Ubantu上部分日志如下
Debug socket.c:233 Create socket for dns : '192.168.2.139'
Listening on port : 8888
When connected press enter at any time to dump the queue
Debug session.c:46 Request challenge
Debug requests.c:146 Sending dns id = 0x4331
Debug requests.c:95 Query is AAAAAAFdAA.=auth.dns2tcp.com len 28
No response from DNS 192.168.2.139
Debug session.c:46 Request challenge
Debug requests.c:146 Sending dns id = 0x3262
Debug requests.c:95 Query is AAAAAG+qAA.=auth.dns2tcp.com len 28
Debug queue.c:538 received reply for unknown request 0x4331
Debug rr.c:106 rr_decode_next_reply_encode base64 data was = 0n8AAG+qAE5VUURIRFFDSlJSQ0pMM0Y (reply len = 34)
Debug session.c:53 Challenge = 'NUQDHDQCJRRCJL3F'
11:23:07 : Debug session.c:54 Session created (0x7fd2)
Debug session.c:77 Sending response : '3F105EA88A806DC5D341DD2D47BF9A7D6F68CF40' (key = (null))
Debug requests.c:146 Sending dns id = 0x60da
Debug requests.c:95 Query is 0n+FgAABADNGMTA1RUE4OEE4MDZEQzVEMzQxREQyRDQ3QkY5QTdENkY2OENGNDA.=auth.dns2tcp.com len 81
Debug rr.c:106 rr_decode_next_reply_encode base64 data was = 0n+FgAABAA (reply len = 13)
11:23:07 : Debug auth.c:94 Connect to resource "ssh"
Debug requests.c:146 Sending dns id = 0x6518
Debug requests.c:95 Query is 0n/o79u5AHNzaA.=connect.dns2tcp.com len 35
Debug rr.c:106 rr_decode_next_reply_encode base64 data was = 0n/o79u5AA (reply len = 13)
11:23:07 : Debug client.c:141 Adding client auth OK: 0x7fd2
Debug queue.c:366 queue = 0x0x7f023e036010
Debug requests.c:285 Client 0x7fd2 : push data [1] ack [0] len = 0
Debug requests.c:146 Sending dns id = 0x72a7
Debug requests.c:95 Query is 0n8AAAABBA.dns2tcp.com len 22
Debug queue.c:366 queue = 0x0x7f023e036010
...
Kali上部分日志如下:
11:22:52 : Debug options.c:97 Add resource ssh:127.0.0.1 port 22
11:22:52 : Debug options.c:97 Add resource smtp:127.0.0.1 port 25
11:22:52 : Debug socket.c:54 Listening on 192.168.2.139:53 for domain dns2tcp.com
Starting Server v0.5.2...
11:22:52 : Debug main.c:134 Chroot to /tmp
03:23:07 : Debug main.c:144 Change to user nobody
Debug requests.c:167 Receive query : AAAAAAFdAA dns_id = 0x4331 for domain =auth.dns2tcp.com
Creating session id: 0x7b6e address = 192.168.2.129 (compression NOT wanted)
Debug rr.c:204 rr_get_reply_length_encode return 268
Debug requests.c:205 Sending [349] len = 92 dns id = 0x4331 bnsAAAFdAEoyOVkzV1FSQTY4VkVYM04
Debug requests.c:167 Receive query : AAAAAG+qAA dns_id = 0x3262 for domain =auth.dns2tcp.com
Creating session id: 0x7fd2 address = 192.168.2.129 (compression NOT wanted)
Debug rr.c:204 rr_get_reply_length_encode return 268
Debug requests.c:205 Sending [28586] len = 92 dns id = 0x3262 0n8AAG+qAE5VUURIRFFDSlJSQ0pMM0Y
Debug requests.c:167 Receive query : 0n+FgAABADNGMTA1RUE4OEE4MDZEQzVEMzQxREQyRDQ3QkY5QTdENkY2OENGNDA dns_id = 0x60da for domain =auth.dns2tcp.com
Debug rr.c:204 rr_get_reply_length_encode return 188
Debug requests.c:205 Sending [1] len = 124 dns id = 0x60da 0n+FgAABAA
Debug requests.c:167 Receive query : 0n/o79u5AHNzaA dns_id = 0x6518 for domain =connect.dns2tcp.com
03:23:07 : Debug auth.c:60 Ask for resource 'ssh'
03:23:07 : Debug socket.c:183 Connecting to 127.0.0.1 port 22
Bind client id: 0x7fd2 address = 192.168.2.129 to resource ssh
Debug rr.c:204 rr_get_reply_length_encode return 256
Debug requests.c:205 Sending [56249] len = 78 dns id = 0x6518 0n/o79u5AA
Debug requests.c:167 Receive query : 0n8AAAABBA dns_id = 0x72a7 for domain dns2tcp.com
Debug queue.c:642 Packet [1] decoded, data_len 0
Debug queue.c:653 diff = 0
Debug queue.c:407 Queue : dealing packet 1
Debug requests.c:167 Receive query : 0n8AAAACCFNTSC0yLjAtT3BlblNTSF84LjJwMSBVYnVudHUtNHVidW50dTAuOQ0K dns_id = 0x7b12 for domain dns2tcp.com
Debug queue.c:642 Packet [2] decoded, data_len 41
Debug queue.c:653 diff = 1
Debug queue.c:407 Queue : dealing packet 2
Debug queue.c:239 Flush Write 41 bytes, crc = 0x4121
...
2.2. 检测特征
抓取的部分流量特征如下:
源代码中client相关逻辑在client文件夹中,server相关逻辑在server中,目前主要检测逻辑和检测点在connect请求检测和connect成功检测
2.2.1. Client逻辑分析
通过上文的日志,可看到connect相关请求日志在19行,日志如下:
11:23:07 : Debug auth.c:94 Connect to resource "ssh"
定位到相关部分的代码:
其中create_simple_req方法可以简单的认为是对需要发送的输出做初始化和赋值操作,包括请求的的ack,seq,len,type等等其中有个需要注意的点是,这里已经对request->domain做了赋值,相关代码块如下
request->domain = domain;
#subdomain为=connect.
strcpy(request->domain, subdomain);
#config->domain这里为dns2tcp.com
strcat(request->domain, conf->domain);
#整体结果如下:=connect.dns2tcp.com
此外strncpy(resource, conf->resource, sizeof(request.req_data) - PACKET_LEN - 1),对request.req_data进行了赋值,其余过程中需要重点关注一下transceive_query方法,继续跟踪
transceive_query中需要关注send_query和get_simple_reply,一个是发送DNS请求一个是获取DNS请求响应,先看send_query方法:
先调用create_request构造请求数据,之后调用sendto方法(C中winsock.h自带),发送数据,继续看create_request的逻辑实现:
上面逻辑中需要重点关注data2qname方法,继续跟踪:
对request->req.data进行自定义的base64编码,然后再添加.和编码之后的值到create_simple_req的request.domain中,整体为base64(conf.resource).=connect.dns2tcp.com
2.2.2. Server逻辑分析
server端的connect大体逻辑和clienst类似,直接定位到connect_resource的相关方法:
搜索相关方法调用,发现在auth.c的95行中被调用:
通过大致分析,发现最后发送响应数据的方法为send_ascii_reply,继续跟踪
继续跟踪send_reply方法
相关实现如下:
分析发现响应的DNS的Header的flag是确定的,设置了相关的参数,对应flag为0x8580
响应中的requests.req_data为满足client请求要求的config.resource