web-dev-qa-db-ja.com

バッファオーバーフローの実行中にstrcpyでセグメンテーションエラーが発生しました

私はret2libcを実行するために使用する必要があるこのコードを持っています

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

int main(int argc, char *argv[])
{
    char buf[256];

    printf("buff is at:%p\n",buf);
  printf("%s",argv[1]);
  strcpy(buf, argv[1]);

  printf(buf);
}

私はそれをgcc -m32 -fno-stack-protector ./rt2.c -ort2としてコンパイルし、次のように(pwntoolsで生成された)循環パターンで開始します。

./rt2 aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaac

私はメインの終わりにセグメンテーション違反を予期していました...それは代わりにstrcpyの終わりに起こります...実際に何が起こるか(gdbで見ることによって)はstrcpyの終わりにESPは、入力文字列の一部である0x6361616eを指します。

もう1つの奇妙なことは、strcpyの前のprintfが何も出力しないことです。

これは実行の結果です:

$ ./rt2 aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaac


buff is at:0xffffcf20
Segmentation fault (core dumped)

$ dmesg | tail -1
[ 4432.704356] rt2[3280]: segfault at 6361616e ip 00000000565555e0 sp 000000006361616e error 4 in rt2[56555000+1000]

さらに奇妙なことに、私は、printfの前にstrcpyとコメントすると、代わりに出力されます...

Valgrindで実行してみたところ、ある時点でESPが上書きされていることが確認されました。

valgrind ./rt2 aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaac
==2735== Memcheck, a memory error detector
==2735== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2735== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2735== Command: ./rt2 aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaac
==2735== 
buff is at:0xfeffce80
==2735== Warning: client switching stacks?  SP change: 0xfeffcf98 --> 0x6361616e
==2735==          to suppress, use: --max-stackframe=1684115926 or greater
==2735== Invalid read of size 4
==2735==    at 0x1085E0: main (rt2.c:20)
==2735==  Address 0x6361616e is on thread 1's stack
==2735== 
==2735== 
==2735== Process terminating with default action of signal 11 (SIGSEGV)
==2735==  Access not within mapped region at address 0x6361616E
==2735==    at 0x1085E0: main (rt2.c:20)
==2735==  If you believe this happened as a result of a stack
==2735==  overflow in your program's main thread (unlikely but
==2735==  possible), you can try to increase the size of the
==2735==  main thread stack using the --main-stacksize= flag.
==2735==  The main thread stack size used in this run was 8388608.
--2735-- VALGRIND INTERNAL ERROR: Valgrind received a signal 11 (SIGSEGV) - exiting
--2735-- si_code=1;  Faulting address: 0x6361616E;  sp: 0x82d8cf20

valgrind: the 'impossible' happened:
   Killed by fatal signal

Host stacktrace:
==2735==    at 0x5803F9F6: ??? (in /usr/lib/valgrind/memcheck-x86-linux)

sched status:
  running_tid=1

Thread 1: status = VgTs_Runnable (lwpid 2735)
==2735==    at 0x482A4D0: _vgnU_freeres (in /usr/lib/valgrind/vgpreload_core-x86-linux.so)

私は次のようにコンパイルしようとしました:gcc -g -m32 -fno-stack-protector -z stack-size=4194304 ./rt2.c -ort2何も変更されていません

2
Luigi

編集:最初にデバッガで見たものを複製することができました。私はstrcpyにブレークポイントを設定し、それをステップオーバーしようとするとセグメンテーション違反が発生しました。 ただし、命令にブレークポイントを設定した場合afterstrcpymainが終了するまでsegfaultを取得しません:

_ → 0x56556239 <main+144>       lea    esp, [ecx-0x4]
   0x5655623c <main+147>       ret
_

そのため、この場合、デバッガーで異常が発生し、クラッシュが発生した場所について誤った仮定がなされたのではないかと思います。ここで最終的に参照されるアドレスを上書きしていたことは明らかです。私はオーバーフローにさまざまなサイズを試しましたが、結局これを回避してEIPを制御するクラッシュを引き起こすものを見つけました。 268のサイズでうまくいくようです。

元の回答: segfaultがstrcpy中に発生し、戻りアドレスを上書きできないことを考えると、問題には別のアプローチが必要になると思います。 printf(buf);の存在は、フォーマット文字列の脆弱性を悪用することで解決されると思われます。ほぼ任意のアドレスを上書きできる可能性があります。保存されたリターンポインタを指すスタックアドレスがスタック上にある場合は、それに書き込むことで制御を取得できる場合があります。

なぜsegfaultがどこで発生しているのか正確にはわかりませんが、スタックレイアウトは、バッファオーバーフローによる実行フローの乗っ取りには単に不利である可能性があります。結局のところ、これは「未定義の動作」です。

1
multithr3at3d