MENU

Adobe Flash过期封禁策略技术分析及应对方法

前言

事件1
再见,Flash!

2017年7月25日,Adobe 终于官宣了 Flash 的产品寿命结束计划:

2020年12月31日,终止 Flash Player 的开发支持工作;

2021年1月12日,Flash Player 将不再支持播放 Flash 内容;

同时,该公司“强烈建议”所有用户立即在系统中卸载 Flash Player。
1610975394_600588a216e334d7a1ec3.png

事件2
Flash 停服引起故障,大连车务段昼夜攻关

事件3
家里的网站也被这个flash屏蔽给搞坏了。
1610975487_600588ffc3ede4fa221d7.png
Flash服务了这么多年,可以说覆盖率相当大,此次停用,等同于埋了一个后门,定时触发“后门攻击”,不同于安全漏洞,它是有意为之。造成的影响不亚于一次供应链攻击。

很好奇,它是如何实现的呢?

分析

分析目的
Adobe在pepflashplayer.dll里如何实现对过期使用的封禁?从安全对抗的角度,这个限制策略是否可以绕过?

分析对象

名称版本md5
pepflashplayer.dll32.0.0.465AF6D91D849B5AD7BF71CE730EF1AC0E0

分析环境
Win10
Chrome 87.0.4280.141

分析工具
BurpSuit Pro
QQAnalyzer
WinDbg Preview
IDA
010 Editor

分析过程
1、寻找突破口

Adobe在其之前发布的几版Flash软件中埋下了逻辑后门,会在2021年1月12日触发,导致代码在此日期之后拒绝渲染任何更多内容。

这颗逻辑后门是否就在flash.dll里呢?

我们当前的dll位置:C:UsersvinegarAppDataLocalGoogleChromeUser DataPepperFlash32.0.0.465pepflashplayer.dll

下载一个老版本v26.0.0.131,替换该pepflashplayer.dll,重启chrome,flash渲染正常,可以断定逻辑后门确实在该dll中。

过期使用封禁的策略是怎样的呢?

猜测两个可能,一个是联网状态,获取服务端限制策略,使本地逻辑开关关闭,另一个是获取本地日期,与限制日期比较。

情况一 联网抓包

针对http/https请求,burpsuit未发现可疑请求

针对TCP/UDP请求,QQAnalyzer也未发现可疑请求

也可能看漏了。。。

情况二 日期比较

这种情况,又分4种

(1) 当前日期来自本地,限制日期来自服务端

(2) 当前日期来自服务端,限制日期来自本地

(3) 当前日期来自本地,限制日期来自本地

(4) 当前日期来自服务端,限制日期来自服务端[这种类似情况一,但是直接下发一个开关就好了,没必要从server拿两个日期到client比较]

抓包没有发现,直接修改本地时间到2021.1.12之前,重启浏览器,加载成功。

可以确定,flash获取了本地时间,进行比较。

2、定位系统时间获取函数

Win中可以获取系统时间的方式很多,如何确定目标DLL是如何获取的呢?

可以参考导入函数表

IDA加载pepflashplayer.dll,查看导入函数,time关键字过滤

1610975818_60058a4ac05f4b7f0671e.png
这里关注Get相关函数,有了时间获取函数,可以批量下断,动态调试跟踪逻辑了。

3、定位时间校验逻辑

我们知道chrome是多进程运行,包括浏览器,渲染器和插件程序

1610975872_60058a8018e294e154d92.png

哪一个才是我们要调试的进程呢?

知识补充:

Adobe Flash Player 

ActiveX:适用于7、Vista、XP系统IE内核浏览器zhi、本地视频、游戏客户端

NPAPI:适用于FireFox(火狐)、Safari(苹果)、Opera (欧dao朋,12.17版以下)

PPAPI:适用于Chromium浏览器、Opera (欧朋,15.00版以上)

我们用的是chrome浏览器,所以目标锁定在上图第三个进程16736,--type=ppapi

WinDbg Preview 附加,lm查看加载模块,果然,我们的分析对象就在这里

1610975951_60058acf35e8b871fc61e.png

从实际效果看,Attach方式调试已经晚了,校验逻辑已经执行完毕

如何在时间校验逻辑触发前,就断下来呢?

需要 Launch方式加载chrome.exe,并且调试子进程

1610975974_60058ae6b36c18d80790f.png

进入我们需要调试的目标子进程

8:071> |
   0    id: 448c    create    name: chrome.exe
   1    id: 3e30    child    name: chrome.exe
   2    id: 326c    child    name: chrome.exe
   3    id: 1f84    child    name: chrome.exe
   4    id: a60    child    name: chrome.exe
   5    id: 46d8    child    name: chrome.exe
   6    id: 45d0    child    name: chrome.exe
   7    id: 3580    child    name: chrome.exe
.  8    id: 3a24    child    name: chrome.exe
8:071> | 8 s
ntdll!LdrpDoDebuggerBreak+0x30:
00007fff`6b610fcc cc              int     3
8:071> |.
.  8    id: 3a24    child    name: chrome.exe

设置模块加载断点

8:071> sxe ld:pepflashplayer
8:071> g
ModLoad: 00007fff`689c0000 00007fff`68b58000   C:\Windows\System32\gdi32full.dll
ModLoad: 0000016e`9a1d0000 0000016e`9a364000   C:\Windows\System32\USER32.dll
ModLoad: 00007fff`6b400000 00007fff`6b42e000   C:\Windows\System32\IMM32.DLL
ModLoad: 00007fff`67e00000 00007fff`67e0c000   C:\Windows\SYSTEM32\CRYPTBASE.DLL
ModLoad: 00007fff`13b50000 00007fff`15ad4000   C:\Users\vinegar\AppData\Local\Google\Chrome\User Data\PepperFlash\32.0.0.465\pepflashplayer.dll
0000016e`99051734 c3              ret

批量设置获取时间函数断点

8:071> bm KERNEL32!GetSystemTime*
  1: 00007fff`69f5ec90 @!"KERNEL32!GetSystemTimeAdjustmentStub"
  2: 00007fff`69f5a840 @!"KERNEL32!GetSystemTimeStub"
  3: 00007fff`69f56a70 @!"KERNEL32!GetSystemTimeAsFileTimeStub"
  4: 00007fff`69f5e470 @!"KERNEL32!GetSystemTimesStub"
  5: 00007fff`69f625c0 @!"KERNEL32!GetSystemTimePreciseAsFileTime"
8:071> bl
     1 e Disable Clear  00007fff`69f5ec90     0001 (0001)  8:**** KERNEL32!GetSystemTimeAdjustmentStub
     2 e Disable Clear  00007fff`69f5a840     0001 (0001)  8:**** KERNEL32!GetSystemTimeStub
     3 e Disable Clear  00007fff`69f56a70     0001 (0001)  8:**** KERNEL32!GetSystemTimeAsFileTimeStub
     4 e Disable Clear  00007fff`69f5e470     0001 (0001)  8:**** KERNEL32!GetSystemTimesStub
     5 e Disable Clear  00007fff`69f625c0     0001 (0001)  8:**** KERNEL32!GetSystemTimePreciseAsFileTime

截获的时间函数调用很多,如何确定哪一个才是我们要找的呢?

这里有个笨办法,还好被调用的也就8,9次。

每次时间函数断下,修改系统时间,gu放行,再改回系统时间,g放行,查看页面效果,确认哪次修改,会使flash正常工作。

操作发现,GetSystemTimeAsFileTimeStub函数断下后,修改系统时间,可使flash正常工作。但该函数的上层调用位于chrome.dll中,并未在pepflashplayer.dll中。

难道check逻辑是在chrome.dll中?这与我们上面的验证逻辑不符,替换pepflashplayer.dll为老版本,可以正常渲染,难道chrome.dll能判断版本?

继续追溯上层调用发现,

Breakpoint 3 hit
KERNEL32!GetSystemTimeAsFileTimeStub:
00007fff`69f56a70 48ff2571210600  jmp     qword ptr [KERNEL32!_imp_GetSystemTimeAsFileTime (00007fff`69fb8be8)] ds:00007fff`69fb8be8={KERNELBASE!GetSystemTimeAsFileTime (00007fff`685bd100)}
8:071> gu
chrome!ChromeMain+0x867:
00007ffe`f05e5817 4c89f0          mov     rax,r14
8:071> gu
chrome!ChromeMain+0x6b3:
00007ffe`f05e5663 4889f0          mov     rax,rsi
8:071> gu
chrome!RelaunchChromeBrowserWithNewCommandLineIfNeeded+0xae2056:
00007ffe`f492cea6 488b0e          mov     rcx,qword ptr [rsi] ds:00000038`4bffdcf0=002f176961bc531f
8:071> gu
pepflashplayer!IAEModule_IAEKernel_UnloadModule+0x8863a3:
00007fff`14f86f03 f20f5905a5ea1800 mulsd   xmm0,mmword ptr [pepflashplayer!curl_share_strerror+0x134ee0 (00007fff`151159b0)] ds:00007fff`151159b0=408f400000000000
8:071> gu
pepflashplayer!PPP_ShutdownBroker+0x19ef45:
00007fff`13db35d5 0f28f0          movaps  xmm6,xmm0

原来chrome.dll中的上层调用,来自pepflashplayer.dll。

所以是flash.dll从chrome.dll中获取时间,到自己内部做判断。奇怪,它自己读时间不简单嘛?

4、时间校验逻辑分析

基址信息

00007ff6`14d70000 00007ff6`14fa0000   chrome_exe
00007ffe`f05e0000 00007ffe`f9a5c000   chrome
00007fff`13b50000 00007fff`15ad4000   pepflashplayer

GetSystemTimeAsFileTimeStub函数的上层调用函数偏移计算:

内存中chrome.dll的获取时间函数地址:00007ffef05e5817
内存中chrome.dll的基址:00007ffef05e0000
IDA中chrome.dll的基址:180000000
IDA中chrome.dll的获取时间函数地址:00007ffef05e5817-00007ffef05e0000+180000000=180005817

所以GetSystemTimeAsFileTimeStub函数的上层调用位于chrome.dll的sub_180005680函数
1610976127_60058b7f5a045ef8acaa1.png
继续追溯,上层调用位于pepflashplayer.dll的sub_181436EF0函数
1610976145_60058b9144502799e4126.png
上层调用位于pepflashplayer.dll的sub_180262FD0函数
1610976159_60058b9f422ff7bf1d6ce.png
比对参数就是qword_1815F8468,数值写死
1610976176_60058bb0d3cbb6b34d933.png

分析总结

程序流程
1610976201_60058bc93b75ac50c339d.png
时间校验流程
1610976219_60058bdb41b45e5d80619.png

思考

时间校验逻辑中的对比数据,硬编码在dll中,直接修改该数据足够大,是否能绕过该check呢?

POC测试

1、定位pepflashplayer.dll中的时间戳硬编码位置: 40 46 3E 6F 77 42
1610976289_60058c2101eece6e3a8c0.png
2、修改该时间戳硬编码,足够大:FF FF FF FF FF 42
1610976344_60058c5895b8182ae0124.png
3、重启chrome,poc生效,成功

结论

Adobe Flash Player的过期封禁策略,是通过pepflashplayer.dll调用chrome.dll获取系统时间戳,与本地硬编码的时间戳做对比,实现过期无法渲染的逻辑。

有三种方式可以绕过上述校验逻辑:

1、hook上述check函数,修改读取到的系统时间戳;
2、时间戳对比结果值存储于寄存器al,修改该寄存器的值;
3、修改pepflashplayer.dll中的时间戳硬编码,flash未对dll做防篡改校验;

原文作者:vinegar


文章标题:Adobe Flash过期封禁策略技术分析及应对方法
如果文中内容侵犯了您的权益,请及时与博主取得联系进行删除!
本站文章未经许可禁止转载,本文地址:https://blog.wanvale.com/archives/324/

Archives QR Code Tip
QR Code for this page
Tipping QR Code