密码管理软件 Teampass 存在未授权 SQL 注入漏洞

前言

Teampass是一个首次发布于2011年底的协作密码管理器。我们检测到一个关键的未经验证的SQL注入和文件包含漏洞,可能会导致许多用户密码的泄露。这些问题在今年早些时候已经报告和确定。

RIPS分析

14816094621

RIPS是一个用php编写的源代码分析工具,它使用了静态分析技术,能够自动化地挖掘PHP源代码潜在的安全漏洞。RIPS能够在25秒内分析整个项目,包括约14万行代码,发现了很多严重的安全漏洞。存在的两种主要的问题是SQL注入和文件包含。幸运的是,大多数SQL注入在安装/升级功能中发现,并且不太严重。

截断的分析结果在RIPS演示应用程序中提供,查看RIPS演示报告

案例分析

示例1:经过身份验证的Blind SQL注入

这个漏洞是RIPS如何遵循复杂的数据流以及其对PHP的独特功能的理解的一个很好的例子。

//api/index.php
parse_str($_SERVER['QUERY_STRING']);
rest_get();

上面的代码是这个应用程序中存在漏洞的主要罪魁祸首。函数parse_str()将查询字符串解析为变量,例如,参数data=12&var=foo初始化变量$data=12和$var=’foo’。 来自变量$ _SERVER[‘QUERY_STRING’]的HTTP查询字符串用作parse_str($_SERVER[‘QUERY_STRING’])中的输入,它允许攻击者在全局范围内为应用程序创建任意变量。 然后,函数rest_get()被调用,创建一个类的新对象NestedTrees。

//api/functions.php
function rest_get() {
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
    $tree->rebuild();
//includes/libraries/Tree/NestedTree/NestedTree.php
class NestedTree {
    public function __construct($table, $idField, $parentField, $sortField) {
        $this->table = $table;

rsip-1

这里,table属性设置为对prefix_table(”nested_tree”)的调用的结果。仔细观察函数定义,可以看到全局变量$ pre被前缀到1180行的函数的table参数。攻击者现在能够通过简单的改变来改变全局变量$ pre的内容,从而改变表名 GET参数,因为前面解释过的parse_str()调用。此外htmlspecialchars()的用法还不足以对SQL注入进行过滤,尽管在这种特定情况下它不会起作用,因为没有攻击者需要突破的引号。 RIPS检测到由于其上下文敏感的脏数据分析不足的过滤。

//includes/libraries/Tree/NestedTree/NestedTree.php
class NestedTree {
public function rebuild() {
    $this->getTreeWithChildren();

14816204301

最后,在由mysqli_query()执行的查询中未污染的表名被使用,并且可以利用它来从数据库读取任意值。 由于Teampass是密码管理器,因此很可能在数据库中发现敏感数据。

我们无法利用此漏洞,因为每当我们通过GET参数更改全局变量$ pre时触发了另一个SQL注入。 幸运的是,对于我们来说,新发现的SQL注入不需要利用身份验证,因此更为关键。 下面的案例研究示例描述了该漏洞。

示例2:未经身份验证的Blind SQL注入

在这个例子中的安全问题非常类似于前一个,只是它是更容易利用,因为不需要认证。 以下代码受到影响。

//api/index.php
parse_str($_SERVER['QUERY_STRING']);
rest_get();
//api/functions.php
function rest_get () {
    if(apikey_checker($GLOBALS['apikey'])) {
//api/functions.php
function apikey_checker ($apikey_used) {
    teampass_connect();
    $apikey_pool = teampass_get_keys();

12131421

如前面所述,主要原因是调用parse_str()函数,使攻击者能够创建任意的全局变量。对API发起的每个GET请求,必须使用apikey_checker()函数检查API密钥的正确性。这里与前面一样,函数prefix_table()使用全局变量$ pre和稍后使用queryOneColumn()方法执行查询的表名api前缀。攻击者能够改变前置变量并且从数据库中选择任意数据而不需要任何认证要求。

示例3:文件包含

还有一个有趣的文件包含漏洞使用相同的入口点,我们在以下代码中看到,应用程序中的许多文件包含操作都受到类似的影响。

//api/index.php
parse_str($_SERVER['QUERY_STRING']);
rest_get();
//api/functions.php
function rest_get() {
    cryption($data['pw'], SALT, $data['pw_iv'], 'decrypt');
function cryption($p1, $p2, $p3, $p4 = null) {
    require_once $_SESSION['settings']['cpassman_dir'] . '/includes/libraries/Encryption/Encryption/Crypto.php';

这里,攻击者可以使用parse_str()函数通过GET参数设置变量$ _SESSION [‘settings’] [‘cpassman_dir’],从而能够包括开发人员不想要的文件。根据服务器配置,可以包括任意远程文件。幸运的是,require_once语句只能由经过身份验证的用户访问,并且常量DEFUSE_ENCRYPTION为true,这不是受影响版本的默认值。

重新扫描固定版本

14816214981

上图描述了重新扫描Teampass更新版本(2.1.26.8  2.1.26.9)的统一统计量,RIPS比较两次扫描的分析结果,并能够精确识别更新的应用程序版本中已修复的、旧的和新的问题。 可以看出,新版本修复了很多问题,只是在代码库中引入了一个新的XSS问题。

总结

密码管理器是非常敏感的工具,在部署为Web应用程序时更加脆弱。 我们发现了许多关键问题,由于一个PHP内置函数使用不当,这就是为什么与所有安全相关的PHP函数的精确理解是RIPS分析引擎的核心功能。

 

*转载请注明来自MottoIN

原创文章,作者:Sam,如若转载,请注明出处:http://www.mottoin.com/article/web/93751.html

发表评论

登录后才能评论

联系我们

021-62666911

在线咨询:点击这里给我发消息

邮件:root@mottoin.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code