你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱

渗透技巧 2年前 (2022) admin
602 0 0
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
点击蓝字·关注我们
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
全文 2744 字,预计阅读时间 10 分钟
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱

前言

Python开发人员始终相信他们写的程序是安全的,因为使用的都是标准库和通用框架。但是,Python的某些功能可能会被误用,从而导致安全问题。这些问题隐蔽,并且危害性十足,像一颗定时炸弹,存在于程序中,下面将分享在实际的Python项目中遇到的Top 10鲜为人知的安全陷阱。

你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱

1. 优化机制+assert

为了使代码内存占用更少,运行更快,Python提供了一种优化运行的机制。然而需要注意的是,当以优化模式运行代码的时候,所有的assert都会被忽略掉,如果开发者使用了assert进行身份验证,可能导致权限绕过漏洞。


示例

def superuser_action(request, user):    assert user.is_super_user    # execute action as super user

这里的assert将会被忽略掉,导致验证身份的代码无效,从而造成权限绕过。

你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱

2. MakeDirs的默认权限差异

os.makedirs一般用来创建一个/多个文件夹,它的第2个参数mode用来指定创建文件夹的默认权限。我们先来看一个例子


示例

def init_directories(request):    os.makedirs("A/B/C", mode=0o700)    return HttpResponse("Done!")

在 Python < 3.6 中,文件夹 A、B 和 C 的创建权限分别为 700。

但是,在 Python > 3.6 中,只有最后一个文件夹 C 的权限为 700,其他文件夹 A 和 B 的默认权限为 755。

P.S. Python > 3.6,函数os.makedirs与 Linux 中mkdir -m 700 -p A/B/C 保持一致。

一些开发人员不知道版本之间的差异,可能会导致权限提升漏洞,比如 Django 中的权限升级漏洞 ( CVE-2020-24583 )。

你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱

3. 绝对路径连接

os.path.join(path, *paths)函数用于将多个文件路径连接成一个组合文件路径。第一个参数通常是基础路径,而每个其他参数都会附加到基础路径后。但是这个函数有个鲜为人知的特性,如果某一个附加路径以 / 开头,包括基本路径在内的,它之前的路径都会被忽略,并且把这个附加路径视为绝对路径。


示例

def read_file(request):    filename = request.POST['filename']    file_path = os.path.join("var", "lib", filename)    if file_path.find(".") != -1:        return HttpResponse("Failed!")    with open(file_path) as f:        return HttpResponse(f.read(), content_type='text/plain')

如果传入的filename参数是 a/b/c.txt,则读取的文件是 /var/lib/a/b/c.txt,如果传入的是 /a/b/c.txt,则读取的文件变成了 /a/b/c.txt。这种问题已经导致了很多安全漏洞,比如CVE-2020-35736

你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱

4. 指定名称的临时文件

tempfile.NamedTemporaryFile函数用于创建具有特定名称的临时文件,有prefix和suffix两个参数指定前后缀,如果前后缀参数可控,则会导致任意目录写文件漏洞。


示例

def touch_tmp_file(request):    id = request.GET['id']    tmp_file = tempfile.NamedTemporaryFile(prefix=id)    return HttpResponse(f"tmp file: {tmp_file} created!", content_type='text/plain')

用户输入id用作临时文件的前缀。如果攻击者传递/../var/www/test给参数id,则会创建以下tmp文件:/var/www/test_zdllj17,可以将文件写到Web目录。

你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱

5. zipfile处理../

压缩文件中打包的文件使用../作为文件名,从而进行目录穿越读写文件已经是老生常谈了,zipfile的extract和extractall函数都会对../进行清理,从而阻断此漏洞。但是,zipfile中的函数只有这两个有这个功能,一些开发人员认为自己使用了zipfile库就是安全无忧的。


示例

def extract_html(request):    filename = request.FILES['filename']    zf = zipfile.ZipFile(filename.temporary_file_path(), "r")    for entry in zf.namelist():        if entry.endswith(".html"):            file_content = zf.read(entry)            with open(entry, "wb") as fp:                fp.write(file_content)    zf.close()    return HttpResponse("HTML files extracted!")

上述代码使用了zipfile库,但是没使用extract和 extractall函数。如果传入的zip文件夹中有一个../../var/www/html,则会将恶意内容写入到Web目录。NLTK下载器出现过这类漏洞(CVE-2019-14751)。

你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱

6. 正则表达式中match和search的差异

正则表达式是代码中不可或缺的一部分,re.search会匹配多行内容,而re.match只匹配第一行,攻击者可能会使用 n 进行绕过。


示例

def is_sql_injection(request):    pattern = re.compile(r".*(union)|(select).*")    name_to_test = request.GET['name']    if re.search(pattern, name_to_test):        return True    return False

如果攻击者传入aaaa n union select,不匹配正则表达式,从而绕过权限控制。

P.S. 不建议使用正则进行安全检查。

你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱

7. Unicode标准化函数

unicode.normalize() 函数可以按照指定形式对字符串进行标准化,如NFKC。可能会导致标准化前的无害代码,在绕过了安全检查后进行了标准化,变成了恶意payload。来看下面的例子。


示例

import unicodedatafrom django.shortcuts import renderfrom django.utils.html import escape
def render_input(request): user_input = escape(request.GET['p']) normalized_user_input = unicodedata.normalize("NFKC", user_input) context = {'my_input': normalized_user_input} return render(request, 'test.html', context)

用户的输入被escape函数转义,来防止XSS。假设输入的字符为%EF%B9%A4script%EF%B9%A5,在标准化后,就变成了<script>,从而引入了XSS漏洞。

你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱

8. Unicode大小写冲突

Unicode试图统一世界上所有的语言,然而语言的种类太多了,这也就导致不同语言的字符有很大概率会使用同一个Unicode编码。例如,小写的土耳其字符ı(不带点)的大写字符是l;拉丁文字符i大写字符也是l,两个不同语言的小写字符的大写字符Unicode编码是一致的,这可能会导致漏洞利用。Django漏洞(CVE-2019-19844)产生的原理就是这个。


示例

from django.core.mail import send_mailfrom django.http import HttpResponsefrom vuln.models import User
def reset_pw(request): email = request.GET['email'] result = User.objects.filter(email__exact=email.upper()).first() if not result: return HttpResponse("User not found!") send_mail('Reset Password','Your new pw: 123456.', '[email protected]', [email], fail_silently=False) return HttpResponse("Password reset email send!")

可以看到,检查电子邮件的时候,将email转换成大写,进行判断是否存在。攻击者现在可以简单地将foo@mıx.com作为email参数传递(其中i被土耳其语ı替换)。进行检查的时候,email参数被转换为大写,结果为[email protected]。这意味着用户存在,然后发送密码重置的电子邮件。但是密码重置邮件的收件地址仍然是土耳其语的email。换句话说,另一个用户的密码被发送到攻击者控制的电子邮件地址中。

你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱

9. ipaddress标准化

Python<3.8中,ipaddress库在标准化ip地址的时候,会删除多余的0(见下面示例)。这种行为会导致绕过防御SSRF的黑名单IP列表,从而导致SSRF。


示例

import requestsimport ipaddress
def send_request(request): ip = request.GET['ip'] try: if ip in ["127.0.0.1", "0.0.0.0"]: return HttpResponse("Not allowed!") ip = str(ipaddress.IPv4Address(ip)) except ipaddress.AddressValueError: return HttpResponse("Error at validation!") requests.get('https://' + ip) return HttpResponse("Request send!")

如果传入的ip参数是127.0.00.1,则会被ipaddress标准化为127.0.0.1,而127.0.00.1不在SSRF黑名单中,从而绕过了检查。

你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱

10. 特殊的URL变量分隔符

Python < 3.7 中,函数urllib.parse.parse_qsl允许使用 ; 和 & 字符作为 URL 查询变量的分隔符。这里有趣的是,其他语言不将字符 ; 识别为分隔符。在下面的示例中,我们将说明为什么这种行为会导致漏洞。

假设我们正在运行一个项目,前端是一个 PHP 应用程序,后端是 Python 应用程序。


示例

攻击者向 PHP 前端发送以下 GET 请求:

GET https://victim.com/?a=1;b=2

PHP解析出的变量是a,值为1;b=2,传到后端,python解析到两个变量a和b,这种差异会导致很严重的安全漏洞,例如Djabgo著名的Web缓存中毒漏洞(CVE-2021-23336)。

你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱

参考链接

https://blog.sonarsource.com/10-unknown-security-pitfalls-for-python

你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
END
你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱
免责声明

本公众号内的文章及工具仅提供学习用途,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本公众号及文章作者不为此承担任何责任。


好文分享收藏赞一下最美点在看哦

原文始发于微信公众号(我不是Hacker):你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱

版权声明:admin 发表于 2022年2月21日 上午1:01。
转载请注明:你写的Python程序安全吗?详解Python 10大鲜为人知的安全陷阱 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...