SUCTF2019Pythonginx

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)
#去掉 url 中的空格
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常见的配置文件位置如下:

3.png

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

4.png

结果:

5.png

这样就很清楚了,我们可以直接用 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是个空值。这个也是非预期解。

6.png

然后同样的方式 读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