I've been trying to learn the basics of a heap overflow attack. I'm mostly interested in using a corruption or modification of the chunk metadata for the basis of the attack, but I'm also open to other suggestions. I know that my goal of the exploit should be do overwrite the printf()
function pointer with that of the challenge()
function pointer, but I can't seem to figure out how to achieve that write. I have the following piece of code which I want to exploit, which is using malloc
from glibc 2.11.2
:
我一直在尝试学习堆溢出攻击的基础知识。我最感兴趣的是在攻击的基础上使用块元数据的损坏或修改,但我也愿意接受其他建议。我知道这个漏洞的目标应该是用challenge()函数指针覆盖printf()函数指针,但我似乎不知道如何实现这个写入。我有下面这段代码,我想利用它,它使用了glibc 2.11.2中的malloc:
void challenge()
{
puts("you win\n");
}
int main(int argc, char **argv)
{
char *inputA, *inputB, *inputC;
inputA = malloc(32);
inputB = malloc(32);
inputC = malloc(32);
strcpy(inputA, argv[1]);
strcpy(inputB, argv[2]);
strcpy(inputC, argv[3]);
free(inputC);
free(inputB);
free(inputA);
printf("execute challenge to win\n");
}
Obviously, achieving an actual overwrite of an allocated chunk's metadata is trivial. However, I have not been able to find a way to exploit this code using any of the standard techniques. I have read and attempted to implement the techniques from:
显然,实现对已分配块的元数据的实际覆盖是微不足道的。但是,我还没有找到使用任何标准技术来利用这段代码的方法。我已阅读并尝试执行以下技术:
- The paper: w00w00 on Heap Overflows
- Although the paper is very clear, the
unlink
technique has been obsolete for some time. - 虽然论文很清楚,但是解链技术已经过时一段时间了。
- Although the paper is very clear, the
- 论文:w00w00关于堆溢出的论文虽然很清楚,但unlink技术已经过时一段时间了。
-
Malloc Maleficarum.txt
- This paper expands upon the exploit techniques from the w00w00 days, and accounts for the newer versions of glibc. However, I have not found that given the 5 techniques detailed in the paper, that the code above matches any of the prerequisites for those techniques.
- 本文详述了w00w00天的开发技术,并对glibc的更新版本进行了说明。然而,我还没有发现,考虑到本文中详细介绍的5种技术,上面的代码与这些技术的任何先决条件都不匹配。
- Malloc Maleficarum。本文对w00w00天的开发技术进行了扩展,并对glibc的更新版本进行了说明。然而,我还没有发现,考虑到本文中详细介绍的5种技术,上面的代码与这些技术的任何先决条件都不匹配。
-
Understanding the Heap By Breaking it(pdf)
- The pdf gives a pretty good review of how the heap works, but focuses on double free techniques.
- pdf对堆的工作方式进行了很好的回顾,但重点关注了双*技术。
- 通过破坏堆(pdf)来理解堆(pdf)可以很好地回顾堆是如何工作的,但是关注的是双*技术。
I originally tried to exploit this code by manipulating the size value of the chunk for inputC, so that it pointed back to the head of the inputC chunk. When that didn't work, I tried pointing further back to the chunk of inputB. That is when I realized that the new glibc performs a sanity check on the size value.
我最初试图通过操作inputC块的大小值来利用这段代码,因此它指向inputC块的头部。当它不起作用时,我试着用手指着那块inputB。这时我意识到新的glibc对大小值进行了全面检查。
How can a user craft an exploit to take advantage of a free, assuming he has the ability to edit the allocated chunk's metadata to arbitrary values, and user it to overwrite a value in the GOT or write to any other arbitrary address?
假设用户有能力将分配的块的元数据编辑为任意值,并使用它覆盖get中的值,或将其写入任何其他任意地址,那么用户如何利用一个免费的数据?
Note: When I write 'arbitrary address' I understand that memory pages may be read only or protected, I mean an address that I can assume I can write to.
注意:当我写“任意地址”时,我知道内存页可能是只读的或受保护的,我的意思是我可以假定我可以写入的地址。
3 个解决方案
#1
10
Note: I will say before I answer that this is purely an academic answer, not intended to be used for malicious purposes. I am aware of the exercises OP is doing and they are open source and not intended to encourage any users to use these techniques in unapproved circumstances.
注意:在回答之前,我要说,这纯粹是一个学术性的回答,无意用于恶意目的。我知道OP正在做的练习,它们是开源的,不打算鼓励任何用户在未经批准的情况下使用这些技术。
I will detail the technique below but for your reference I would take a look at the Vudo malloc tricks (It's referenced in one of your links above) because my overview is going to be a short one: http://www.phrack.com/issues.html?issue=57&id=8
我将详细介绍下面的技术,但是为了便于您参考,我将查看Vudo malloc技巧(它在上面的一个链接中被引用),因为我的概述很简短:http://www.phrack.com/issues.html?
It details how malloc handles creating blocks of memory, pulling memory from lists and other things. In particular the unlink attack is of interest for this attack (note: you're correct that glibc now performs a sanity check on sizes for this particular reason, but you should be on an older libc for this exercise... legacy bro).
它详细说明了malloc如何处理创建内存块、从列表和其他东西中提取内存。特别值得一提的是,unlink攻击对这次攻击很有兴趣(注意:glibc现在针对这个特殊原因对大小进行了全面检查,您应该使用一个更老的libc进行这个练习……遗留的兄弟)。
From the paper, an allocated block and a free block use the same data structure, but the data is handled differently. See here:
在本文中,一个已分配的块和一个空闲块使用相同的数据结构,但是数据的处理方式不同。在这里看到的:
chunk -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| prev_size: size of the previous chunk, in bytes (used |
| by dlmalloc only if this previous chunk is free) |
+---------------------------------------------------------+
| size: size of the chunk (the number of bytes between |
| "chunk" and "nextchunk") and 2 bits status information |
mem -> +---------------------------------------------------------+
| fd: not used by dlmalloc because "chunk" is allocated |
| (user data therefore starts here) |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| bk: not used by dlmalloc because "chunk" is allocated |
| (there may be user data here) |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| |
| |
| user data (may be 0 bytes long) |
| |
| |
next -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| prev_size: not used by dlmalloc because "chunk" is |
| allocated (may hold user data, to decrease wastage) |
+---------------------------------------------------------+
Allocated blocks don't use the fd or bk pointers, but free ones will. This is going to be important later. You should know enough programming to understand that "blocks" in Doug Lea's malloc are organized into a doubly-linked list; there's one list for free blocks and another for allocated ones (technically there are several lists for free depending on sizes but it's irrelevant here since the code allocates blocks of the same size). So when you're freeing a particular block, you have to fix the pointers to keep the list in tact.
分配的块不使用fd或bk指针,但是*块会。这在以后会很重要。你应该知道足够多的编程知识来理解道格·李的malloc中的“块”被组织成一个双链列表;有一个列表用于空闲块,另一个列表用于已分配的块(技术上,根据大小有几个列表是免费的,但是这里不相关,因为代码分配了相同大小的块)。因此,当您释放一个特定的块时,您必须修复指针以使列表保持圆滑。
e.g. say you're freeing block y from the list below:
例如,你可以从下面的列表中释放y块:
x <-> y <-> z
Notice that in the diagram above the spots for bk and fd contain the necessary pointers to iterate along the list. When malloc wants to take a block p off of the list it calls, among other things, a macro to fix the list:
注意,在上面的图中,bk和fd的位置包含了在列表中迭代的必要指针。当malloc想要从它调用的列表中删除一个block p时,它会调用一个宏来修复列表:
#define unlink( y, BK, FD ) {
BK = P->bk;
FD = P->fd;
FD->bk = BK;
BK->fd = FD;
}
The macro itself isn't hard to understand, but the important thing to note in older versions of libc is that it doesn't perform sanity checks on the size or the pointers being written to. What it means in your case is that without any sort of address randomization you can predictably and reliably determine the status of the heap and redirect an arbitrary pointer to an address of your choosing by overflowing the heap (via the strncopy here) in a specific way.
宏本身并不难理解,但在旧版本的libc中需要注意的重要一点是,它不会对要写入的大小或指针执行完整性检查。在您的例子中,它的意思是,在没有任何地址随机化的情况下,您可以通过以特定的方式溢出堆(通过这里的strncopy),以可预见和可靠地确定堆的状态,并将任意指针重定向到您选择的地址。
There's a few things required to get the attack to work:
要让攻击生效,有几件事是必须的:
- the fd pointer for your block is pointing to the address you want to overwrite minus 12 bytes. The offset has to do with malloc cleaning up the alignment when it modifies the list
- 块的fd指针指向要覆盖- 12字节的地址。偏移量与malloc在修改列表时清除对齐方式有关。
- The bk pointer of your block is pointing to your shellcode
- 块的bk指针指向shell代码
- The size needs to be -4. This accomplishes a few things, namely it sets the status bits in the block
- 大小应该是-4。这完成了一些事情,即它设置了块中的状态位。
So you'll have to play around with the offsets in your specific example, but the general malicious format that you're trying to pass with the strcpy here is of the format:
所以你必须在具体的例子中使用偏移量,但是你试图通过strcpy传递的一般恶意格式是这样的格式:
| junk to fill up the legitimate buffer | -4 | -4 | addr you want to overwrite -12 (0x0C) | addr you want to call instead
|垃圾来填充合法的缓冲区| -4 | -4 | addr你想重写-12 (0x0C) | addr你想调用
Note the negative number sets the prev_size field to -4, which makes the free routing believe that the prev_size chunk actually starts in the current chunk that you control/are corrupting.
注意负数将prev_size字段设置为-4,这使得*路由相信prev_size块实际上是从您控制/正在腐蚀的当前块中开始的。
And yes, a proper explanation wouldn't be complete without mentioning that this attack doesn't work on current versions of glibc; the size has a sanity check done and the unlink method just won't work. That in combination with mitigations like address randomization make this attack not viable on anything but legacy systems. But the method described here is how I did that challenge ;)
是的,如果不提及这次攻击对glibc的当前版本不起作用的话,正确的解释是不完整的;该大小完成了完整的检查,unlink方法无法工作。再加上地址随机化等缓和措施,这种攻击只能在遗留系统上使用。但这里描述的方法是我如何做这个挑战;)
#2
3
Note that most of the techniques explained in Malloc Malleficarum are now protected. The glibc has improved a lot all that double free scenarios.
注意,Malloc Malleficarum中解释的大多数技术现在都得到了保护。glibc大大改进了所有的双重*场景。
If you want to improve your knowledge about the Malloc Malleficarum techniques read the Malloc Des-Malleficarum and the House of Lore: Reloaded written by blackngel. You can find these texts in phrack.
如果你想提高你对Malloc Malleficarum技术的认识,请阅读Malloc Des-Malleficarum和the House of Lore: Reloaded by blackngel。你可以在phrack找到这些文本。
Malloc Des-Malleficarum
I'm also working on it, and I can say to you that, for example, House of Mind is no longer exploitable, at least, as is explained in the texts. Although it might be possible to bypass the new restrictions added to the code. Add that the easiest way to execute your code is to overwrite the .dtors address therefore your code will always be executed once the program finish.
我也在研究它,我可以对你们说,例如,《心灵之屋》不再是可利用的,至少,正如文中解释的那样。尽管可以绕过添加到代码中的新限制。另外,执行代码的最简单方法是覆盖.dtors地址,因此,一旦程序完成,您的代码将始终执行。
If you download the glibc code and study the critic zones of malloc., etc you will find code checks that are not documented in the documents previously mentioned. These check were included to stop the double free party.
如果下载glibc代码并研究malloc的批评者区域。,等等,您将发现在前面提到的文档中没有记录的代码检查。这些支票被包括以阻止双重*的政党。
On the other hand, the presentation of Justin N. Ferguson (Understanding the Heap by breaking it) that you could find in youtube (BlackHat 2007) is perfect in order to understand all the heap mechanics, but I must admit that the techniques shown are far from being reliable, but at least, he opens a new field to heap exploitation.
另一方面,贾斯汀·n·弗格森的演讲(理解堆打破),你可以在youtube上找到(2007年的统称)是完美的,以了解所有堆力学,但我必须承认,远非所示的技术可靠,但至少,他打开了一个新的领域堆剥削。
Understanding the heap by breaking it
通过破坏堆来理解堆
Anyways, I'm also working on it, so if you want to contact me, we can share our advances. You can reach me in the overflowedminds.net domain as newlog (build the mail address yourself ^^ ).
无论如何,我也在努力,所以如果你想联系我,我们可以分享我们的进展。你可以找到我在overflowedminds.net域newlog(建立邮件地址自己^ ^)。
#3
-2
Heap overflows are tricky to pull off, and are very heavilly heap-layout dependent, although it looks like you're going after the Windows CRT heap, which has lots of mitigations in place specifically to stop this type of attack.
堆溢出是很难实现的,并且非常严重地依赖于堆布局,尽管它看起来像在运行Windows CRT堆,它有大量的缓解措施来阻止这种类型的攻击。
If you really do want to do this kind of thing, you need to happy jumping into WinDbg and stepping into functions like free to see exactly what is going on inside free, and hence what kind of control you might be able to achieve via the heap overflow of the previous value.
如果你真的想要做这种事情,你需要开心跳进WinDbg和步入功能如免费看看里面究竟什么是免费的,所以什么样的控制可以实现通过堆溢出的前一个值。
I won't give you any more specific help than that for the simple reason that demonstrating a heap overflow is usually enough for defensive security - defensive security experts can report a heap overflow without needing to actually fully exploit it. The only people who do need to fully exploit a heap-overflow all the way to remote code execution are people exploiting bugs offensively, and if you want to do that, you're on your own.
我不会提供比这更具体的帮助,原因很简单:演示堆溢出通常足以用于防御安全——防御安全专家可以报告堆溢出,而无需真正充分利用它。唯一需要充分利用一个heap-overflow的人,所有的远程代码执行都是开发bug的人,如果你想这样做的话,你就只能靠自己了。
#1
10
Note: I will say before I answer that this is purely an academic answer, not intended to be used for malicious purposes. I am aware of the exercises OP is doing and they are open source and not intended to encourage any users to use these techniques in unapproved circumstances.
注意:在回答之前,我要说,这纯粹是一个学术性的回答,无意用于恶意目的。我知道OP正在做的练习,它们是开源的,不打算鼓励任何用户在未经批准的情况下使用这些技术。
I will detail the technique below but for your reference I would take a look at the Vudo malloc tricks (It's referenced in one of your links above) because my overview is going to be a short one: http://www.phrack.com/issues.html?issue=57&id=8
我将详细介绍下面的技术,但是为了便于您参考,我将查看Vudo malloc技巧(它在上面的一个链接中被引用),因为我的概述很简短:http://www.phrack.com/issues.html?
It details how malloc handles creating blocks of memory, pulling memory from lists and other things. In particular the unlink attack is of interest for this attack (note: you're correct that glibc now performs a sanity check on sizes for this particular reason, but you should be on an older libc for this exercise... legacy bro).
它详细说明了malloc如何处理创建内存块、从列表和其他东西中提取内存。特别值得一提的是,unlink攻击对这次攻击很有兴趣(注意:glibc现在针对这个特殊原因对大小进行了全面检查,您应该使用一个更老的libc进行这个练习……遗留的兄弟)。
From the paper, an allocated block and a free block use the same data structure, but the data is handled differently. See here:
在本文中,一个已分配的块和一个空闲块使用相同的数据结构,但是数据的处理方式不同。在这里看到的:
chunk -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| prev_size: size of the previous chunk, in bytes (used |
| by dlmalloc only if this previous chunk is free) |
+---------------------------------------------------------+
| size: size of the chunk (the number of bytes between |
| "chunk" and "nextchunk") and 2 bits status information |
mem -> +---------------------------------------------------------+
| fd: not used by dlmalloc because "chunk" is allocated |
| (user data therefore starts here) |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| bk: not used by dlmalloc because "chunk" is allocated |
| (there may be user data here) |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| |
| |
| user data (may be 0 bytes long) |
| |
| |
next -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| prev_size: not used by dlmalloc because "chunk" is |
| allocated (may hold user data, to decrease wastage) |
+---------------------------------------------------------+
Allocated blocks don't use the fd or bk pointers, but free ones will. This is going to be important later. You should know enough programming to understand that "blocks" in Doug Lea's malloc are organized into a doubly-linked list; there's one list for free blocks and another for allocated ones (technically there are several lists for free depending on sizes but it's irrelevant here since the code allocates blocks of the same size). So when you're freeing a particular block, you have to fix the pointers to keep the list in tact.
分配的块不使用fd或bk指针,但是*块会。这在以后会很重要。你应该知道足够多的编程知识来理解道格·李的malloc中的“块”被组织成一个双链列表;有一个列表用于空闲块,另一个列表用于已分配的块(技术上,根据大小有几个列表是免费的,但是这里不相关,因为代码分配了相同大小的块)。因此,当您释放一个特定的块时,您必须修复指针以使列表保持圆滑。
e.g. say you're freeing block y from the list below:
例如,你可以从下面的列表中释放y块:
x <-> y <-> z
Notice that in the diagram above the spots for bk and fd contain the necessary pointers to iterate along the list. When malloc wants to take a block p off of the list it calls, among other things, a macro to fix the list:
注意,在上面的图中,bk和fd的位置包含了在列表中迭代的必要指针。当malloc想要从它调用的列表中删除一个block p时,它会调用一个宏来修复列表:
#define unlink( y, BK, FD ) {
BK = P->bk;
FD = P->fd;
FD->bk = BK;
BK->fd = FD;
}
The macro itself isn't hard to understand, but the important thing to note in older versions of libc is that it doesn't perform sanity checks on the size or the pointers being written to. What it means in your case is that without any sort of address randomization you can predictably and reliably determine the status of the heap and redirect an arbitrary pointer to an address of your choosing by overflowing the heap (via the strncopy here) in a specific way.
宏本身并不难理解,但在旧版本的libc中需要注意的重要一点是,它不会对要写入的大小或指针执行完整性检查。在您的例子中,它的意思是,在没有任何地址随机化的情况下,您可以通过以特定的方式溢出堆(通过这里的strncopy),以可预见和可靠地确定堆的状态,并将任意指针重定向到您选择的地址。
There's a few things required to get the attack to work:
要让攻击生效,有几件事是必须的:
- the fd pointer for your block is pointing to the address you want to overwrite minus 12 bytes. The offset has to do with malloc cleaning up the alignment when it modifies the list
- 块的fd指针指向要覆盖- 12字节的地址。偏移量与malloc在修改列表时清除对齐方式有关。
- The bk pointer of your block is pointing to your shellcode
- 块的bk指针指向shell代码
- The size needs to be -4. This accomplishes a few things, namely it sets the status bits in the block
- 大小应该是-4。这完成了一些事情,即它设置了块中的状态位。
So you'll have to play around with the offsets in your specific example, but the general malicious format that you're trying to pass with the strcpy here is of the format:
所以你必须在具体的例子中使用偏移量,但是你试图通过strcpy传递的一般恶意格式是这样的格式:
| junk to fill up the legitimate buffer | -4 | -4 | addr you want to overwrite -12 (0x0C) | addr you want to call instead
|垃圾来填充合法的缓冲区| -4 | -4 | addr你想重写-12 (0x0C) | addr你想调用
Note the negative number sets the prev_size field to -4, which makes the free routing believe that the prev_size chunk actually starts in the current chunk that you control/are corrupting.
注意负数将prev_size字段设置为-4,这使得*路由相信prev_size块实际上是从您控制/正在腐蚀的当前块中开始的。
And yes, a proper explanation wouldn't be complete without mentioning that this attack doesn't work on current versions of glibc; the size has a sanity check done and the unlink method just won't work. That in combination with mitigations like address randomization make this attack not viable on anything but legacy systems. But the method described here is how I did that challenge ;)
是的,如果不提及这次攻击对glibc的当前版本不起作用的话,正确的解释是不完整的;该大小完成了完整的检查,unlink方法无法工作。再加上地址随机化等缓和措施,这种攻击只能在遗留系统上使用。但这里描述的方法是我如何做这个挑战;)
#2
3
Note that most of the techniques explained in Malloc Malleficarum are now protected. The glibc has improved a lot all that double free scenarios.
注意,Malloc Malleficarum中解释的大多数技术现在都得到了保护。glibc大大改进了所有的双重*场景。
If you want to improve your knowledge about the Malloc Malleficarum techniques read the Malloc Des-Malleficarum and the House of Lore: Reloaded written by blackngel. You can find these texts in phrack.
如果你想提高你对Malloc Malleficarum技术的认识,请阅读Malloc Des-Malleficarum和the House of Lore: Reloaded by blackngel。你可以在phrack找到这些文本。
Malloc Des-Malleficarum
I'm also working on it, and I can say to you that, for example, House of Mind is no longer exploitable, at least, as is explained in the texts. Although it might be possible to bypass the new restrictions added to the code. Add that the easiest way to execute your code is to overwrite the .dtors address therefore your code will always be executed once the program finish.
我也在研究它,我可以对你们说,例如,《心灵之屋》不再是可利用的,至少,正如文中解释的那样。尽管可以绕过添加到代码中的新限制。另外,执行代码的最简单方法是覆盖.dtors地址,因此,一旦程序完成,您的代码将始终执行。
If you download the glibc code and study the critic zones of malloc., etc you will find code checks that are not documented in the documents previously mentioned. These check were included to stop the double free party.
如果下载glibc代码并研究malloc的批评者区域。,等等,您将发现在前面提到的文档中没有记录的代码检查。这些支票被包括以阻止双重*的政党。
On the other hand, the presentation of Justin N. Ferguson (Understanding the Heap by breaking it) that you could find in youtube (BlackHat 2007) is perfect in order to understand all the heap mechanics, but I must admit that the techniques shown are far from being reliable, but at least, he opens a new field to heap exploitation.
另一方面,贾斯汀·n·弗格森的演讲(理解堆打破),你可以在youtube上找到(2007年的统称)是完美的,以了解所有堆力学,但我必须承认,远非所示的技术可靠,但至少,他打开了一个新的领域堆剥削。
Understanding the heap by breaking it
通过破坏堆来理解堆
Anyways, I'm also working on it, so if you want to contact me, we can share our advances. You can reach me in the overflowedminds.net domain as newlog (build the mail address yourself ^^ ).
无论如何,我也在努力,所以如果你想联系我,我们可以分享我们的进展。你可以找到我在overflowedminds.net域newlog(建立邮件地址自己^ ^)。
#3
-2
Heap overflows are tricky to pull off, and are very heavilly heap-layout dependent, although it looks like you're going after the Windows CRT heap, which has lots of mitigations in place specifically to stop this type of attack.
堆溢出是很难实现的,并且非常严重地依赖于堆布局,尽管它看起来像在运行Windows CRT堆,它有大量的缓解措施来阻止这种类型的攻击。
If you really do want to do this kind of thing, you need to happy jumping into WinDbg and stepping into functions like free to see exactly what is going on inside free, and hence what kind of control you might be able to achieve via the heap overflow of the previous value.
如果你真的想要做这种事情,你需要开心跳进WinDbg和步入功能如免费看看里面究竟什么是免费的,所以什么样的控制可以实现通过堆溢出的前一个值。
I won't give you any more specific help than that for the simple reason that demonstrating a heap overflow is usually enough for defensive security - defensive security experts can report a heap overflow without needing to actually fully exploit it. The only people who do need to fully exploit a heap-overflow all the way to remote code execution are people exploiting bugs offensively, and if you want to do that, you're on your own.
我不会提供比这更具体的帮助,原因很简单:演示堆溢出通常足以用于防御安全——防御安全专家可以报告堆溢出,而无需真正充分利用它。唯一需要充分利用一个heap-overflow的人,所有的远程代码执行都是开发bug的人,如果你想这样做的话,你就只能靠自己了。