Stack Overflow

HackTricksをサポートする

スタックオーバーフローとは

スタックオーバーフローは、プログラムがスタックに割り当てられたよりも多くのデータを書き込むときに発生する脆弱性です。この余分なデータは隣接するメモリ空間を上書きし、有効なデータの破損、制御フローの混乱、そして潜在的には悪意のあるコードの実行を引き起こします。この問題は、入力に対して境界チェックを行わない安全でない関数の使用によってしばしば発生します。

この上書きの主な問題は、保存された命令ポインタ(EIP/RIP)と保存されたベースポインタ(EBP/RBP)が前の関数に戻るためにスタックに保存されていることです。したがって、攻撃者はそれらを上書きし、プログラムの実行フローを制御できるようになります。

この脆弱性は通常、関数がスタックに割り当てられたバイト数よりも多くのバイトをコピーすることによって発生し、他のスタックの部分を上書きできるようになります。

これに脆弱な一般的な関数には、strcpystrcatsprintfgetsなどがあります。また、fgetsread、および**memcpyのような長さ引数**を取る関数も、指定された長さが割り当てられたものより大きい場合に脆弱な方法で使用される可能性があります。

例えば、以下の関数が脆弱である可能性があります:

void vulnerable() {
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}

スタックオーバーフローのオフセットを見つける

スタックオーバーフローを見つける最も一般的な方法は、非常に大きな入力の As を与えることです(例: python3 -c 'print("A"*1000)')そして、アドレス 0x41414141 にアクセスしようとしたことを示す Segmentation Fault を期待します

さらに、スタックオーバーフローの脆弱性があることがわかったら、リターンアドレスを上書きするために必要なオフセットを見つける必要があります。そのためには、通常 De Bruijn シーケンス が使用されます。これは、サイズ k のアルファベットと長さ n の部分列に対して、長さ _n_** のすべての可能な部分列がちょうど一度だけ連続した部分列として現れるサイクリックシーケンスです。

この方法では、EIP を制御するために必要なオフセットを手動で特定する代わりに、これらのシーケンスの1つをパディングとして使用し、上書きされたバイトのオフセットを見つけることができます。

これには pwntools を使用することができます:

from pwn import *

# Generate a De Bruijn sequence of length 1000 with an alphabet size of 256 (byte values)
pattern = cyclic(1000)

# This is an example value that you'd have found in the EIP/IP register upon crash
eip_value = p32(0x6161616c)
offset = cyclic_find(eip_value)  # Finds the offset of the sequence in the De Bruijn pattern
print(f"The offset is: {offset}")

または GEF:

#Patterns
pattern create 200 #Generate length 200 pattern
pattern search "avaaawaa" #Search for the offset of that substring
pattern search $rsp #Search the offset given the content of $rsp

スタックオーバーフローの悪用

オーバーフロー中(オーバーフローサイズが十分大きいと仮定すると)、スタック内のローカル変数の値を上書きすることができ、保存されたEBP/RBPおよびEIP/RIP(またはそれ以上)に到達します。 この種の脆弱性を悪用する最も一般的な方法は、戻りアドレスを変更することで、関数が終了すると制御フローがユーザーが指定したポインタの場所にリダイレクトされることです。

しかし、他のシナリオでは、スタック内のいくつかの変数の値を上書きするだけで悪用が可能な場合もあります(簡単なCTFチャレンジのように)。

Ret2win

この種のCTFチャレンジでは、バイナリ内に 決して呼び出されない 関数があり、勝つために呼び出す必要があります。これらのチャレンジでは、戻りアドレスを上書きするためのオフセットを見つけ、呼び出す関数のアドレスを見つけるだけで済みます(通常、ASLRは無効になります)ので、脆弱な関数が戻ると、隠れた関数が呼び出されます:

Ret2win

スタックシェルコード

このシナリオでは、攻撃者はスタックにシェルコードを配置し、制御されたEIP/RIPを悪用してシェルコードにジャンプし、任意のコードを実行することができます:

Stack Shellcode

ROP & Ret2... テクニック

このテクニックは、前のテクニックに対する主要な保護を回避するための基本的なフレームワークです:実行可能なスタックなし(NX)。これにより、バイナリ内の既存の命令を悪用して任意のコマンドを実行する他のいくつかのテクニック(ret2lib、ret2syscall...)を実行することができます:

ROP - Return Oriented Programing

ヒープオーバーフロー

オーバーフローは常にスタック内で発生するわけではなく、例えばヒープ内で発生することもあります:

Heap Overflow

保護の種類

脆弱性の悪用を防ぐためのいくつかの保護があります。詳細は以下を確認してください:

Common Binary Exploitation Protections & Bypasses
HackTricksをサポートする

Last updated