[论文翻译与解读] Hacking Blind
Posted 漫小牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[论文翻译与解读] Hacking Blind相关的知识,希望对你有一定的参考价值。
文章目录
- Hacking Blind
参考文献:
Blind Return Oriented Programming (BROP) Attack 攻击原理
Hacking Blind
Andrea Bittau, Adam Belay, Ali Mashtizadeh, David Mazi`eres, Dan Boneh
Stanford University
摘要/Abstract
英文 | 中文 |
---|---|
Abstract—We show that it is possible to write remote stackbuffer overflow exploits without possessing a copy of the target binary or source code, against services that restart after a crash. This makes it possible to hack proprietary closed-binary services, or open-source servers manually compiled and installed from source where the binary remains unknown to the attacker. Traditional techniques are usually paired against a particular binary and distribution where the hacker knows the location of useful gadgets for Return Oriented Programming (ROP). Our Blind ROP (BROP) attack instead remotely finds enough ROP gadgets to perform a write system call and transfers the vulnerable binary over the network, after which an exploit can be completed using known techniques. This is accomplished by leaking a single bit of information based on whether a process crashed or not when given a particular input string. BROP requires a stack vulnerability and a service that restarts after a crash. We implemented Braille, a fully automated exploit that yielded a shell in under 4,000 requests (20 minutes) against a contemporary nginx vulnerability, yaSSL + mysql, and a toy proprietary server written by a colleague. The attack works against modern 64-bit Linux with address space layout randomization (ASLR), no-execute page protection (NX) and stack canaries. | 摘要 — 针对崩溃后重新启动的情况,在没有获得二进制文件和源代码的情况下,编写远端的栈缓冲区溢出exp也是可能的。这种方法,有利于pwn掉未开放二进制的服务,或手工编译的开源服务,在这两种情况下,攻击者对二进制文件均是未知的。传统的技术通常可通过软件发布找到对应的二进制,在这种情况下,黑客知道面向返回编程(Return-orientedprogramming,ROP)的有用gadget的位置。与传统技术不同的是,我们的BROP攻击会远程找到足够的ROP gadgets来执行write系统调用,并通过网络发送给存在漏洞的二进制文件,然后可以使用已知技术完成攻击。实现方式是:输入特定的字符串时,服务是否崩溃来确定1个bit的泄露。BROP成功实施的前提是存在一个stack漏洞,并且crash后服务会重启。我们实现了一个全自动化漏洞利用工具Braille。针对nginx漏洞(yaSSL+MySQL),能够在20分钟内不少于4000次请求,拿到一个shell。该攻击适用于ASLR、NX和Canary保护的现代64位Linux。 |
解读: | |
(1)从本地ROP到远端BROP,类似于SQL盲注。 | |
(2)成功实施要求有两点:一是存在stack溢出漏洞,二是服务器崩溃后会自动重启。 | |
(3)可绕过三种保护机制:ASLR、NX和Canary。 | |
(4)20分钟内4000次请求,平均每分钟200次请求,说明适用于一些轻量级的服务,在crash后能马上回复执行,BROP对于重启时间较长的服务并不适用。 |
1 引言/Introduction
序号 | 英文 | 中文 |
---|---|---|
1 | Attackers have been highly successful in building exploits with varying degrees of information on the target. Open-source software is most within reach since attackers can audit the code to find vulnerabilities. Hacking closed-source software is also possible for more motivated attackers through the use of fuzz testing and reverse engineering. In an effort to understand an attacker’s limits, we pose the following question: is it possible for attackers to extend their reach and create exploits for proprietary services when neither the source nor binary code is available? At first sight this goal may seem unattainable because today’s exploits rely on having a copy of the target binary for use in Return Oriented Programming (ROP) [1]. ROP is necessary because, on modern systems, non-executable (NX) memory protection has largely prevented code injection attacks. | 攻击者在利用目标机上不同信息构建漏洞方面,已取得了很大的成功。由于攻击者可以通过审计代码来发现漏洞,因此基于开源软件发现漏洞较为便捷并利于实施。同时,通过使用模糊测试和逆向工程,更有想法的攻击者也可以攻击闭源软件。为了理解攻击者的局限性,我们提出了以下问题:**当源代码和二进制代码都不可用时,攻击者能否在现有攻击能力的基础上,对专有服务进行攻击?**乍一看,这个目标似乎不可能实现,因为现在的漏洞利用依赖于在面向返回编程(Return-orientedprogramming,ROP)中使用目标二进制文件的副本[1]。在现代系统中,不可执行(NX)内存保护在很大程度上阻止了代码注入攻击,因此,ROP是必要的。 |
2 | To answer this question we start with the simplest possible vulnerability: stack buffer overflows. Unfortunately these are still present today in popular software (e.g., nginx CVE-2013-2028 [2]). One can only speculate that bugs such as these go unnoticed in proprietary software, where the source (and binary) has not been under the heavy scrutiny of the public and security specialists. However, it is certainly possible for an attacker to use fuzz testing to find potential bugs through known or reverse engineered service interfaces. Alternatively, attackers can target known vulnerabilities in popular open-source libraries (e.g., SSL or a PNG parser) that may be used by proprietary services. The challenge is developing a methodology for exploiting these vulnerabilities when information about the target binary is limited. | 为了回答这个问题,我们从最简单的漏洞开始:堆栈缓冲区溢出。不幸的是,堆栈缓冲区溢出仍然普遍存在于当前的软件中。 人们只能推测,像这样的bug在专有软件中是不会被注意到的,因为源代码(和二进制代码)并没有受到公众和安全专家的严格审查。但是,攻击者当然有可能通过已知的或逆向得到的服务接口,使用模糊测试来发现潜在的bug。或者,攻击者可以攻击由专有服务使用的开源库(例如SSL或PNG解析器)中的已知漏洞。当前的挑战在于开发一种方法,在目标二进制文件的信息受限时能够利用这些漏洞。 |
3 | One advantage attackers often have is that many servers restart their worker processes after a crash for robustness. Notable examples include Apache, nginx, Samba and OpenSSH. Wrapper scripts like mysqld_safe.sh or daemons like systemd provide this functionality even if it is not baked into the application. Load balancers are also increasingly common and often distribute connections to large numbers of identically configured hosts executing identical program binaries. Thus, there are many situations where an attacker has potentially infinite tries (until detected) to build an exploit. | 攻击者具备的一个主要优势是:许多服务器在崩溃后重启以增强健壮性。比较典型的例子有Apache、nginx、Samba和OpenSSH。像mysqld_safe.sh脚本或systemd守护进程也提供了这种功能,即使它没有直接指向某个应用程序。负载平衡器也越来越常见,通常将连接分发给大量执行相同二进制文件的配置相同的主机。因此,在许多情况下,攻击者可能会无限次尝试(直到被检测到)构建攻击。 |
4 | We present a new attack, Blind Return Oriented Programming (BROP), that takes advantage of these situations to build exploits for proprietary services for which both the binary and source are unknown. The BROP attack assumes a server application with a stack vulnerability and one that is restarted after a crash.The attack works against modern 64-bit Linux with ASLR (Address Space Layout Randomization), non-executable (NX) memory, and stack canaries enabled. While this covers a large number of servers, we can not currently target Windows systems because we have yet to adapt the attack to the Windows ABI. The attack is enabled by two new techniques: 1) Generalized stack reading: this generalizes a known technique, used to leak canaries, to also leak saved return addresses in order to defeat ASLR on 64-bit even when Position Independent Executables (PIE) are used. 2)Blind ROP: this technique remotely locates ROP gadgets. | 我们提出了一种新的攻击,即面向盲返回编程(BROP),它利用这些情况来构建对二进制和源程序都未知的专有服务的攻击。BROP攻击假设服务器应用程序具有栈溢出漏洞,并且在崩溃后重新启动。该攻击适用于支持ASLR(地址空间布局随机化)、不可执行(NX)内存和堆栈金丝雀的现代64位Linux。虽然攻击覆盖了大量的服务,由于攻击并不适用于Windows ABI,所以目前还无法对Windows系统实施攻击。攻击成功实施需要两类新的技术: 1) 通用堆栈读取技术:将一种已知技术通用化处理,用于泄漏canaris,同时也能泄漏保存的返回地址,以便绕过ASLR甚至PIE。 2)BROP:这种技术可以远程定位ROP gadgets。 |
5 | Both techniques share the idea of using a single stack vulnerability to leak information based on whether a server process crashes or not. The stack reading technique overwrites the stack byte-by-byte with possible guess values, until the correct one is found and the server does not crash, effectively reading (by overwriting) the stack. The Blind ROP attack remotely finds enough gadgets to perform the write system call, after which the server’s binary can be transferred from memory to the attacker’s socket. At this point, canaries, ASLR and NX have been defeated and the exploit can proceed using known techniques. | 这两种技术具有相同的思想:使用栈溢出漏洞泄漏信息,并取决于服务进程是否崩溃。堆栈读取技术使用可能的猜测值逐字节覆盖堆栈,直到找到正确的值,而此时服务不会崩溃。BROP攻击可以远程找到足够的gadgets来执行write系统调用,而后服务器的二进制文件可以从内存传输到攻击者的socket。这样就能绕过canary,ASLR和NX保护,并利用现有的攻击技术进行漏洞利用。 |
6 | The BROP attack enables robust, general-purpose exploits for three new scenarios: 1)Hacking proprietary closed-binary services. One may notice a crash when using a remote service or discover one through remote fuzz testing. 2)Hacking a vulnerability in an open-source library thought to be used in a proprietary closed-binary service. A popular SSL library for example may have stack vulnerability and one may speculate that it is being used by a proprietary service. 3)Hacking an open-source server for which the binary is unknown. This applies to manually compiled installations or source-based distributions such as Gentoo. | BROP攻击可针对以下三种新场景进行强大的通用攻击: 1)入侵专有的封闭二进制服务。使用远程服务时可能会注意到崩溃,或者通过远程模糊测试发现崩溃。 2)入侵一个开源库中的漏洞,该库被认为用于专用的不开放二进制的服务。例如,一个SSL库可能有堆栈漏洞,可以推测它正被一个专有服务使用。 3)入侵一个二进制未知的开源服务器。这适用于手动编译的安装或基于源代码的发行版,如Gentoo。 |
7 | We evaluate all three scenarios. Ideally, for the first scenario we would test our techniques against production services for which we hold no information about the software, but we are constrained for obvious legal reasons. To simulate such a scenario, we tested against a toy proprietary service a colleague of ours wrote for which we had no information about source, binary, or functionality. For the second scenario, we target a real vulnerability in the yaSSL library[3]. This library was used by MySQL in past and we use that as the host application. For the third scenario, we target a recent (2013) vulnerability in nginx [2] and write a generic exploit that does not depend on a particular binary. This is particularly useful as the exploit will work on any distribution and vulnerable nginx version without requiring an attacker to write a specific exploit for each distribution and version combination (as is done today). | 我们对三种场景进行评估。理想情况下,对于第一个场景,我们将针对服务测试我们的技术,对于这些服务,我们没有关于软件的信息,但是由于明显的法律原因,我们受到限制。为了模拟这样的场景,我们测试了一个小型专有服务,该服务由我们的一个同事编写,我们没有关于源代码、二进制文件或功能的信息。对于第二种场景,漏洞利用的目标是yaSSL库中的一个真实的漏洞。这个库在过去被MySQL使用,我们使用它作为宿主应用程序。对于第三个场景,我们针对nginx[2]中最近(2013年)的一个漏洞,并编写一个不依赖于特定二进制文件的通用攻击。这种通用性特别有用,因为该漏洞可用于任何发行并易受攻击的nginx版本,而无需攻击者为每个发行版编写特定的漏洞。 |
8 | We implemented a new security tool, Braille, that makes BROP attacks highly automated. Braille can yield a shell on a vulnerable server in approximately 4,000 requests, a process that completes in under 20 minutes and, in some situations, in just a few minutes. An attacker need only provide a function that constructs a request of a minimum length to crash the server and append a string provided by Braille. The function must also return a single bit based on whether the server crashes or not. | 我们实现了一个新的安全工具Braille,使BROP攻击高度自动化。盲文可在一个存在漏洞的服务器上20分钟内产生大约4000个请求的shell,在某些情况下,只需几分钟。攻击者只需提供构造最小长度请求的函数即可使服务器崩溃并附加Braille提供的字符串。函数还必须根据服务器是否崩溃返回一个bit值。 |
9 | Our contributions are: 1) A technique to defeat ASLR on servers (generalized stack reading). 2) A technique to remotely find ROP gadgets (BROP) so that software can be attacked when the binary is unknown. 3)Braille: a tool that automatically constructs an exploit given input on how to trigger a stack overflow on a server. 4)The first (to our knowledge) public exploit for nginx’s recent vulnerability, that is generic, 64-bit, and defeats (full/PIE) ASLR, canaries and NX. 5) Suggestions for defending against BROP attacks. In summary, ASLR must be applied to all executable segments (PIE) and re-randomization must occur after each crash (at odds with fork-only servers). Holding the bin ary from the attacker or purposefully altering it may not be an effective security countermeasure. | 我们的贡献是: 1) 一种在服务器上绕过ASLR的技术。 2) 一种可远程发现ROP gadgets的技术,使得在二进制未知的情况下实施攻击。 3) Braille:自动构造漏洞利用的一种工具,通过给定的输入来触发服务器上的堆栈溢出。 4)据我们所知,这是针对nginx近期漏洞的第一个公开的exp,这是一种通用的64位exp,可绕过(full/PIE)ASLR、canaris和NX。 5) 给出了防御BROP攻击的建议。总的来说,ASLR必须应用于所有可执行段(PIE), 并且每次崩溃后必须进行重新随机化(与仅使用fork的服务器不一致)。从攻击者手中拿住垃圾箱或故意更改垃圾箱可能不是有效的安全对策。防止攻击者拿到二进制文件或故意更改二进制文件可能并不是有效的安全对策。 |
2 缓冲区溢出简史/Brief History of Buffer Overflows
序号 | 英文 | 中文 |
---|---|---|
1 | Buffer overflows are a classic vulnerability with a long history of exploits [4]. Conceptually, they are relatively easy to attack. For instance, a vulnerable program might read data from the network into a buffer. Then, assuming the program lacks sufficient bounds checks to limit the size of the incoming data, an attacker could overwrite memory beyond the end of the buffer. As a result, critical control-flow state, such as return addresses or function pointers, could be manipulated. Stack buffer overflows tend to be especially dangerous because return addresses are implicitly nearby in memory due to function calling conventions. However, attacks that target buffers on the heap are also viable [5]. | 在很长的漏洞历史当中,缓冲区溢出是一类经典的漏洞。从概念上讲,这种漏洞更容易受到攻击。例如,易受攻击的程序可能会将数据从网络读入缓冲区。然后,假设程序缺少足够的边界检查来限制传入数据的大小,攻击者可能会覆盖缓冲区末尾以外的内存。这样,就可以操纵关键控制流状态,例如返回地址或函数指针。堆栈缓冲区溢出往往特别危险,根据函数调用约定,返回地址隐式地存在于内存附近。同时,针对堆上缓冲区的攻击也是可行的[5]。 |
2 | In the early days of stack buffer overflows, it was common for an attacker to include malicious code as part of the payload used to overflow the buffer. As a result, the attacker could simply set the return address to a known location on the stack and execute the instructions that were provided in the buffer. Such “code injection” attacks are no longer possible on contemporary machines because modern processors and operating systems now have the ability to mark data memory pages as non-executable (e.g., NX on x86). As a result, if an attacker tries to run code on the stack, it would only cause an exception. | 在堆栈缓冲区溢出的早期,攻击者通常会将恶意代码作为用于溢出缓冲区的有效负载的一部分。因此,攻击者可以简单地将返回地址设置为堆栈上的已知位置,并执行缓冲区中提供的指令。这种“代码注入”攻击在现代机器上已不可行,因为现代处理器和操作系统现在能够将数据内存页标记为不可执行(例如x86上的NX)。因此,如果攻击者试图在堆栈上运行代码,则只会导致异常。 |
3 | An innovative technique, known as return-oriented programming (ROP) [1], was developed to defeat defenses based on non-executable memory. It works by linking together short code snippets already present in the program’s address space. Such code snippets, called gadgets, can be combined to form arbitrary computation. As a result, attackers can use ROP to gain control of programs without any dependence on code injection. Simpler variations of ROP are sometimes possible. For example, with return-to-libc attacks, a high-level library function can be used as the return address. In particular, the system() function is useful for attackers because it can run arbitrary shell code with only a single argument [6]. These attacks were very effective on 32-bit systems where arguments were passed on the stack, already under control of the attacker. On 64-bit systems, arguments are passed in registers, so additional gadgets are needed to populate registers. | 一种被称为面向返回编程(return-orientedprogramming,ROP)[1]的创新技术被开发出来,可用来绕过NX防御。它的工作原理是将程序地址空间中已有的短代码片段链接在一起。这样的代码片段称为gadgets,可以进行组合以满足任意需求的计算。因此,攻击者可以使用ROP获得对程序的控制,而不依赖于代码注入。一些ROP变种有时也是可行的。例如,对于return-to-libc攻击,可以使用高级库函数作为返回地址。system()函数对攻击者非常有用,因为它只需用一个参数就能运行任意shell代码[6]。这些攻击在32位系统上非常有效,32位系统中,参数在堆栈上传递,并且可受攻击者的控制。在64位系统中,使用寄存器传递参数,因此需要额外的gadget来填充寄存器。 |
4 | Address space layout randomization (ASLR) [7], [8] was introduced as an additional defense against buffer overflow attacks. It works by randomizing the location of code and data memory segments in the process address space. In many implementations code segment randomization is only applied to libraries, but full address space randomization is also possible. ASLR creates a major challenge for attackers because it makes the address locations of code (or even the stack) impossible to predict in advance. Unfortunately, on 32-bit platforms, ASLR is constrained by the number of available bits (usually 16) for randomization. As a result, brute-force attacks can be quite effective [9]. However, on 64-bit platforms there are typically too many random bits for brute-forcing to be feasible. In such cases, ASLR can still be circumvented, but only when combined with a vulnerability that leaks information about the address space layout, such as a format string [10]. | 地址空间布局随机化(ASLR)[7],[8]是缓冲区溢出攻击的另一种防御机制。它的工作原理是随机化进程地址空间中代码段和数据段的位置。在许多实现中,代码段随机化只应用于库,但是完全地址空间随机化也是可能的。ASLR给攻击者带来了很大的挑战,因为它使代码(甚至堆栈)的地址位置无法提前预测。不幸的是,在32位平台上,ASLR受到随机化可用位数(通常为16位)的限制。因此,暴力攻击对32位ASLR非常有效[9]。然而,在64位平台上,通常有太多的随机位,使得暴力攻击无法奏效。在这种情况下,只有与泄漏地址空间布局信息的漏洞(如格式字符串[10])结合使用时才能绕过ASLR。 |
5 | In addition to the larger address space for ASLR and the need to locate additional gadgets to fill argument registers, 64-bit systems present a third complication for attackers. . Because the architecture limits virtual addresses to 48-bits, user-level memory pointers are required to contain zero-valued bytes. These zeros cause early termination of overflows relying on string operations such as strcpy(). | ASLR除了有更大的地址空间和需要定位gadget来填充参数寄存器之外,64位 系统还为攻击者带来了第三个复杂问题。**由于该体系结构将虚拟地址限制为48位,因此需要用户级内存指针包含零值的字节。**这些零值会导致依赖字符串的操作(如strcpy())提前终止溢出。 |
6 | Canaries [11] are another common defense against buffer overflow attacks. Canaries cannot prevent buffer overflows, but they can detect them retroactively and terminate the program before an attacker can influence control flow. For example, with stack canaries, a secret value that was determined in advance is placed just before each saved frame pointer and return address. Then, when a function returns, the secret value is checked to make sure it has not changed. This can prevent stack buffer overflows from being exploited because an attacker must correctly overwrite the secret value in order for the program to actually use an overwritten return address. However, just as with ASLR, canaries can be defeated through an additional vulnerability that leaks information about the secret value. The layout of stack memory can be an important consideration for canary implementations. The layout of stack memory can be an important consideration for canary implementations. One common approach is to place all buffers at the top of the frame so that if they overflow it will not be possible to overwrite other variables before corrupting the canary [12]. The motivation is to protect pointers because sometimes they can be used to overwrite arbitrary memory [13]. Unfortunately, canaries are not a perfect solution, as even with layout precautions, the structure of a buffer overflow can sometimes permit an attacker to bypass canary words and access critical state directly, as happened with unsafe pointer arithmetic in yaSSL [3]. | Canary[11]是另一种常见的防御缓冲区溢出攻击的方法。Canary不能防止缓冲区溢出,但它可以追溯检测它们,并在攻击者影响控制流之前终止程序。例如,对于stack canaris,预先确定的secret值就放在每个保存的帧指针和返回地址之前。而后,当函数返回时,检查secret值以确保它没有更改。这可以防止堆栈缓冲区溢出被利用,因为攻击者必须正确覆盖secret值,以便程序实际使用覆盖的返回地址。然而,就像ASLR一样,Canary也可以通过泄露有关secret值信息进行绕过。堆栈内存的布局对于canary实现来说是一个重要的考虑因素。一种常见的方法是将所有缓冲区放在帧的顶部,这样,如果它们溢出,就不可能在破坏Canary之前覆盖其他变量[12]。其动机是保护指针,因为有时它们可以用来覆盖任意内存[13]。不幸的是,Canary并不是一个完美的解决方案,因为即使有布局预防措施,缓冲区溢出的结构有时也会允许攻击者绕过Canary,直接访问关键布局空间,就像yaSSL中不安全的指针算法[3]所发生的那样。 |
3 ROP介绍/ROP TUTORIAL
序号 | 英文 | 中文 |
---|---|---|
1 | Before discussing the Blind ROP technique, we first familiarize the reader with ROP. Modern exploits rely heavily on ROP. The goal of ROP is to build an instruction sequence that typically spawns a shell (shellcode) based on existing code fragments (gadgets). Once a shell is executed, the attacker can execute more commands to continue the attack. Traditionally, exploits would inject off-the-shelf shellcode into the process and execute it. Figure 1 shows typical shellcode that pipes the attacker’s socket to standard input, output and error and executes a shell. | 在讨论BROP技术之前,我们首先让读者熟悉ROP。当前的exp很大程度上依赖于ROP。ROP的目标是构建一个指令序列,该指令序列通常基于现有的代码片段(gadget)拿到shell。一旦shell被执行,攻击者就可以执行更多命令来继续攻击。传统上,漏洞利用程序会将现成的shellcode注入进程并执行它。图1显示了典型的shellcode,它将攻击者的socket传递到标准输入、输出和错误,并执行shell。 |
2 | Of course injecting shellcode is no longer possible because these days writable memory (e.g., the stack) is non-executable, and so ROP must be used instead. Figure 2 shows how ROP can in principle be used to create the shellcode previously shown in Figure 1. The stack is overflowed so that the addresses of all the gadgets are present in sequence. Each gadget ends with a return so that the next gadget can execute. | 当然,由于当前编译器一般是可写的内存(例如堆栈)是不可执行的(NX保护),注入shellcode已经不可能了,所以必须改用ROP。图2显示了如何使用ROP来创建图1中所示的shellcode。图中,所有gadgets的地址都按顺序出现,并实现栈溢出。每个gadget以一个返回结束,以便下一个gadget可以执行。 |
3 | In practice, each ROP gadget will be a short sequence of machine instructions terminated by a return. Executing a simple system call like dup2 will require multiple gadgets because arguments are passed in registers so gadgets to populatethese will be needed. Figure 3 shows the required gadgets for dup2. Registers rdi and rsi control the first two arguments to system calls, and rax controls the system call number. Registers can be controlled by using pop gadgets and placing the value to load on the stack. By chaining enough gadgets, complete shellcode can eventually be built. | 实际上,每个ROP gadget都是一个由返回终止的短序列机器指令。执行像dup2这样的简单系统调用需要多个gadget,因为参数是在寄存器中传递的,所以需要gadget来填充这些参数。图3显示了dup2所需的gadgets。寄存器rdi和rsi控制系统调用的前两个参数,rax控制系统调用号。寄存器可以通过使用pop gadgets和并放置从stack上加载的值来控制。通过链接足够多的gadgets,最终可以构建完整的shellcode。 |
4 当前的缓冲区溢出/BUFFER OVERFLOWS TODAY
序号 | 英文 | 中文 |
---|---|---|
1 | On most contemporary operating systems, where NX and ASLR are common, an attacker must fulfill at least two requirements in order to gain full control of a remote program’s execution: 1) To defeat NX, the attacker must know where gadgets reside in side the program executable. 2) To defeat ASLR, the attacker must derandomize the location at which the executable’s text segment is actually loaded in memory. These requirements can easily be brute-forced on 32-bit systems [9], [14] through simple guessing. | 在NX和ASLR普遍存在的现代操作系统上,攻击者必须满足至少两个要求才能完全控制远程程序的执行: 1) 要绕过NX,攻击者必须知道gadgets在程序可执行文件中的位置。 2 要绕过ASLR,攻击者必须找到代码段加载的位置。通过简单的猜测,这些要求很容易在32位系统[9]、[14]上通过暴力破解解决。 |
2 | This is not practical for 64-bit systems; in fact, most public exploits target 32-bit systems only. The purpose of the BROP attack is to circumventthese requirements on 64-bit systems. Hence, the rest of this discussion exclusively considers 64-bit attacks. | 然而,这种方法并不适用于64位系统;事实上,大多数公开攻击只针对32位系统。BROP攻击的目的是绕过64位系统上保护机制。因此,本文的其余部分仅考虑64位攻击。 |
3 | Defeating ASLR is also a significant challenge without BROP, but there are some possible strategies. Firstly, aninformation leak might reveal the address location of a code segment. Secondly, it may be possible to exploit any code that remains statically positioned across executions. For example, on Linux it is usually the case that the executable’s code is mapped to a fixed address even though dynamic libraries and other data memory regions are randomized with ASLR. As a result, an attacker could simply apply ROP to the program’s text segment directly. Additionally, on some platforms, such as Windows, there are shared libraries that are incompatible with ASLR, and thus such libraries are mapped to static locations. | 如果没有BROP,绕过ASLR存在挑战,但也有一些可能的策略。首先,信息泄漏可能会暴露代码段的地址位置。其次,可以利用在执行过程中保持静态位置的任何代码。例如,在Linux上,即使动态库和其他数据内存区域随机,但通常情况下,可执行文件的代码映射到固定地址。因此,攻击者可以直接将ROP应用于程序的代码段。此外,在某些平台(如Windows)上,存在与ASLR不兼容的共享库,因此这些库被映射到静态位置。 |
4 | On Linux, it is possible to apply ASLR to the entire address space, including the program’s text segment, by enabling PIE. With GCC, this is achieved through the -pie flag. Using PIE has been recommended in previous studies [15], but unfortunately, it has not been widely deployed to date. When PIE is enabled, there are no known general-purpose 64-bit techniques, outside of our proposed generalized stack reading attack, that can be used to defeat ASLR. | 在Linux上,通过启用PIE,可以将ASLR应用于整个地址空间,包括程序的代码段。对于GCC,这是通过-pie标志实现的。在以前的研究[15]中建议使用PIE,但不幸的是,到目前为止还没有得到广泛的应用。启用PIE后,除了我们提出的通用堆栈读取攻击之外,并没有已知的64位技术可用于绕过ASLR。 |
5 | Figure 4 shows how our BROP attack improves the state of the art in 64-bit exploit techniques. Today there are general techniques (ROP) to attack 64-bit servers only when the exact binary is available to the attacker and PIE is not used. Our stack reading technique makes it possible to attack PIE servers that do not rerandomize after a crash (i.e., fork-only without execve). The BROP attack additionally opens up the possibility of hacking systems where the binary is unknown. In all cases, the BROP attack cannot target PIE servers that rerandomize (e.g., execve) after a crash. | 图4显示了我们的BROP攻击如何改进64位攻击技术。如今,只有当攻击者可以拿到二进制文件且不使用PIE保护时,才有方法(ROP)来攻击64位服务器。我们的堆栈读取技术可以攻击在崩溃后不重新随机化的PIE服务器(即,fork-only-without-execve)。BROP攻击还增加了黑客攻击未知二进制的可能性。在所有情况下,BROP攻击都不能有效应对崩溃后重新随机化(例如execve)的PIE服务器。 |
5 | Hacking without binary knowledge is useful even in the not-completely-blind case (e.g., open-source) because it makes it possible to write generic, robust exploits that work against all distributions and are agnostic to a specific version of the binary. Today, attackers need to gather exact information (e.g., binaries) for all possible combinations of distribution versions and vulnerable software versions, and build an exploit for each. One might assume attackers would only bother with the most popular combinations. An implication of our work is that more obscure distributions offer little protection (through obscurity) against buffer overflows. | 即使在没有完全blind的情况下(例如,开源),BROP也可有效实施,这并不需要坚实的二进制基础,因为它可以编写针对所有发行版的通用、健壮的攻击,而此时并不需要知道二进制的特定版本。如今,攻击者需要收集发布版本和漏洞软件版本相结合的所有可能的信息,并为每个版本构建一个漏洞利用程序。有人可能认为攻击者只会使用最流行的组合。我们的工作也显示:不太流行的发布版本也提供很少的保护,来防止缓冲区溢出。 |
5 BROP环境/BROP ENVIRONMENT
序号 | 英文 | 中文 |
---|---|---|
1 | The Blind Remote Oriented Programming (BROP) attack makes the following assumptions and requires the following environment: 1) A stack vulnerability and knowledge of how to trigger it. 2) A server application that restarts after a crash. | BROP攻击作出以下假设,并需要以下环境: 1) 存在栈溢出漏洞。 2)应用服务在崩溃后重启。 |
2 | The threat model for a BROP attack is an attacker that knows an input string that crashes a server due to a stack overflow bug. The attacker must be able to overwrite a variable length of bytes including a return instruction pointer. The attacker need not know the source or binary of the server. The attacker is able to crash the server as many times as he wishes while conducting the attack, and the server must restart. If the server is compiled with the PIE flag, the server must be a forking daemon and must restart without using execve. The same is true for overflows where the canary must be modified by the exploit. The attacker is also able to distinguish when a server crashes prematurely, e.g., by noticing that the socket closes without receiving a response. | BROP攻击的威胁模型是:攻击者知道由于堆栈溢出错误导致服务器崩溃的输入字符串。攻击者必须能够覆盖数字节长度的变量,包括返回指令指针。攻击者不需要知道服务的源文件或二进制文件。攻击者可以在执行攻击时使服务器崩溃任意次数,并且服务器必须重新启动。如果服务是用PIE选项编译的,那么必须采用fork而不使用execve的情况下重新启动。对于必须通过漏洞攻击修改Canary的溢出也是如此。攻击者还能够区分服务器何时过早崩溃,例如,通过观察到套接字关闭而未收到响应。 |
6 攻击框架/ATTACK OUTLINE
序号 | 英文 | 中文 |
---|---|---|
1 | The BROP attack has the following phases: 1) Stack reading: read the stack to leak canaries and a return address to defeat ASLR. 2)Blind ROP: find enough gadgets to invoke write and control its arguments. 3) Build the exploit: dump enough of the binary to find enough gadgets to build a shellcode, and launch the final exploit. | BROP攻击包括如下几个阶段: 1)读stack:读stack来泄露canaryies和return addr来绕过ASLR。2) 找到足够的gadgets,控制参数,调用write函数。 3) 构建漏洞:转储足够的二进制文件以找到足够的gadgets来构建shellcode,并启动最终的漏洞。 |
2 | The first phase is needed so that a starting point address for scanning gadgets is found. Gadgets are then searched for until enough are found to invoke write. After that, the binary is transferred over the network from memory, enabling known techniques to be applied toward building the final exploit. | 第一阶段用于找到扫描gadgets的起始地址。而后搜索gadgets,直到找到可调用write。之后,二进制文件从内存通过网络传输,使已知的技术能够应用于构建最终的漏洞利用程序。 |
7 栈读取:ASLR解随机化/STACK READING: ASLR DE-RANDOMIZATION
序号 | 英文 | 中文 |
---|---|---|
1 | Exploits must have a method of defeating ASLR for configurations where PIE is used. We present a new stack reading technique that generalizes a known technique used for leaking canaries. It is useful even in cases where the binary is known and a full BROP attack is not required. The basic idea in leaking canaries is to overflow a single byte, overwriting a single byte of the canary with value x. If x was correct, the server does not crash. The algorithm is repeated for all possible 256 byte values until it is found (128 tries on average). The attack continues for the next byte until all 8 canary bytes (on 64-bit) are leaked. Figure 5 illustrates the attack. We generalize the attack to leak more words from the stack (“stack reading”). After the canary, one typically finds the saved frame pointer and then the saved return address, so three words need to be read. Figure 6 shows a typical stack layout. | 当使用PIE编译时,漏洞攻击必须有一种绕过ASLR的方法。我们提出了一种新的堆栈读取技术,它使得一种已知的用于泄漏Canary的技术更一般化。它甚至在二进制已知且不需要完全BROP攻击的情况下也很有效。泄漏Canary的基本思想是:溢出一个字节,并用值x覆盖Canary的一个字节。如果x是正确的,服务器不会崩溃。对一个字节的所有可能的256个值重复该算法,直到找到为止(平均128次尝试)。继续对下一个字节使用这种攻击方法,直到所有8个字节(64位)泄漏出来。图5说明了这种攻击方式。我们将攻击推广到从堆栈中泄漏更多words(“堆栈读取”)。在canary之后,通常会找到保存的帧指针,然后找到保存的返回地址,因此需要读取三个单词。图6显示了一个典型的堆栈布局。 |
2 | There are a few subtleties that apply to generalized stack reading but not to reading canaries. With canaries, exact values will always be returned because there is only one value canary that is correct. In general though, stack reading will not necessarily return the exact saved instruction pointer present on the stack. It is possible that a slightly different value is returned depending on whether another value still resumes program execution without causing a crash. For example, suppose that 0x400010 was stored on the stack and the value 0x400007 is currently being tested. It is possible that the program keeps executing without crashing and 0x400007 is obtained from stack reading. This is OK as the attacker is searching for any valid value in the .text segment range and not for a specific one. | **将栈读取技术应用于除Canary之外的其他值时,存在一些区别。**对于Canary,总是会返回准确的值,因为只有一个值是正确的。不过,通常情况下,堆栈读取不一定会返回堆栈上存在的准确的已保存指令指针。返回的值可能稍有不同,这取决于另一个值是否能使程序继续执行而不会导致崩溃。例如,假设0x400010存储在堆栈上,0x400007是当前正在测试的值。有可能程序在不崩溃的情况下继续执行,并从堆栈读取中获取0x400007。这是正常的,因为攻击者正在搜索.text段范围内的任何有效值,而不是特定值。 |
3 | It is possible that stack reading does not return an address in the application’s own .text segment, but rather a return address in a library. This can happen, for example, when the vulnerability lies in a library, or a callback happens. This is fine because gadgets can be found in the library instead. One can also stack read further to find more return addresses, if needed. | 堆栈读取可能不会返回应用程序自己的.text段中的地址,而是返回库中的地址。例如,当漏洞位于库中或发生回调时,可能会发生这种情况。这就很好,因为可以在库中找到gadgets。如果需要,还可以进一步堆栈读取以查找更多的返回地址。 |
4 | On 64-bit x86 systems only a portion of the address space is made available to the operating system (canonical form addresses). This allows us to skip several bytes when reading pointers. For user space processes the top two bytes are always zero. In fact, on Linux the third byte is 0x7f for libraries and the stack. The main binary and heap are usually stored at 0x00 for executables compiled without the PIE flag. Thus we can skip on average three bytes (384 requests) when reading addresses. | 在64位x86系统上,只有一部分地址空间可供操作系统使用(规范格式地址)。这允许我们在读取指针时跳过几个字节。对于用户空间进程,前两个字节始终为零。实际上,在Linux上,对于库和堆栈,第三个字节是0x7f。对于不带pie编译选项的可执行文件,主二进制文件和堆通常存储在0x00开始的位置。因此,在读取地址时,我们可以平均跳过三个字节(384个请求)。 |
5 | Table I shows the complexity of using stack reading versus standard brute-force attacks. We compare 32-bit and 64-bit systems across several operating systems. Clearly the brute force attack on 64-bit Linux is not practical and attackers have resorted to other techniques to circumvent ASLR. Many attacks have depended on non-randomized (without PIE) binaries that are common on Linux. Similarly Windows exploits have also resorted to attacking binaries that have opted out of randomization, or libraries that randomize once per reboot. Other attacks have used leaked pointers sometimes requiring another vulnerability. | 表1显示了使用堆栈读取与标准暴力攻击的复杂度。 我们比较了几种操作系统中的32位和64位系统。显然,64位Linux上的暴力攻击并不实用,攻击者已经在研究其他技术来绕过ASLR。许多攻击都依赖于Linux上常见的非随机化(没有PIE)二进制文件。类似地,Windows漏洞攻击也诉诸于攻击选择不随机化的二进制文件,或者攻击每次重启随机化一次的库。其他攻击使用了泄漏的指针,并经常需要借助另一个漏洞配合以达到效果。 |
6 | The fact that stack reading succeeds tells the attacker that the BROP environment exists and that a stack overflow, rather than some random bug, is being triggered. A bug like a null pointer dereference may cause a crash for all possible byte values being probed, or a no crash for multiple possible values(as opposed to one only). The words returned by stack reading give further evidence of the BROP attack working because the values can be somewhat sanitized: e.g., a random canary (which always starts with zero on Linux), a frame pointer, and a return address with known upper bits (0x40 for non-PIE or 0x7f). | 堆栈读取可达成目标的事实告诉攻击者BROP环境存在,并且正在触发堆栈溢出,而不是一些随机的错误。像空指针解引用这样的错误可能会导致所有可能被探测的字节值崩溃,或者导致多个可能值(而不是一个)不崩溃。堆栈读取技术返回的一些字节提供了BROP攻击有效的进一步证据,因为这些值可能会经过某种程度的清理:例如,一个随机的canary(在Linux上总是以零开始)、一个帧指针和一个具有已知高位的返回地址(0x40表示非PIE或0x7f)。 |
8 BROP攻击/BROP ATTACK
序号 | 英文 | 中文 |
---|---|---|
1 | The BROP attack allows writing exploits without possessing the target binary. It introduces techniques to find ROP gadgets remotely and optimizations to make the attack practical. | BROP攻击允许在没有拿到二进制文件的情况下进行攻击。可通过远程查找ROP gadgets并展开优化使得攻击实用可行。 |
A The pieces of the puzzle
序号 | 英文 | 中文 |
---|---|---|
1 | The goal is to find enough gadgets to invoke write. After that, the binary can be dumped from memory to the network to find more gadgets. The write system call takes three arguments: a socket, a buffer and a length. Arguments are passed in rdi, rsi and rdx registers, and the system call number is stored in the rax register. The following gadgets are therefore needed:While an attack that finds all these gadgets is possible (see Section VIII-I) we first describe an optimized version that makes the attack more practical. | 目标是找到足够的gadgets并调用write。之后,二进制文件可以从内存转储到网络中,以找到更多的gadgets。write系统调用有三个参数:套接字、缓冲区和长度。参数在rdi、rsi和rdx寄存器中传递,系统调用号存储在rax寄存器中。基于以上的分析,需要以下gadgets: 虽然攻击有可能找到所有gadgets(见第8-I节),但我们首先描述一个优化版本,使攻击更加实用。 |
2 | The first optimization is the BROP gadget. Shown in Figure 7, the BROP gadget is very common as it restores all callee saved registers. Misaligned parses of it yield a pop rdi and pop rsi. So by finding a single gadget, we find two gadgets that control the first two arguments of a call. | 第一项优化是BROP gadgets。如图7所示,BROP gadgets非常常见,因为它恢复所有被调用者保存的寄存器。未对齐的解析会产生pop rdi和pop rsi。因此,通过找到一个gadget,我们就能发掘出两个gadgets,来一次控制系统调用的前两个参数。 |
3 | The second optimization is finding a call write. Instead of finding two gadgets (pop rax; ret and syscall) we can find a single call write instruction. One convenient place to find call write is the program’s Procedure Linking Table (PLT). The PLT is a jump table used for dynamic linking containing all external library calls made by the application. Figure 8 shows the structure of an ELF binary; the PLT is the first region to contain valid executable code. | 第二项优化是找到一个write调用。通过一个单独的write调用指令,替代两个gadgets(pop rax; ret和syscall)。查找write调用的一个便捷的位置是程序的过程链接表(Procedure Linking Table,PLT)。PLT是一个用于动态链接的跳转表,包含应用程序发出的所有外部库调用。图8显示了ELF二进制文件的结构;PLT是第一个包含有效可执行代码的区域。 |
4 | The problem is now reduced to finding the BROP gadget, write’s entry in the PLT and a way to control rdx for the ength of the write. Any greater than zero length for write will do as one can leak the binary in multiple small chunks by chaining writes. We note that at the time of exploit, rdx may have a sane (greater than zero) value so having to control rdx may be unnecessary, but for the general case it is. Unfortunately pop rdx; ret gadgets are rare, so an optimization is to find a call to strcmp instead (again in the PLT) which sets rdx to the length of the string being compared. The optimized attack therefore requires: 1) Finding the BROP gadget. 2) Finding the PLT.(Finding the entry for write. Finding the entry for strcmp) | 现在的问题是找到BROP gadget、PLT中write的条目以及控制rdx写入长度的方法。任何大于零的写入长度都可以,因为可以通过链接写入将二进制文件泄漏到多个小块中。我们注意到,在攻击时,rdx可能本来就是一个大于零值,因此并不是必须要控制rdx。不幸的是,pop rdx;ret的gadgets很稀有,因此一个优化方法是找到对strcmp的调用(同样在PLT中),该调用将rdx设置为要比较的字符串的长度。因此,优化后的攻击需要: 1)找到BROP gadget。 2)找到PLT。(找到write的入口。找到strcmp的入口) |
B Finding gadgets and the stop gadget
序号 | 英文 | 中文 |
---|---|---|
1 | The basic idea in finding gadgets remotely is to scan the application’s text segment by overwriting the saved return address with an address pointing to text and inspecting program behavior. A starting address can be found from the initial stack reading phase or 0x400000 can be used on default non-PIE Linux. Generally speaking two things will occur: the program will crash or it will hang, and in turn the connection will close or stay open. Most of the time the program will crash, but when it does not, a gadget is found. For example, 0x400000 may point to code with a null pointer dereference and cause a crash. The next address, 0x400001, may point to code which causes an infinite loop and keeps the connection open. These latter gadgets that stop program execution are fundamental to finding other gadgets: we call these stop gadgets. | 远程查找gadgets的基本思想是扫描应用程序的text段,方法是用指向text的地址覆盖保存的返回地址并检查程序行为。可以从初始堆栈读取阶段找到起始地址,也可以在默认的非PIE Linux上使用0x400000。通常会发生两件事情:程序将崩溃或挂起,反过来连接将关闭或保持打开。大多数情况下,程序会崩溃,但当它不崩溃时,就会发现一个gadget。例如,0x400000可能指向具有空指针解引用的代码并导致崩溃。下一个地址0x400001可能指向导致无限循环并保持连接打开的代码。这些停止程序执行的末尾的gadgets对于找到其他gadgets是非常重要的:我们称之为stop gadgets。 |
2 | A problem with using this technique naively for finding gadgets is that even if the return address is overwritten with the address of a useful gadget like pop rdi; ret, the application will still likely crash because it will eventually attempt to return to the next word on the stack, likely an invalid address. The crash would cause us to discard the gadget classifying it as uninteresting. Figure 9 shows this. To find gadgets we need to stop the ROP chain execution. This is where stop gadgets come in. A stop gadget is anything that would cause the program to block, like an infinite loop or a blocking system call (like sleep). To scan for useful gadgets, one places the address being probed in the return address, followed by a number of stop gadgets. Note that a pop rdi;ret gadget would pop the next item from the stack into rdi so two stop gadgets would be needed in this case. Each time a useful gadget that does not cause a program crash is found, the stop gadget will run, blocking the program and leaving the socket open (instead of causing a crash). One can now scan the entire .text segment to compile a list of gadgets. The next section describes how the attacker can identify the instructions of a gadget—e.g., differentiate between pop rdi; ret and pop rsi; ret. | 直接使用这种技术查找gadgets的一个问题是:即使返回地址被像pop rdi;ret这样的gadget覆盖,应用程序仍可能崩溃,因为它最终将尝试返回到堆栈上的下一个word,这很可能是一个无效的地址。崩溃会导致我们丢弃这个gadget。图9显示了这一点。为了找到gadgets,我们需要停止ROP链的执行。这时就需要引入stop gadgets。stop gadget是任何会导致程序阻塞的程序片段,比如无限循环或阻塞系统调用(比如sleep)。要扫描有用的gadgets,可以将要探测的地址放在返回地址中,而后紧跟一定数量的stop gadgets。可以注意到,pop rdi;ret gadget会将堆栈中的下一项弹出到rdi寄存器中,因此在这种情况下需要放两个stop gadget。每次找到一个不会导致程序崩溃的有用的gadget时,stop gadget就会运行,阻塞程序并保持套接字打开(而不是导致崩溃)。现在可以扫描整个.text段并得到gadget列表。下一节将描述攻击者如何识别gadget指令,例如,区分pop-rdi;ret和pop-rsi;ret。 |
3 | Stop gadgets need not necessarily be gadgets that “stop” the program. They are merely a signaling mechanism. For example, a stop gadget could be one that forces a particular write to the network so the attacker can tell whether the stop gadget executed. Another scenario is one in which a stop gadget is already present in the stack frame. The stack will indeed already have multiple return addresses in it, and one of them may act as a stop gadget. For example a server may handle requests in a while-true loop, so returning to that loop may “resume” program execution and another request can be handled. This can be used to signal whether a program crashed or is still alive (i.e., the stop gadget ran). The attacker in this case would populate the stack with the addresses of enough ret instructions to “eat up” enough stack until the next word on the stack is a return address of a previous stack frame that acts as a stop gadget (e.g., returns to the main program loop). This particular optimization is useful for preventing situations where worker processes are limited and infinite loop-type stop gadgets ca 以上是关于[论文翻译与解读] Hacking Blind的主要内容,如果未能解决你的问题,请参考以下文章 DVWA靶场实战——SQL Injection(Blind) |