50

私は CentOS 6.4 32 ビットを使用しており、プログラムでバッファ オーバーフローを引き起こそうとしています。GDB内では機能します。出力は次のとおりです。

[root@localhost bufferoverflow]# gdb stack
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/bufferoverflow/stack...done.
(gdb) r
Starting program: /root/bufferoverflow/stack
process 6003 is executing new program: /bin/bash
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.107.el6_4.2.i686
sh-4.1#

ただし、プログラムスタックを単独で実行すると、セグメント障害が発生します。これはなぜでしょうか?

4

7 に答える 7

129

エクスプロイトの開発は、デバッグ プロセスに非決定性を導入する要因を適切に考慮しないと、深刻な頭痛の種になる可能性があります。特に、デバッガ内のスタック アドレスは、通常の実行中のアドレスと一致しない場合があります。このアーティファクトは、オペレーティング システム ローダーがスタックの先頭の前に環境変数とプログラム引数の両方を配置するために発生します。

プロセスレイアウト

脆弱なプログラムは引数を取らないため、環境変数が原因である可能性があります。シェルとデバッガーの両方の呼び出しで同じであることを確認してください。このために、呼び出しをenv次のようにラップできます。

env - /path/to/stack

デバッガーを使用すると、次のようになります。

env - gdb /path/to/stack
($) show env
LINES=24
COLUMNS=80

上記の例では、gdb によって設定された 2 つの環境変数があり、さらに無効にすることができます。

unset env LINES
unset env COLUMNS

show env空のリストを返すようになりました。この時点で、デバッグ プロセスを開始して、ジャンプ先として想定している絶対スタック アドレス (例: 0xbffffa8b) を見つけ、それをエクスプロイトにハードコードできます。

./stackもう 1 つの微妙ですが重要な詳細: と の呼び出しには違いがあります。プログラムを呼び出した/path/to/stackとおりargv[0]に保持するため、呼び出し文字列が等しいことを確認する必要があります。/path/to/stack上記の例で and だけでなく./stackを使用したのはそのためgdb stackです。

メモリの安全性の脆弱性を悪用する方法を学習するときは、以下のラッパー プログラムを使用することをお勧めします。

$ invoke stack         # just call the executable
$ invoke -d stack      # run the executable in GDB

スクリプトは次のとおりです。

#!/bin/sh

while getopts "dte:h?" opt ; do
  case "$opt" in
    h|\?)
      printf "usage: %s -e KEY=VALUE prog [args...]\n" $(basename $0)
      exit 0
      ;;
    t)
      tty=1
      gdb=1
      ;;
    d)
      gdb=1
      ;;
    e)
      env=$OPTARG
      ;;
  esac
done

shift $(expr $OPTIND - 1)
prog=$(readlink -f $1)
shift
if [ -n "$gdb" ] ; then
  if [ -n "$tty" ]; then
    touch /tmp/gdb-debug-pty
    exec env - $env TERM=screen PWD=$PWD gdb -tty /tmp/gdb-debug-pty --args $prog "$@"
  else
    exec env - $env TERM=screen PWD=$PWD gdb --args $prog "$@"
  fi
else
  exec env - $env TERM=screen PWD=$PWD $prog "$@"
fi
于 2013-07-21T19:20:46.197 に答える
10

gdb でコードを実行したときのスタック フレーム ポインタのアドレスは、通常の実行時とは異なります。そのため、gdb モードではリターン アドレスが破損する可能性がありますが、通常モードでは正しくない可能性があります。その主な理由は、環境変数が 2 つの状況で異なることです。

これは単なるデモであるため、被害者のコードを変更して、バッファのアドレスを出力できます。次に、戻りアドレスをオフセット + バッファーのアドレスに変更します。

ただし、実際には、悪意のあるコードの前にNOP スレッドを追加してリターン アドレスを推測する必要があります。また、推測が間違っている可能性があるため、正しいアドレスを取得するために何度も推測する場合があります。

これがあなたを助けることを願っています。

于 2015-04-10T10:57:47.170 に答える
10

ターミナルと で同一のスタックを使用してプログラムを実行する簡単な方法を次に示しますgdb

まず、プログラムがスタック保護なしでコンパイルされていることを確認してください。

gcc -m32 -fno-stack-protector -z execstack -o shelltest shelltest.c -g

および ASLR が無効になっています。

echo 0 > /proc/sys/kernel/randomize_va_space

注: 私のマシンのデフォルト値は 2 でした。これを変更する前にメモしておいてください。

次に、プログラムを次のように実行します (それぞれ端末と gdb):

env -i PWD="/root/Documents/MSec" SHELL="/bin/bash" SHLVL=0 /root/Documents/MSec/shelltest
env -i PWD="/root/Documents/MSec" SHELL="/bin/bash" SHLVL=0 gdb /root/Documents/MSec/shelltest

内でgdb、 と を確認しunset LINESCOLUMNSください。

注:テスト プログラムをいじって、これらの環境変数を取得しました。

この 2 回の実行では、スタックのトップへの同一のポインターが得られるため、リモートでホストされているバイナリを悪用しようとしている場合でも、リモート スクリプトを悪用する必要はありません。

于 2017-03-30T05:32:13.713 に答える
7

バッファ オーバーフローが gdb で機能し、それ以外の場合に segfaults が機能する理由は、gdb がアドレス空間レイアウトのランダム化を無効にするためです。これは、gdb バージョン 7 ではデフォルトでオンになっていると思います。

これは、次のコマンドを実行して確認できます。

show disable-randomization

そして、それを設定します

set disable-randomization on

また

set disable-randomization off
于 2013-07-21T18:10:51.847 に答える
4

ここで受け入れられた解決策を試しましたが、うまくいきません(私にとっては)。gdb が環境変数を追加したため、スタック アドレスが一致しないことはわかっていましたが、その変数を削除しても、gdb なしではエクスプロイトを実行できません (受け入れられたソリューションに投稿されたスクリプトも試しました)。

しかし、ウェブで検索すると、私に適した他のスクリプトが見つかりました: https://github.com/hellman/fixenv/blob/master/r.sh

使用法は基本的に、受け入れられたソリューションのスクリプトと同じです。

  • r.sh gdb ./program [args] gdb でプログラムを実行する
  • r.sh ./program [args] gdb なしでプログラムを実行する

そして、このスクリプトは私にとってはうまくいきます。

于 2016-10-12T15:58:13.100 に答える
1

私はCentOS 6.4 32ビットを使用しており、プログラムでバッファオーバーフローを引き起こそうとしています...しかし、プログラムスタックを単独で実行すると、セグメント障害が発生します。

また、FORTIFY_SOURCE が結果に影響を与えていないことを確認する必要があります。FORTIFY_SOURCE は、いくつかのタイプのバッファ オーバーフローを防ぐために「より安全な」関数呼び出しを挿入するため、セグ フォールトは FORTIFY_SOURCE が問題になる可能性があるように聞こえます。コンパイラがデスティネーション バッファ サイズを推定できる場合、サイズがチェックさabort()れ、違反 (つまり、セグ フォールト) が発生したときに呼び出されます。

テストのために FORTIFY_SOURCE をオフにするには、-U_FORTIFY_SOURCEまたはでコンパイルする必要があります-D_FORTIFY_SOURCE=0

于 2014-09-12T12:41:11.760 に答える
0

gdb の外では起こらないが、gdb が行う主なことの 1 つは、メモリがゼロになることです。コードのどこかでメモリを初期化していない可能性が高く、ガベージ値を取得しています。Gdb は、これらのタイプのエラーを隠して割り当てたすべてのメモリを自動的にクリアします。

例: 以下は gdb で機能するはずですが、外部では機能しません。

int main(){
    int **temp = (int**)malloc(2*sizeof(int*)); //temp[0] and temp[1] are NULL in gdb, but not outside
    if (temp[0] != NULL){
        *temp[0] = 1; //segfault outside of gdb
    }
    return 0;
}

valgrind の下でプログラムを実行して、この問題を検出できるかどうかを確認してください。

于 2013-07-21T18:04:50.637 に答える