完美的错误:在Flash中使用类型混淆。 第一部分

你好! 明天我们将在“逆向工程”课程的新小组中上课。 传统上,我们与您分享有关该主题的有用材料的翻译。 走吧

对于某些攻击者来说,利用该漏洞非常可靠非常重要。 在具有已知平台和版本Flash的系统上启动时,它应始终导致代码执行。 要创建它,您可以使用特别高质量的错误。 本文介绍了这些错误之一的使用,以及使其特别适合可靠操作的因素。



虫子

CVE-2015-3077 -Adobe Flash ButtonMovieClip过滤器设置器中的类型混淆问题,使您可以将任何类型的过滤器与其他类型混淆。 我在2015年12月上旬进行了报告,并在5月修复了该问题。 发生此错误是因为破解者可以覆盖用于初始化过滤器对象的构造函数。 重现此问题的示例代码如下:



由于使用了[]运算符,因此该代码有些混乱,这在Flash CS中进行编译是必需的。 逻辑上等效的代码(不是编译的事实)如下:



此代码将对象的过滤器字段设置为:Button或MovieClip为BlurFilter,然后将其直接存储在Flash中。 然后,ConvolutionFilter构造函数将覆盖BlurFilter构造函数。 之后,将调用getter并创建一个ActionScript对象来存储原始的BlurFilter。 但是,构造函数已经被覆盖,因此调用了ConvolutionFilter。 这将产生一个ConvolutionFilter类型的对象,该对象受原始BlueFilter的返回支持。

最终,可以访问(读取和写入)ConvolutionFilter字段,就像它们属于BlurFilter一样。 对于其他任何类型的过滤器也是如此。 这为利用提供了广泛的操作方法。

下图显示了在64位Linux中使用此漏洞可能使原始对象在内存中的位置。



在两种情况下,指针相当于整数和可以操纵的浮点数。 这意味着可以直接读取和写入指针。 另外,由于对象的字段根据类的定义按大小排序和排序,因此它们始终位于可预测的位置,因此写入和读取不会失败。 这些属性对于确保漏洞利用的可靠性很重要。

利用

由于利用此问题需要反复运行类型混淆,因此我从创建用于类型混淆的实用程序函数FilterConfuse.confuse开始 。 它还可以整理事情:将ActionScript筛选器构造函数返回到其正常状态,以反复调用易受攻击的函数,而不会影响该函数本身之外的ActionScript行为。
第一步是通过定义虚拟功能表(简称vtable)的地址来绕过ASLR。 理想的方法是将一个对象与一个vtable以及一个对象重叠,该对象中有一个重叠于vtable的元素可以被操纵。 但是所有过滤器对象的vtable具有相同的偏移量。 相反,我使用了DisplacementMapFilter中的BitmapData对象来确定vtable地址。

为了确定对象的BitmapData内存中的位置,我将DisplacementMapFilter与BevelFilter混淆了。 这使存储在DisplacementMapFilter中的BitmapData指针与BevelFilter的颜色属性( shadowColorshadowAlphahighlightColorHighlightAlpha )对齐。 这些属性由两个32位整数(在上面和下面显示为scolor和hcolor)支持,并且color属性访问每个整数的24位,而alpha属性访问高8位。 如果阅读这些属性并使用位算术将它们组合,则可以提取对象的直接BitmapData地址。



然后,您需要从BitmapData对象的顶部读取vtable。 为此,我使用了ConvolutionFilter对象的matrix属性。 它存储为指向浮点数数组的指针,在设置属性时将在该数组下分配内存,并且在收到属性时将返回包含这些数字的ActionScript数组。 通过将矩阵指针设置为BitmapData对象,可以从内存中以浮点数数组的形式读取此对象的内容。

要设置指针,我将ConvolutionFilter对象与DisplacementMapFilter对象(与上面使用的DisplacementMapFilter不同)相混淆,并在mapPoint属性中设置了对象的BitmapData的位置。 mapPoint属性是一个点,其整数坐标x和y(下图中的p_x和p_y)对应于ConvolutionFilter中的矩阵指针,这使设置此值变得容易。 之后,可以使用ConvolutionFilter对象中的矩阵数组从BitmapData对象中读取vtable(值得注意的是,必须将该对象与DisplacementBitmapFilter混淆,然后再与ConvolutionFilter混淆)。



此时,由于使用浮点数,维护漏洞利用程序的可靠性变得更加困难。 从ConvolutionFilter矩阵中将值vtable_low和vtable_high读取为浮点数,因为这是数组类型。 但是,不幸的是,并非每个有效的指针值都是一个有效的浮点数。 这意味着读取该值将返回NaN,或更糟糕的是,它不是一个完全正确的数值。

理想情况下,要解决此问题,您需要通过getter访问vtable_low和vtable_high,该方法将它们解释为整数,但这不是因为过滤器元素由于其功能而通常是浮动的。

幸运的是,AS2虚拟机足够懒惰来解释浮点数-仅在ActionScript中对其执行操作时,它才将值转换为浮点数。 除了特殊的运算(如算术运算)外,原始运算通常不需要解释。 这意味着,当将浮点数从矩阵数组复制到vtable_low或vtable_high时,即使它对float无效,它也会将其值保留在内存中,而在ActionScript中未使用复制该变量的变量或在本机中执行算术运算代码。 因此,如果变量的值立即与支持整个32位值范围的另一种类型(例如int)混淆,则可以保证它与矩阵数组的内存中的原始值相同。 因此,为了避免利用中的不可靠性,在操作ActionScript中的浮点数之前必须进行类型混淆。

为此,我编写了一个转换类FloatConverter ,在过滤器中使用类型混淆来实现整数到浮点和浮点到整数的功能。 它将矩阵 ColorMatrixFilter属性(不要与ConvolutionFilter矩阵属性混淆)混淆,该属性是一组内置浮点,具有访问不同int字节的GlowFilter coloralpha属性。



这样,您可以实现float到int的可靠转换,但是不幸的是,这在相反的方向上不能可靠地工作。 要在ActionScript中访问ColorMatrix中的颜色​​数组,即使您仅访问第一个颜色数组,也要复制整个数组。 复制数组时,每个元素都将转换为Number,其中包括对指针的调用(例如,调用对象的valueOf)。 由于颜色数组是整个GlowFilter类中最长的,因此与GlowFilter混淆时,它会堆积。 这意味着可能会发生此堆中未知值的转换,如果在转换为Number时引用无效指针,则会导致崩溃。 因此,对于从int到float的实现,我使用了另一个混淆ConvolutionFilter和DisplacementMapFilter实现了一个float转换器,这是直接转换,不会导致堆中的未知值。



这解决了由于从堆中访问不熟悉的值而导致崩溃的问题,但是不幸的是,在此漏洞利用中,还有另一个与浮点数相关的可靠性问题。 这是由于ConvolutionFilter矩阵获取器的实现所致。 ActionScript 2中的所有数值均为Number类型,它是整数和双精度数的指针的并集。 原始的ConvolutionFilter矩阵存储为浮点数数组,但在调用矩阵getter时将其复制到ActionScript数组以保留访问权限,并且在此过程中将值转换为double。 然后,当调用浮点转换器时,它们将转换回浮点数。

将浮点数强制转换为双精度数,反之亦然,通常会保存其值,但如果浮点值为SNaN,则不会。 根据浮点规范,有两种类型的NaN:静默NaN(QNaN)和信号NaN(SNaN)。 当出现QNaN时,什么也没有发生,但是SNaN在某些情况下会引发浮点异常。 在x86中,将double转换为float始终会导致QNaN(即使double源自SNaN)也可以避免意外的异常。

因此,如果指针的低位是SNaN,它将被转换为QNaN,这意味着第一位(第一个尾数位,第22位)将被置位。 读取vtable时可以避免此问题-无需对齐即可确认当前值的情况下读取包含第一位的指针的第三字节。 因此,代码将不对齐地读取(在再次读取vtable并将Bitmap指针增加一之后),如果浮点数最终为SNaN,则调整int值。

使用上述的浮点转换器,可以将vtable地址转换为整数。 现在,您需要获取使用此地址执行的代码。 移动指令指针的一种简单方法是覆盖对象的vtable(或指向具有vtable的对象的指针)。 这可以通过混淆ConvolutionFilter矩阵数组和DisplacementFilter指针的BitmapData来完成。

第一部分结束。 翻译的第二部分将在稍后发布,现在我们正在等待您的评论,我们邀请所有人参加OTUS 逆向工程课程。

Source: https://habr.com/ru/post/zh-CN442640/


All Articles