• 代码审计:python代码审计汇总(持续更新中)


    后续有时间会持续更新补充,当前整理为一些重点漏洞的,如下:

    命令注入

    代码注入

    不安全的反序列化、

    sql注入、

    任意文件下载、

    文件上传(文件操作)、

    XXE、

    SSRF、

    XSS、

    直接重定向、

    日志伪造、

    模板注入SSTI、

    不安全的随机数、

    格式化的字符串

    OS命令注入

    主要是程序中通过Python的OS接口执行系统命令,常见的危险函数有等一些接口。

    1、os.system( )

    def myserve(request,fullname):
    os.system("sudo rm -f %s"%fullname)
    

    fullname是用户可控的,恶意用户只需利用shell的拼接符;就可以完成一次很好的攻击。

    2、popen( )

    os.popen( )
    subprocess.popen( )
    

    popen()函数是Python中用于执行外部命令的函数之一。它可以将一个shell命令作为参数传递给操作系统,并在Python中执行该命令的结果。

    popen()函数是在subprocess模块中定义的。使用之前,我们需要先导入这个模块:

    import subprocess

    要执行一个命令,我们可以使用subprocess.Popen()函数。它的基本语法如下:

    subprocess.Popen(cmd, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)
    

    3、platform.popen( )

    import platform
    print platform.popen('dir').read()
    

    4、commands模块的一些方法

    import commands
    
    commands.getoutput('ifconfig')
    commands.getstatusoutput('ifconfig')
    

    subprocess模块的一些方法

    subprocess.run()
    subprocess.Popen()
    subprocess.call()
    subprocess.check_call()
    subprocess.getstatusoutput()
    subprocess.getoutput()
    subprocess.check_output()
    

    subprocess中的shell参数,如果shell=True的话,curl命令是被Bash(Sh)启动,所以支持shell语法。 如果shell=False的话,启动的是可执行程序本身,后面的参数不再支持shell语法。

    防御办法需保证

    (1)shell=True未设置

    (2)转义变量的函数:Python 2.x使用pipes.quote(),Python 3.3或更高版本使用shlex.quote();

    PS:其中Java中的Runtime.getRuntime().exec()效果类似shell=False,而PHP中的shell_exec就类似于shell=True,PHP中的exec则类似于shell=False。

    spawn( ):

    pty.spawn('whoami')
    

    importlib.import_module()

    importlib.import_module('os').system('whoami')
    importlib.__import__('os').system('whoami')
    

    代码注入

    任意代码执行需关注的函数:

    **eval():**将字符串str当成有效的表达式来求值并返回计算结果。

    **exec():**执行 shell 命令、代码。与 eval() 函数类似,都是用于执行字符串形式的代码。然而,exec() 函数更加强大,可以执行多条语句甚至整个代码块。

    eval('__import__("os").system("dir")')
    exec('__import__("os").system("dir")')
    

    案例参考:

    (1)eval() 函数 :python的序列话函数eval,将字符串str当成有效的表达式来求值并返回计算结果。

    代码示例:

    >>>x = 7
    >>> eval( '3 * x' )
    21
    

    例1:request引入的login参数

    def eval_test(request,login):
    login = eval(login)
    

    如果恶意用户从外界传入 import(“os”).system(“rm /tmp -fr”) 就可以清空tmp目录。

    例2:input引入的参数

    user input = input("请输入一个表达式:")
    result = eval (user input)
    print("结果::", result)
    

    **为了避免此类问题,,**可以使用其他替代方法,如

    ast.literal_eval () 或 int() 、 float() 、eval ()函数的安全子集

    (2)exec函数

    exec() 函数与 eval() 函数类似,都是用于执行字符串形式的代码。然而,exec() 函数更加强大,可以执行多条语句甚至整个代码块。因此,不正确使用 exec() 函数可能会导致安全漏洞。下面是一个示例:

    user_input = input("请输入一段代码:")
    exec(user_input)
    

    上述代码中,恶意用户可以输入恶意代码来执行潜在的危险操作。为了提高安全性,可以限制可执行的代码范围,或使用其他更安全的替代方法。

    **execfile():**execfile() 函数可以用来执行一个文件。返回表达式执行结果。

    execfile(filename[, globals[, locals]])
    
    filename -- 文件名。
    globals -- 变量作用域,全局命名空间,如果被提供,则必须是一个字典对象。
    locals -- 变量作用域,局部命名空间,如果被提供,可以是任何映射对象。
    

    **compile():**是一个内置函数,用于将字符串形式的 Python 代码编译为可执行的代码对象,或者将 AST(抽象语法树)对象编译为代码对象。

    **timeit():**timeit.timeit( ) 创建一个Timer实例,并运行代码进行计时,默认将代码执行一百万次。timeit模块是Python内置的用于统计小段代码执行时间的模块,它同时提供命令行调用接口。

    import timeit
    
    timeit.timeit("__import__('os').system('dir')",number=1)
    

    **timeit.repeat():**指定重复次数的执行timeit方法,返回一个结果列表。

    不安全的反序列化

    Python中用于反序列化的模块有:

    marshal

    PyYAML——>yaml.safe_load()

    yaml.load

    import yaml
    
    yamlString = getYamlFromUser()
    yaml.load(yamlString)
    

    pickle/cpickle

    shelve

    PIL

    Unzip

    1、pickle模块

    pickle 是Python中的一个库,用于序列化和反序列化Python对象。然而,pickle 可能存在安全风险,因为它可以执行任意代码。下面是一个示例:

    import pickle
    
    class User:
    
    def __init__(self, name):
    user = User("Alice")
    pickle_data = pickle.dumps(user)
    loaded_user = pickle.loads(pickle_data)
    print("用户名称:", loaded_user.name)
    

    上述代码中,pickle.dumps() 和 pickle.loads() 函数可将 user 对象序列化和反序列化。然而,如果从不受信任的源加载数据,可能导致执行未经授权的操作。为了避免此类问题,可以使用其他更安全的序列化方法,如 json 或 yaml。

    2、cPickle模块

    cPickle.loads("cos\nsystem\n(S'uname -a'\ntR.")
    

    Sql注入

    在一般的Python web框架中都对sql注入做了防护,但是千万别认为就没有注入风险,使用不当也会导致sql注入。

    例如:

    %user_idres = cur.execute(sql)
    

    修复:正确的使用(直白一点就是:使用”逗号”,而不是”百分号”)

    错误的示范:

    def getUsers(user_id):
    sql = ‘select * from auth_user where id =%s’
    %user_idres = cur.execute(sql)
    

    修复:

    execute() 函数本身有接受sql语句参数位的,

    可以通过python自身的函数处理sql注入问题。

    args = (id, type)
    
    cur.execute(
    'select id,name from user_table where id = %s and name = %s',args )
    
    rs=c.execute(
    "select * from log where
    f_UserName=:usr",{"usr":"fanfan"})
    rs=c.execute(
    "select * from log where f_UserName=:1 ",["fanfan"])
    

    使用如此参数带入方式,python会自动过滤args中的特殊字符,制止SQL注入的产生。

    错误用法:

    sql =
    “select id,type,name from xl_bugs
    where id = %s and type = %s” % (id, type)
    cur.execute(sql)
    

    正确用法:

    cursor.execute(
    'select name,password fromt b1
    where name=%s and password=%s',('min',1234))
    result= cursor.fetchone()
    print(result)
    

    正确的使用(直白一点就是:使用”逗号”,而不是”百分号”)

    任意文件下载

    程序员编写了一个下载报表或者任务的功能,如果没有控制好参数就会导致任意文件下载,

    例如:fullname参数

    def export_task(request,filename):
    return HttpResponse(fullname)
    

    文件操作漏洞

    Python代码中文件处理需关注的函数有:

    file()

    file.save()

    open()

    codecs.open()

    示例:以下代码会处理上传的文件,并将它们移到 Web 根目录下的一个目录中。攻击者可以将恶意文件上传到该程序,并随后从服务器中请求这些文件。

    from django.core.files.storage import default_storage
    from django.core.files.base import File
    ...
    def handle_upload(request):
    files = request.FILES
    for f in files.values():
    path = default_storage.save('upload/', File(f))
    ...
    

    即使程序将上传的文件存储在一个无法通过 Web 访问的目录中,攻击者仍然有可能通过向服务器环境引入恶意内容来发动其他攻击。

    如果程序容易出现

    path manipulationcommand injection 或 remote include 漏洞,

    那么攻击者就可能上传带恶意内容的文件,并利用另一种漏洞促使程序读取或执行该文件。

    XXE

    关注Python代码是否导入使用xml处理解析类:

    xml.dom.*

    xml.etree.ElementTree

    xml.sax.*

    错误示例代码如:

    from xml import etree
    tree1 = etree.parse('test.xml')
    print etree.tostring(tree1.getroot())
    

    SSRF

    关注代码是否存在发起请求的库及函数,常见的有自带库requests.get()及urllib/urllib2库,

    用法为

    url = request.GET['url']
    handle = urllib.urlopen(url)
    //urllib.request.urlopen(url)。
    

    XSS

    下列代码若输入可控则可造成XSS:

    return HttpResponse('hello %s' %(name))
    

    安全的写法为

    return render_to_response('hello.html', {'name':name})
    

    直接重定向

    以下 Python 代码会在用户单击链接时,指示用户浏览器打开从 dest 请求参数中解析的 URL。

    ...
    strDest = request.field("dest")
    redirect(strDest)
    ...
    

    日志伪造

    关注logging()函数及LOGGER 等关键字,查看是否输出口令、密钥和其他敏感信息及输入是否可插入%0A%0D进行日志伪造。

    模板注入(SSTI)

    所谓模板注入,又称服务器端模板注入(SSTI),通常发生在使用Jinja2、Django等模板引擎在Web应用程序中渲染模板时。

    攻击者通过在模板中注入恶意代码,使得渲染后的页面能够执行这些代码。如果服务器端模板引擎没有对输入进行适当的验证和过滤,就可能导致SSTI攻击。

    flask的渲染方法有render_template和render_template_string两种,render_template()是用来渲染一个指定的文件的,render_template_string则是用来渲染一个字符串的,不正确的使用flask中的render_template_string方法会引发SSTI

    以下是一个简单的Python SSTI攻击示例,假设你有一个Web应用程序,它使用Flask框架并且存在SSTI攻击:

    from flask import Flask, render_template_string
    app = Flask(__name__)
    @app.route('/')
    def index():
    name = request.args.get('name', 'Guest')
    return render_template_string('Hello, {{ name }}!', name=name)
    if __name__ == '__main__':
    app.run(debug=True)
    

    攻击者可以通过注入SSTI表达式来改变模板的渲染,例如:

    http://your-app.com/?name={{ 7*7 }}

    如果存在SSTI攻击,攻击者可以执行恶意的命令,例如:

    http://your-app.com/?name={{ config.class.init.globals[‘os’].popen(‘whoami’).read() }}

    这将执行os.popen(‘whoami’).read()命令,显示当前操作系统的用户名。

    Flask中的SSTI防御策略

    (1)使用ORM(Object-Relational Mapping)框架

    ORM框架如SQLAlchemy可以为数据库操作提供一层抽象,减少直接编写SQL语句的需求。这降低了SQL注入的风险,间接地防范了SSTI攻击。

    (2)验证和过滤输入

    在处理用户输入时,应始终进行验证和过滤。对于模板中的变量,应确保其不包含任何恶意代码。在Flask中,可以使用Jinja2模板引擎提供的Markup类来自动转义变量,防止XSS攻击。例如:

    from flask import Flask, render_template_string
    from jinja2 import Markup, Environment, FileSystemLoader
    
    app = Flask(__name__)
    env = Environment(loader=FileSystemLoader('templates'))
    @app.route('/')
    def index():
    user_input = ''  # 恶意代码
    template = env.get_template('index.html')
    output = template.render(user_input=Markup(user_input))  # 自动转义变量
    return output
    

    (3)使用Web框架提供的工具

    许多Web框架提供了工具来帮助开发者防范SSTI攻击。在Flask中,可以使用render_template函数来渲染模板,该函数会自动处理输入并进行转义。因此,建议尽可能使用render_template而不是直接使用render_template_string

    (4)保持框架和库的更新

    及时更新Flask及其依赖库可以确保你使用的是最新版本,新版本通常会修复已知的安全漏洞。此外,关注安全社区和官方发布的信息,以便及时了解最新的安全威胁和防御策略。

    除了上述防御策略外,还应遵循其他一些最佳实践来提高安全性。例如:限制对模板文件的访问权限、避免在模板中存储敏感数据、使用HTTPOnly cookie等。

    其他

    不安全随机数:

    当用于安全加密用途时,不可采用形如random.randint(0, 100)不安全的随机数生成机制;

    在Linux和类Unix下用,需使用/dev/random生成安全随机数,在windows下,使用random模块中的SystemRandom类来实现。

    格式化字符串:

    使用形如下列格式化字符串容易造成敏感信息泄露:

    is %s" % (‘jayway’, )或"Myname is {}".format(‘jayway’)

    “My name is %(name)%” % {‘name’:‘jayway’}

    python代码审计工具:

    Bandit安装

    Bandit 安装需要Python环境支持,安装Python3后,执行以下命令:

    pip install bandit

    安装bandit完成后,执行以下命令:

    bandit -r F:\PythonSpace\sm\bank\ -f html -o 1.html

    其中:

    F:\PythonSpace\sm\bank\ 为扫描的源码目录

    -f html 指定生成html报告,工具支持多种格式,如csv,custom,html,json,screen,txt,xml,yaml。

    -o 1.html 指定导出的文件名

  • 相关阅读:
    基于ssm的演出道具租赁管理系统设计与实现-计算机毕业设计源码+LW文档
    postgres 建立连接并删除记录
    关于数据库分页优化--(oracle, mysql)
    Vue第四讲
    FITC-Dextran 荧光素异硫氰酸酯-葡聚糖,FITC-葡聚糖
    从0到1:如何成为优秀产品经理?必备哪些硬核技能?
    效果最大化广告系列的优势所在!
    考虑储能电池参与一次调频技术经济模型的容量配置方法(matlab代码)
    阿斯达年代记下载注册+短信验证教程分享
    戏说领域驱动设计(二十)——值对象
  • 原文地址:https://blog.csdn.net/qq_32277727/article/details/140413935