『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测

admin 2022年7月21日18:39:05评论15 views字数 7493阅读24分58秒阅读模式
『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测

点击蓝字,关注我们

『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测


日期:2022-07-21
作者:Zero
介绍:一份靠谱的移动安全测试环境搭建指南。
本文涉及的文件可以在公众号回复 0721-APP 获取,如果本文对您有帮助,来个点赞、在看就是对我们莫大的鼓励。

1、 前言

由于谷歌旗下的 Pixel 系列手机因其开放性以及对自家安卓系统的兼容非常好,所以很多移动安全人员都喜欢用该系列的手机作为测试机,进行日常应用测试及脱壳分析等工作,本文为刚接触移动安全的朋友提供一份靠谱的基础环境构建指南系列之Ⅲ-APP违规上报信息检测。

日常工作中,偶尔会碰到应用合规性检查的需求,比如在未告知用户情况下收集IMEI已安装应用列表等个人隐私信息,目前最普遍的方式就是抓取APP数据包,检测数据包中是否存在上述隐私信息,由于违规上报信息检测不需要对数据包进行修改、拦截操作,只需要有搜索过滤功能即可满足需求,在上文中已经完成初步的违规上报信息检测环境搭建,本文将在上篇文章基础上把检测过程进一步自动化,效果如下图所示。

『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测

2、 正文

相关信息:

  • 手机型号:Google Pixel 2 无锁版

  • 官方镜像版本:11.0.0 (RP1A.201005.004.A1, Dec 2020)

  • Magisk:v23.0

  • MagiskTrustUserCerts:v0.4.1

  • Drony:v1.3.154

  • Ubuntu:16.04.3 LTS

  • Node.js:v16.14.2

  • NPM:8.5.0

  • AnyProxy:4.1.3

注:本文涉及到的文件均已打包,开箱即用,获取方式见文末。

2.1 优化手动检测的体验

接上文继续,上文中提到官方版本的AnyProxy搜索过滤的粒度略粗,需要自行调整代码以满足功能需求,因为官方代码中只对URL参数做匹配,所以官方版本只能匹配出使用GET方法在URL中提交数据的请求,默认不对POST提交过去的数据进行处理,而且还对大小写敏感,比如搜索MAC字段,就需要把macMAC两种形式全部填入,在此场景下使用起来不是很方便,于是阅读源码看一下实现逻辑,首先通过页面上的文字定位到record-filter这部分代码。

『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测

顺着逻辑寻找updateFilter来自哪,在文件头部可以看到相关引用。

import React, { PropTypes } from 'react';import ReactDOM from 'react-dom';import ClassBind from 'classnames/bind';import { connect } from 'react-redux';import { Input, Alert } from 'antd';import ResizablePanel from 'component/resizable-panel';import { hideFilter, updateFilter } from 'action/globalStatusAction';import { MenuKeyMap } from 'common/constant';
import Style from './record-filter.less';import CommonStyle from '../style/common.less';

class RecordFilter extends React.Component { constructor () { super(); this.onChange = this.onChange.bind(this); this.onClose = this.onClose.bind(this); this.filterTimeoutId = null; }
static propTypes = { dispatch: PropTypes.func, globalStatus: PropTypes.object }
onChange (event) { this.props.dispatch(updateFilter(event.target.value)); }

根据文件头部的信息跟随前往action/globalStatusAction能够找到updateFilter方法定义。

export function updateFilter(filterStr) {  return {    type: UPDATE_FILTER,    data: filterStr  };}

继续梳理逻辑,在record-worker部分的代码中,找到生成过滤正则的方法getFilterReg

const getFilterReg = function (filterStr) {  let filterReg = null;  if (filterStr) {    let regFilterStr = filterStr      .replace(/rn/g, 'n')      .replace(/nn/g, 'n');
// remove the last /n$/ in case an accidential br regFilterStr = regFilterStr.replace(/n*$/, '');
if (regFilterStr[0] === '/' && regFilterStr[regFilterStr.length - 1] === '/') { regFilterStr = regFilterStr.substring(1, regFilterStr.length - 2); }
regFilterStr = regFilterStr.replace(/((.+)n|(.+)$)/g, (matchStr, $1, $2) => { // if there is 'n' in the string if ($2) { return `(${$2})|`; } else { return `(${$1})`; } });
try { filterReg = new RegExp(regFilterStr); } catch (e) { console.error(e); } }
return filterReg;};

接下来思路就很清晰了,首先需要修改生成过滤正则的getFilterReg方法,使其忽略大小写,然后再定位到引用该方法的地方,加入对Body数据的过滤代码,这样就符合我们的功能需求了。

先处理大小写敏感的问题,忽略大小写只需要在正则最后加入i选项即可,代码做如下修改。

const getFilterReg = function (filterStr) {  let filterReg = null;  if (filterStr) {    let regFilterStr = filterStr      .replace(/rn/g, 'n')      .replace(/nn/g, 'n');
// remove the last /n$/ in case an accidential br regFilterStr = regFilterStr.replace(/n*$/, '');
if (regFilterStr[0] === '/' && regFilterStr[regFilterStr.length - 1] === '/') { regFilterStr = regFilterStr.substring(1, regFilterStr.length - 2); }
regFilterStr = regFilterStr.replace(/((.+)n|(.+)$)/g, (matchStr, $1, $2) => { // if there is 'n' in the string if ($2) { return `(${$2})|`; } else { return `(${$1})`; } });
try { filterReg = new RegExp(regFilterStr,"/i"); } catch (e) { console.error(e); } }
return filterReg;};

在修改之前搜索只有大小写正确才可以过滤出数据,就像这样。

『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测

修改完成后,过滤功能下不再对大小写敏感。

『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测

这样的话过滤功能对大小写敏感的问题就算是解决了,接下来还剩一个对Body数据进行过滤的需求,寻找getFilterReg方法的引用,顺藤摸瓜,可以找到最终的过滤实现方法calculateFilteredRecords

self.calculateFilteredRecords = function (isFullyCalculate, listForThisTime = []) {  const filterReg = getFilterReg(self.filterStr);  if (isFullyCalculate) {    self.FILTERED_RECORD_LIST = [];    const length = recordList.length;    // filtered out the records    for (let i = 0; i < length; i++) {      const item = recordList[i];      if (!filterReg || (filterReg && filterReg.test(item.url))) {        self.FILTERED_RECORD_LIST.push(item);      }    }  } else {    listForThisTime.forEach((item) => {      const index = self.FILTERED_RECORD_LIST.findIndex((record) => {        return item.id === record.id;      });
if (index >= 0) { self.FILTERED_RECORD_LIST[index] = item; } else if (!filterReg || (filterReg && filterReg.test(item.url))) { self.FILTERED_RECORD_LIST.push(item); } }); }};

简单阅读下代码,通过filterReg.test(item.url)这部分代码,很容易发现先前生成的正则表达式只对URL进行了匹配,成功匹配后才会将其显示到页面中,在if中将匹配Body的代码用或运算进行连接,就可以实现我们的需求了。

接下来需要先找到Body数据在哪才能进行匹配,根据item.url也不难猜到Body数据肯定也在item中,此时可以选择浏览器控制台直接查看。

『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测

也可以翻阅代码进行查找,根据点击请求时右侧会展示请求的详情为切入点,定位到record-request-detail代码中的getReqBodyDiv方法。

getReqBodyDiv() {    const { recordDetail } = this.props;    const requestBody = recordDetail.reqBody;
const reqDownload = "<a href={"/fetchReqBody?id=${recordDetail.id}&_t=${Date.now()}"} target="_blank">download</a>"; const getReqBodyContent = () => { const bodyLength = requestBody.length; if (bodyLength > MAXIMUM_REQ_BODY_LENGTH) { return reqDownload; } else { return "<div>{requestBody}</div>" } }// ....

根据代码中的recordDetail.reqBody可以看出Body内容对应的是.reqBody,于是对代码做如下修改。

self.calculateFilteredRecords = function (isFullyCalculate, listForThisTime = []) {  const filterReg = getFilterReg(self.filterStr);  if (isFullyCalculate) {    self.FILTERED_RECORD_LIST = [];    const length = recordList.length;    // filtered out the records    for (let i = 0; i < length; i++) {      const item = recordList[i];      if (!filterReg || (filterReg && (filterReg.test(item.url) || filterReg.test(item.reqBody)))) {        self.FILTERED_RECORD_LIST.push(item);      }    }  } else {    listForThisTime.forEach((item) => {      const index = self.FILTERED_RECORD_LIST.findIndex((record) => {        return item.id === record.id;      });
if (index >= 0) { self.FILTERED_RECORD_LIST[index] = item; } else if (!filterReg || (filterReg && (filterReg.test(item.url) || filterReg.test(item.reqBody)))) { self.FILTERED_RECORD_LIST.push(item); } }); }};

对比一下修改前后的效果,修改后已达预期效果,手动检测只需要打开网页就可以快速进行,不用运行BurpSuite之类的客户端代理软件,体验优化+1

『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测

源码修改已完成,正常来说需要重新部署一下才可以使用,这里提供命令方式对已安装的AnyProxy程序代码打个补丁,本文使用的版本为 4.1.3,安装完主程序后运行如下命令,即可达到一样的效果。

# 需自行确认下文件路径是否一致sed -i "s/f.test(d.url)/(f.test(d.url)||f.test(d.reqBody))/g" /usr/local/lib/node_modules/anyproxy/web/dist/*.jssed -i 's/new RegExp(f)/new RegExp(f,"i")/g' /usr/local/lib/node_modules/anyproxy/web/dist/main.js

至此还有一个问题,由于目前是命令行启动的AnyProxy,会话一旦断开,AnyProxy就会一起结束运行,为了随时可以使用,需要让AnyProxy常驻后台运行,这里后台进程管理交给PM2来处理。

PM2的安装非常简单,使用NPM即可快速安装。

npm install pm2 -g

安装完成后使用PM2启动AnyProxy

pm2 start anyproxy --name anyproxy -- -i -p 1080 -w 8002

命令执行后会列出状态信息,如下所示。

『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测

此时SSH会话或者终端就可以放心关闭了,需要使用时直接访问网页就可以了。

会用到几条命令做个记录。

# 查看状况pm2 list
# 关闭 anyproxypm2 stop anyproxy
# 启动 anyproxypm2 start anyproxy
# 重启 anyproxypm2 restart anyproxy

2.2 规则文件编写

通过上述修改已经可以方便的进行内容筛选,如果想实现自动对内容进行匹配,就需要编写自定义的规则,对预定义的敏感字进行匹配检测,参照官方文档编写规则,要使用的关键接口为beforeSendRequest,以下为该接口的定义。

『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测

在该接口中编写过滤代码,敏感字通过正则进行匹配,将规则文件保存为rule_app.js,其中关键部分如下。

*beforeSendRequest(requestDetail) {    var reg = /mac|imei|device|os.*version|wifi|ssid|app.*list|android.*id|ip|gps|phone.*number|location;/gi;
var url = requestDetail.url; var body = requestDetail.requestData.toString();
if(url.search(reg)>=0 || body.search(reg)>=0) { fs.appendFileSync(log, "URL:[" + url + "]nBody:[" + body + "]nn", 'utf-8', function (err) { if (err) throw err; console.log('err'); }); } return null; },

规则对内容进行正则匹配,如匹配到则将URLBody信息输出至纯文本文件中,这里只用作演示,可以自行更改为存入数据库、输出表格等存储方式,脚本编写完成后上传至服务器中,首先将正在运行的AnyProxy关闭,之后带上自定义规则文件的参数重新启动。

# 关闭 AnyProxypm2 stop anyproxy
# 带参数启动anyproxy --intercept --port 1080 -w 8002 --rule rule_app.js

重新启动完成后,手机打开应用,等待应用启动完成后查看服务器中的纯文本文件是否有内容,有则说明匹配到了相关字段,文件路径可以在规则文件rule_app.js中进行配置。

后续将编写一个上层调度程序,使用ADB将应用安装至系统,启动AnyProxy之后唤起应用程序,等待启动完成后对结果进行检测,如存在信息,再人工对数据进行二次核验,确定最终结论。

3、 结语

至此已初见成效,进行检测工作更加便捷,规则文件及修改后的程序已打包为附件,可在公众号中获取,需要的朋友可以点个关注,防止迷路!

本文涉及的文件可以在公众号回复 0721-APP 获取,如果本文对您有帮助,来个点赞、在看就是对我们莫大的鼓励。


推荐阅读

『杂项』移动安全测试环境搭建(1)-- 基础环境

01-21 特稿

『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测

『杂项』移动安全测试环境搭建(2)--基础抓包环境

03-17 特稿

『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测

『杂项』移动安全测试环境搭建(3)-- APP违规上报信息检测

06-02 特稿

『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测



免责声明:本文仅供安全研究与讨论之用,严禁用于非法用途,违者后果自负。

『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测

宸极实验室隶属山东九州信泰信息科技股份有限公司,致力于网络安全对抗技术研究,是山东省发改委认定的“网络安全对抗关键技术山东省工程实验室”。团队成员专注于 Web 安全、移动安全、红蓝对抗等领域,善于利用黑客视角发现和解决网络安全问题。

团队自成立以来,圆满完成了多次国家级、省部级重要网络安全保障和攻防演习活动,并积极参加各类网络安全竞赛,屡获殊荣。

对信息安全感兴趣的小伙伴欢迎加入宸极实验室,关注公众号,回复『招聘』,获取联系方式。

原文始发于微信公众号(宸极实验室):『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年7月21日18:39:05
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   『杂项』移动安全测试环境搭建(4)— 自动化APP违规上报信息检测https://cn-sec.com/archives/1191795.html

发表评论

匿名网友 填写信息