我正在尝试ProtoStar stack5挑战。我知道解决方案(在写文章之后(,但我正在尝试想出一种不同的方法。
以下是我们试图在上面执行外壳代码的程序的源代码:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buffer[64];
gets(buffer);
}
因此,为了看看寄存器中发生了什么,我做了以下操作:
(gdb) n
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
11 in stack5/stack5.c
(gdb) x/30x $esp
0xbffff750: 0xbffff760 0xb7ec6165 0xbffff768 0xb7eada75
0xbffff760: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff770: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff780: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff790: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff7a0: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff7b0: 0x41414141 0xbffff800 0xbffff85c 0xb7fe1848
0xbffff7c0: 0xbffff810 0xffffffff
(gdb) p $ebp
$1 = (void *) 0xbffff7a8
(gdb)
很好,我的回信地址是41414141。正如预期的那样。现在,我想做的是将返回地址更改为接下来的4个字节,这样
00xbffff7a8: |saved frame pointer| - | return address| - |shellcode part 1| - |...| - |shellcode part n|
然而,当我试图写76"41"s,然后写地址0xbffff7a8+4(即0xbffff4b0(时,它总是写错东西。以下是我输入的内容:
41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141b0f7ffbf
请注意,我们使用的是一个小端序系统。
然而,当我输入这个(作为ASCII(时,这就是我在$esp和$ebp:上看到的
(gdb) n
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA°÷ÿ¿
11 in stack5/stack5.c
(gdb) x/30x $esp
0xbffff760: 0xbffff770 0xb7ec6165 0xbffff778 0xb7eada75
0xbffff770: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff780: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff790: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff7a0: 0x41414141 0x41414141 0x41414141 0xb7c3b0c2
0xbffff7b0: 0xbfc2bfc3 0xbffff800 0xbffff86c 0xb7fe1848
0xbffff7c0: 0xbffff820 0xffffffff ...
(gdb) p $ebp
$1 = (void *) 0xbffff7a8
正如您所看到的,写入0xb7c3b0c2而不是预期的0xbffff7b0
有人知道为什么会这样吗?
注意:我意识到我实际想要的地址是0xbffff7ac,而不是0xbffff4b0。我会解决这个问题,但这并不能改变我遇到的问题。
所以我最终在LiveOverflow的子版块reddit上发布了这个问题,LiveOverflow向我指出了这个视频的方向。
视频会比我更好地解释它,但本质上,python2和python3并没有将十六进制打印成相同的ascii。Python3插入额外的字符,而python2打印原始的十六进制字符串。
我强烈鼓励你观看视频,因为它对它进行了深入的解释。
@dsh在SO上回答的另一个问题的答案也解释了这一点:
字节序列C3 BE是字符U+00FE。
Python 2将字符串处理为字节序列,而不是字符。因此"\xfe"是一个包含一个字节的str对象。
在Python3中,字符串是(Unicode(字符的序列。所以代码"\xfe"是一个包含一个字符的字符串。当您打印字符串,必须将其编码为字节。由于您的环境选择了UTF-8的默认编码,因此进行了相应的编码。
如何解决这个问题取决于您的数据。是字节还是字符?如果字节,然后更改代码以告诉解释器:print(b'\xfe'(。如果是字符,但您想要不同的编码,则编码相应的字符串:print('\xf'.encode('latin1'((。