nginx重要配置文件、urlsplit和urlunsplit的利用、编码的利用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @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"
|
flask写的一个后端,代码量很少,没什么东西,简单说一下代码逻辑,对我们输入的url进行检查,第一步判断host是不是suctf.cc 不是才进行下一步,然后用到了 urlsplit(url) ,再判断host是不是suctf.cc 不是才进行下一步, 最后保证host是suctf.cc ,然后urlopen(finalUrl).read() 。
解法一:
首先我们想办法找到flag文件的位置,这个时候需要读 nginx 里面的配置文件(也是一个考点),nginx常见的配置文件位置如下:

我们很自然的想到用 file协议来读,现在关键是怎么绕过去,直接用file://suctf.cc/usr/local/nginx/conf/nginx.conf 来读的话第一步就被ban了。但是可以利用到 file://// , 这个我不知道是不是python urlsplit和 urlunsplit的一个bug 。 我们本地测试一下:

结果:

这样就很清楚了,我们可以直接用 file:////suctf.cc/usr/local/nginx/conf/nginx.conf 来读配置文件 ,
1 2 3 4 5
| newhost = [] for h in host.split('.'): newhost.append(h.encode('idna').decode('utf-8')) parts[1] = '.'.join(newhost) #去掉 url 中的空格
|
用这个方法的话,这几行代码基本上失去了意义。因为 host是个空值。这个也是非预期解。

然后同样的方式 读flag。
解法二:
利用到了unicode 编码的特性
我们构造 url = file://suctf.c℆sr/local/nginx/conf/nginx.conf, 其中 “℆” 这个字符,在经过idna编码之后 会变成c/u.从而可以绕过前两个判断,然后进过下面的代码:
1 2 3 4
| for h in host.split('.'): newhost.append(h.encode('idna').decode('utf-8')) parts[1] = '.'.join(newhost) #去掉 url 中的空格
|
其中parts[1] 就变成了 ‘suctf.cc/usr’ 。 后面的方法同理
参考链接:https://www.cnblogs.com/wangtanzhi/p/12181032.html