DNS Shell初体验
*本文原创作者:ArkTeam 楚子航,本文属FreeBuf原创奖励计划,未经许可禁止转载
背景介绍
我们遇到过各种各样的 Shell,从协议上来看,最开始基于 TCP、UDP 的 Shell,到后来基于ICMP 的 Shell 。从依托工具上看,有 nc 反弹、telnet 反弹、SSH 端口转发等手段,极度猥琐的甚至还有利用 awk 的反弹 Shell。从语言上看,各种流行的语言都能用来写后门,从bash 到 3P(Perl Python PHP)再到 Ruby 和 Java ,大牛总是可以根据不同的环境情况选择不同的 Shell 来利用。
各种 Shell 都有它自己的优点和缺点,采用 TCP 和 UDP 的虽然功能强大,但是却受到了防火墙和杀毒软件的严格监控,Ruby 和 Java 写成的又不一定有相应的运行环境。
主角登场
我们今天介绍一个利用 DNS 协议进行通信的反弹 Shell,和 ICMP 反弹 Shell 的原理几乎相同,只是传输的协议变为了 DNS。
使用 DNS 请求来伪装通信进行命令控制带来的好处不言而喻,不管你做了多么严格的网络控制,你也要满足至少对一个服务器发起的 DNS 查询请求,那么就可以被攻击者恶意利用。
利用 DNS 的想法并不新奇,在黑帽大会上也多次提到过 DNS 隧道,之前的 DNS 域传送漏洞也是一个利用方法,今天我们选取一个开源的工具进行学习–DNShell 。
有关于 DNS 的相关细节不再赘述,有想了解详细内容的移步相关的 RFC 文档,如 RFC 4034、RFC 3755等等。
准备工作
如作者所说,这是一个使用 Python 编写的、利用 DNS 作为命令控制信道的反弹 Shell。对于 Python 库的准备就不再多说了,依赖的环境应该是 Python 2.7,因为其在服务器端的代码中使用了 raw_input 和 .format() 。
众所周知, raw_input 函数在 Python3 中被砍掉了,而 str.format() 则是在 Python 2.6 才加入的函数。
上图是我的 Package 页
from Crypto.Cipher import AES 引入错误,如果在装了 Crypto 后还是错误,就需要装pycrypto 这个库。
如果想修改代码到 Python3 下运行,遇到 import dns.resolver 引入错误,是需要装dnspython3 的。
DNS 查询
简单介绍一下如何利用 Python 来进行 DNS 查询,这也是核心的方法,DNS 作为信道进行隐蔽通信的核心就是把要传递的数据作为 DNS 请求的 hostname 部分。
import dns.resolver myResolver = dns.resolver.Resolver() myAnswers = myResolver.query(“google.com”, “A”) for data in myAnswers: print data
先创建一个实例,然后查询 Google.com 的 A 记录。以同样的方式,我们可以执行对 MX 和NS 的查询,只需要改动 A 的那部分就可以了,很简单。
当用它来进行反向 DNS 查找(主机名到 IP) 时,就不是简单的输入 IP 地址直接执行 A 记录查找。我们需要执行 PTR 查找,查找时要将待查找的 IP 地址逆向书写,并将 “.in addr.arpa”追加到它后面。
例如,为解析 IP 地址为 114.124.134.3 的主机名,我们使用的代码是:
myAnswers = myResolver.query("3.134.124.114.in-addr.arpa", "PTR")
DNS 解析程序也给我们指定我们自己的域名服务器的选项。这可以通过使用:
1. myResolver = dns.resolver.Resolver()
2. myResolver.nameservers = ['8.8.8.8', '8.8.4.4']
这里也引出了一种对抗的方法,我们将在后面进行说明。
分析与问题
上图将 DNShell 的一次命令控制过程进行了展示,由于两个文件代码量并不大,我们不进行逐段的详细解释和分析了,只对一些地方进行简要阐述,想彻底弄懂或者改写代码的请自行研究。
先运行服务器端,再执行被控制端,这一点在 GitHub 的项目主页上作者也有提醒。
Python 有两个内建的模块用于处理命令行参数,一个是 getopt 另一个是 optparse ,作者在这个代码中使用的是 optparse 模块用来解析命令行参数。
监听的端口是常见的 DNS 服务器端口 53,如果你的服务器恰好搭建了 DNS 服务,或者有程序占用这个端口,你就无法对这个端口进行监听了,必须先停止占用端口的程序。
程序使用了 base64 进行编码解码,使用 AES 进行加密解密,在程序两端都要更改密钥和向量来保证加密的安全性。
NXT 资源记录通过在域中创建所有字面上的所有者名称链,指出某个名称在域中不存在。它们同时也指出,一个已有名称当前有什么资源记录类型。
在加解密的时候,因为 AES 是分块加密的,在加解密时作者使用 lambda 表达式这种匿名函数来实现,十分简洁。
执行命令用的传统 subprocess 子进程的方法,如果要改进代码的话,这里还有提升空间可以解决很多问题,比如执行命令时的权限问题、 Windows 和 Linux 的命令不尽相同的问题等。
如果被控制端需要放在 Windows 上运行,不仅要考虑到其没有 Python 运行环境是否打包成exe 文件才能运行的问题、是否触发 UAC 的验证引起用户警觉,还有应该使用加壳、加密等手段来绕过像管家、360 等杀软的问题。
Nullege 是一个查询源代码和文档的好地方,和谷歌配合使用疗效显著。如果你对其中的某些函数感到陌生或者困惑,不但可以查官方文档,也可以在这里查找很多示例的源代码增进理解。
实际部署
服务器端放在了一台 VPS 上,如上图所示。
在被控制端脚本执行后,服务器端会出现一个 SHELL 的提示行,我们在这里输入命令
ipconfig -all
在被控制端,我们可以清楚的看到,经过解码和解密,已经成功得到了 ipconfig -all 这个命令,(需要注意的是,我对代码进行了些微的改动,可能导致行号和作者版本的行号不相同,不过这并不影响什么)
在调试器中查看执行命令的 stdout 可以看到
即远程的命令可以成功执行。
我们再输入退出的指令 quit 来测试一下
被控制端直接退出了,也完成了远程的命令。接着我们用 Wireshark 进行抓包
可以看到这条发送出去的 DNS 请求
返回的响应中,我们也确实看到了携带的数据
对抗方法
在 DNS 查询小节中,我们讲到了在查询时指定域名服务器的方法。
这也是对抗使用 DNS 请求作为隐蔽通信信道的方法,在可能的情况下,使用自己搭建的 DNS 服务器,这样就可以直接得出:除了这一台 DNS 服务器要与外界进行 DNS 请求交互,其余服务器任何试图与外界DNS 服务器发起的请求都是恶意的。
*本文原创作者:ArkTeam 楚子航,本文属FreeBuf原创奖励计划,未经许可禁止转载
- iis7 发布mvc 遇到的HTTP错误 403.14-Forbidden Web 服务器被配置为不列出此目录的内容
- NET中验证控件表达式汇总
- 动态执行超过4000个字符的SQL
- 在ASPNET中使用JS集锦
- 小程序又又又……
- js中页面刷新和页面跳转的方法总结
- PixelBender(着色器)初体验
- Centos下堡垒机Jumpserver V3.0环境部署完整记录(1)-安装篇
- CSS好看的按钮
- Metaball(元球)效果学习
- ASP.NET MVC 4 RC的JS/CSS打包压缩功能
- 表格可在线编辑效果
- CSS侧边栏宽度不动(更改页面宽度时),内容区宽度自适应
- JS网页顶部弹出可关闭广告图层
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python根据指定文件生成XML的方法
- python如何调用java类
- Python pytesseract验证码识别库用法解析
- python 读txt文件,按‘,’分割每行数据操作
- PHP利用递归函数实现无限级分类的方法
- 详解关于php的xdebug配置(编辑器vscode)
- PHP应用跨时区功能的实现方法
- PHP实现的数据对象映射模式详解
- PDO::beginTransaction讲解
- PHP匿名函数(闭包函数)详解
- PDO::getAttribute讲解
- PHP压缩图片功能的介绍
- PHP+RabbitMQ实现消息队列的完整代码
- Pytorch 高效使用GPU的操作
- PDO::commit讲解