Stack Canaries
Reading time: 10 minutes
tip
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
StackGuard と StackShield
StackGuard は、EIP (Extended Instruction Pointer) の前に canary として知られる特別な値を挿入します。具体的には 0x000aff0d
(ヌル、改行、EOF、キャリッジリターンを表す)で、バッファオーバーフローから保護します。しかし、recv()
、memcpy()
、read()
、および bcopy()
のような関数は依然として脆弱であり、EBP (Base Pointer) を保護しません。
StackShield は、Global Return Stack を維持することで、StackGuard よりも洗練されたアプローチを取ります。これにより、すべての戻りアドレス(EIPs)が保存され、オーバーフローが発生しても害を及ぼさないようにします。保存された戻りアドレスと実際の戻りアドレスを比較することで、オーバーフローの発生を検出できます。さらに、StackShield は戻りアドレスを境界値と照合して、EIP が期待されるデータ空間の外を指しているかどうかを検出できます。しかし、この保護は Return-to-libc、ROP (Return-Oriented Programming)、または ret2ret のような技術によって回避可能であり、StackShield がローカル変数を保護しないことを示しています。
Stack Smash Protector (ProPolice) -fstack-protector
:
このメカニズムは、EBP の前に canary を配置し、ローカル変数を再配置してバッファを高いメモリアドレスに配置し、他の変数を上書きできないようにします。また、ローカル変数の上にスタックで渡された引数を安全にコピーし、これらのコピーを引数として使用します。しかし、8 要素未満の配列やユーザーの構造内のバッファは保護しません。
canary は /dev/urandom
から派生したランダムな数またはデフォルト値 0xff0a0000
です。これは TLS (Thread Local Storage) に保存され、スレッド間で共有メモリ空間がスレッド固有のグローバルまたは静的変数を持つことを可能にします。これらの変数は最初に親プロセスからコピーされ、子プロセスは親や兄弟に影響を与えずにデータを変更できます。しかし、fork()
を使用して新しい canary を作成しない場合、すべてのプロセス(親と子)は同じ canary を共有し、脆弱になります。i386 アーキテクチャでは、canary は gs:0x14
に保存され、x86_64 では fs:0x28
に保存されます。
このローカル保護は、攻撃に脆弱なバッファを持つ関数を特定し、これらの関数の先頭にコードを注入して canary を配置し、末尾でその整合性を確認します。
ウェブサーバーが fork()
を使用すると、canary バイトをバイト単位で推測するためのブルートフォース攻撃が可能になります。しかし、fork()
の後に execve()
を使用するとメモリ空間が上書きされ、攻撃が無効になります。vfork()
は、子プロセスが書き込みを試みるまで複製なしで実行できるようにし、その時点で複製が作成され、プロセスの作成とメモリ管理に異なるアプローチを提供します。
長さ
x64
バイナリでは、canary クッキーは 0x8
バイトの qword です。最初の 7 バイトはランダムで、最後のバイトは ヌルバイトです。
x86
バイナリでは、canary クッキーは 0x4
バイトの dword です。最初の 3 バイトはランダムで、最後のバイトは ヌルバイトです。
caution
両方の canary の最下位バイトはヌルバイトであり、これはスタックの最初に来るため、文字列を読み取る関数はそれを読み取る前に停止します。
バイパス
canary を漏洩させ、その後自分の値で上書きします(例:バッファオーバーフロー)。
- canary が子プロセスでフォークされる場合、1 バイトずつ ブルートフォース することが可能かもしれません:
BF Forked & Threaded Stack Canaries
- バイナリに興味深い 漏洩または任意の読み取り脆弱性 がある場合、漏洩させることができるかもしれません:
- スタックに保存されたポインタの上書き
スタックがスタックオーバーフローに脆弱な場合、上書き可能な文字列や関数のアドレスを含む可能性があります。これにより、スタック canary に到達することなく脆弱性を悪用できます。確認してください:
- マスターとスレッドの canary の両方を変更
canary で保護されたスレッド関数のバッファ オーバーフロー を使用して、スレッドのマスター canary を変更できます。その結果、チェックが同じ(ただし変更された)2 つの canary で使用されるため、緩和策は無効になります。
さらに、canary で保護されたスレッド関数のバッファ オーバーフロー を使用して、TLS に保存されたマスター canary を変更することもできます。これは、スレッドのスタック内の bof を介して TLS が保存されているメモリ位置に到達することが可能であるためです。
その結果、チェックが同じ(ただし変更された)2 つの canary で使用されるため、緩和策は無効になります。
この攻撃は次の書き込みで実行されます:http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads
また、https://www.slideshare.net/codeblue_jp/master-canary-forging-by-yuki-koike-code-blue-2015 のプレゼンテーションも確認してください。これは、通常 TLS が mmap
によって保存され、スレッドの スタック が mmap
によって生成されることを示唆しており、これにより前述の書き込みで示されたようにオーバーフローが可能になるかもしれません。
__stack_chk_fail
の GOT エントリを変更
バイナリが Partial RELRO を持っている場合、任意の書き込みを使用して __stack_chk_fail
の GOT エントリを、canary が変更されてもプログラムをブロックしないダミー関数に変更できます。
この攻撃は次の書き込みで実行されます:https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/
参考文献
- https://guyinatuxedo.github.io/7.1-mitigation_canary/index.html
- http://7rocky.github.io/en/ctf/htb-challenges/pwn/robot-factory/#canaries-and-threads
- https://7rocky.github.io/en/ctf/other/securinets-ctf/scrambler/
tip
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。