在本系列关于注释型语言底层攻击面的第一篇文章中,我们领会到,纵然在Javascript、Python和Perl等注释型语言的焦点实现中,内存平安也不是自作掩饰的。

在本文中,我们将加倍深入地探讨,在通过外部函数接口(Foreign Function Interface,FFI)将基于C/C++的库“粘合”到注释语言的历程中,平安破绽是若何发生的。正如我们之前所讨论的,FFI充当用两种差别语言编写的代码之间的接口。例如,使一个基于C语言的库可用于Javascript程序。

FFI卖力将编程语言A的工具翻译成编程语言B可以使用的器械,反之亦然。为了实现这种翻译,开发人员必须编写特定于语言API的代码,以实现两种语言之间的往返转换。这通常也被称为编写语言绑定。

从攻击者的角度来看,外部语言绑定代表了一个可能的攻击面。当处置一个从内存平安语言翻译成内存不平安语言(如C/C++)的FFI时,开发者就有可能引入内存平安破绽。

纵然高层的语言被认为是内存平安的,同时目的外部代码也经过了严酷的平安审查,然则,在两种语言之间架起桥梁的代码中,仍可能潜伏着可行使的破绽。

在这篇文章中,我们将仔细研究两个这样的破绽,我们将一步步地领会攻击者若何评估你的代码的可行使性的。本文的目的是提高读者对exploit开发历程的明白,而不仅仅是针对一个详细的案例,而是从观点的角度来明白。通过领会exploit开发人员若何思索您的代码,帮您确立防御性的编程习惯,从而编写出更平安的代码。

在我们的案例研究中,我们将考察两个看起来异常相似的bug,然而只有一个是bug,而另一个则是一个平安破绽。两者都存在于绑定Node.js包的C/C++代码中。

node-sass

Node-sass是一个库,它将Node.js绑定到LibSass(一款盛行的样式表预处置器Sass的C版本)。虽然node-sass最近被弃用了,但它每周仍有500万次以上的下载量,以是,它是一个异常有价值的审计工具。

当阅读node-sass绑准时,我们注重到以下代码模式:

 int indent_len = Nan::To
    Nan::Get(
        options,
        Nan::New("indentWidth").ToLocalChecked()
    ).ToLocalChecked()).FromJust();
 
 
[1]
  ctx_w->indent = (char*)malloc(indent_len + 1);
 
 
  strcpy(ctx_w->indent, std::string(
[2]
    indent_len,
    Nan::To
        Nan::Get(
            options,
            Nan::New("indentType").ToLocalChecked()
        ).ToLocalChecked()).FromJust() == 1 ? '\t' : ' '

在[1]处,我们注重到一个受控于用户输入的32位整数值被用于内存分配。若是该用户提供的整数为-1,则整数算术表达式indent_len + 1的值将酿成0。在[2]处,原始负值用于建立由indent_len字符组成的制表符或空格字符串,其中indent_len值为负,现在将酿成一个相当大的正值,由于std::string组织函数期望吸收无符号的长度参数,其类型为size_t。

在 *** API级别,我们注重到indentWidth的检索方式如下所示:

/**
 * Get indent width
 *
 * @param {Object} options
 * @api private
 */
 
 
function getIndentWidth(options) {
  var width = parseInt(options.indentWidth) || 2;
 
 
  return width > 10 ? 2 : width;
}

此处的目的是确保indentWidth >= 2或 <= 10,但现实上这里仅检查了上界,而且parseInt允许我们提供负值,例如: 

var sass = require('node-sass')
var result = sass.renderSync({
        data: `h1 { font-size: 40px; }`,
        indentWidth: -1
});

这将触发一个整数溢出,从而导致分配的内存不足,并进一步导致后续的内存被损坏。

为领会决这个问题,node-sass应该确保在将用户提供的indentWidth值传递给底层绑定之前,先检查该值的下界和上界。

周全地检查输入,并明确地将它们的取值局限限制在对程序逻辑有意义的局限内,这将很好地辅助您养成一种通用的防御性编程习惯。

以是我们来总结一下。这里的bug模式是什么?整数溢出,导致堆分配不足,厥后的内存填充可能会损坏相邻的堆内存。听起来确实值得分配CVE,不是吗?

然而,虽然这个整数溢出确实会导致堆内存分配不足,但这个bug并不代表就是一个破绽,由于这个样式表输入很可能不是攻击者控制的,而且在任何堆损坏发生之前,都市抛出std::string异常。纵然发生了堆损坏,也只是一个异常有限的控制笼罩(借助于一个异常大的indent_len的制表符或空格字符),以是,现实被行使的可能性很低。

anticomputer@dc1:~$ node sass.js
terminate called after throwing an instance of 'std::length_error'
  what():  basic_string::_S_create
Aborted (core dumped)

结论:只是一个bug。 

那么,什么情形下攻击者才会对这样的bug感兴趣呢?攻击者能够对触发bug的输入施加影响。在这种情形下,不太可能有人为node-sass绑定提供受控于攻击者的输入。同时,内存损坏原语自己的控制能力也会异常有限。虽然确实存在这样的情形:纵然是异常有限的堆损坏也足以充分行使某个缺陷,但通常攻击者会更乐于追求具有某些控制权的情形,好比可以控制用于损坏内存的器械,或者可以控制笼罩的内存数目。更好是两者兼而有之。

在这种情形下,纵然std::string组织函数没有退出,攻击者也必须用空格或制表符举行大规模的笼罩,以控制历程。虽然这并非完全不可能,但考虑到对周围内存结构的足够影响和控制,可能性仍然偏低。

在这种情形下,我们通常可以通过回覆下面的三个问题,来举行一个简朴的可行使性“嗅觉测试”:

· 攻击者是若何触发这个bug的?

· 攻击者控制了哪些数据,控制到什么水平?

· 哪些算法受到攻击者控制的影响?

,

皇冠体育APP

:www.huangguan.us是一个开放皇冠 *** APP下载、皇冠会员APP下载、皇冠线路APP下载、皇冠登录APP下载的平台,皇冠体育APP上最新登录线路、新2皇冠网址更新最快,皇冠体育APP开放皇冠会员注册、皇冠 *** 开户等业务。

,

除此之外,可行使性主要取决于攻击者的目的、履历和资源。这些我们可能一无所知。除非您花了许多时间现实编写exploit,否则很难确定某个问题是否可行使。特别是当您的代码被其他软件使用时,即您编写的是库代码,或者是一个更大系统中的一个组件。在一个伶仃的环境中,某个错误看起来只是bug,在更大的局限内可能就是平安破绽。

虽然知识对于确定可行使性有很大的辅助,但在时间和资源允许的情形下,任何可以由用户控制(或影响)的输入触发的bug都是潜在的平安破绽,因此,将其视为平安破绽是异常明智的做法。

png-img

对于我们的第二个案例研究,我们将考察GHSL-2020-142。这个bug存在于提供libpng绑定的node.js png-img包中。

当加载PNG图像举行处置时,png-img绑定将使用PNGIMG::InitStorage函数来分配用户提供的PNG数据所需的初始内存。

void PngImg::InitStorage_() {
    rowPtrs_.resize(info_.height, nullptr);
[1]
    data_ = new png_byte[info_.height * info_.rowbytes];
 
 
[2]
    for(size_t i = 0; i < info_.height; ++i) {
        rowPtrs_[i] = data_ + i * info_.rowbytes;
    }
}

在[1]处,我们观察到为一个巨细为info_.height * info_.rowbytes的png_byte数组分配了响应的内存。其中,结构体成员height和rowbytes的类型都是png_uint_32,这意味着这里的整数算术表达式肯定是无符号32位整数运算。

info_.height可以直接作为32位整数从PNG文件提供,info_.rowbytes也可以从PNG数据派生。

这种乘法运算可能会触发整数溢出,导致data_内存区域分配不足。

例如,若是我们将info_.height设置为0x01000001,而info_.rowbytes的值为0x100,那么天生的表达式将是(0x01000001 * 0x100) & 0xffffffff ,其值为0x100。这样的话,data_将作为一个0x100巨细的png_byte数组来分配内存,这显著不够用。

随后,在[2]处,将使用行数据指针填充rowPtrs_array,这些指针指向所分配的内存区的界限之外,由于for循环条件是对原始的info_.height值举行操作的。

一旦现实的行数据被从PNG文件中读取,任何与data_区域相邻的内存都可能被攻击者控制的行数据笼罩,更高可达info_.height * info_.rowbytes字节,这给任何潜在的攻击者提供了大量可控的历程内存。

需要注重的是,凭据攻击者的意愿,可以通过不从PNG自己提供足够数目的行数据来提前住手笼罩,这时libpng错误例程就会启动。任何后续处置错误路径的程序逻辑都市在被损坏的堆内存上运行。

这很有可能导致一个高度受控(无论是内容照样巨细)的堆溢出破绽,我们的直觉是,这个bug可能是一个可行使的平安破绽。

下面,让我们往返答可行使性问题,以确定这个bug是否对攻击者具有足够的吸引力。

攻击者是若何触发该bug的?

这个bug是由攻击者提供的PNG文件触发的。攻击者可以完全控制在png-img绑定中作用于PNG的任何数据,并破除文件花样完整性检查所施加的任何限制。

由于攻击者必须依赖于加载的恶意PNG文件,我们可以假设任何行使逻辑都可能必须包罗在这个单一的PNG文件中。这意味着,攻击者与目的Node.js历程频频交互的机“可能”更少,例如,实行信息泄露,以辅助后续的破绽行使历程绕过任何系统级别的缓解措施,如地址空间结构随机化(ASLR)。

我们说“可能”,是由于我们无法展望png-img的现实使用情形。换句话说,也可能存在这样的使用情形:存在可重复的交互机遇,来触发该bug或进一步辅助行使该bug。

攻击者能够控制哪些数据,控制到什么水平?

攻击者可以提供所需的height和rowbytes变量,以便对整数运算和后续的整数封装(integer wrap)举行精致控制。被封装的值用于确定data_数组的最终分配内存的巨细。它们也可以通过PNG图像自己提供完全受控的行数据,这些数据通过rowPtrs数组中的越界指针值填充到越界内存中。他们可以通过提前终止提供的行数据,精致控制这个攻击者提供的行数据有多少被填充到内存中。

简而言之,攻击者可以通过精致控制内容和长度来笼罩任何与data_相邻的堆内存。

哪些算法会受到攻击者控制的影响?

由于我们处置的是堆溢出,攻击者的影响扩展到任何涉及被损坏的堆内存的算法。这可能涉及Node.js注释器代码、系统库代码,固然另有绑定代码和任何相关库代码自己。

小结

在本文中,我们将深入地探讨,在通过外部函数接口(Foreign Function Interface,FFI)将基于C/C++的库“粘合”到注释语言的历程中,平安破绽是若何发生的。由于篇幅过长,我们将分为多篇举行先容,更多精彩内容,敬请期待!

本文翻译自:​https://securitylab.github.com/research/now-you-c-me-part-two: 鄂尔多斯新闻网声明:该文看法仅代表作者自己,与本平台无关。转载请注明:usdt无需实名买入卖出(caibao.it):深入考察注释型语言背后隐藏的攻击面,Part 2(一)
发布评论

分享到:

电银付小盟主(dianyinzhifu.com):嫦娥五号完成月面自动采样封装
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。