スタックカナリア
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) の前に カナリア として知られる特別な値 0x000aff0d
(ヌル、改行、EOF、キャリッジリターンを表す)を挿入して、バッファオーバーフローから保護します。しかし、recv()
、memcpy()
、read()
、および bcopy()
のような関数は依然として脆弱であり、EBP (Base Pointer) を保護することはありません。
StackShield は、すべての戻りアドレス (EIPs) を保存する グローバルリターンスタック を維持することで、StackGuard よりも洗練されたアプローチを取ります。この設定により、オーバーフローが発生しても害を及ぼさず、保存された戻りアドレスと実際の戻りアドレスを比較してオーバーフローの発生を検出できます。さらに、StackShield は戻りアドレスを境界値と照合して、EIP が期待されるデータ空間の外を指しているかどうかを検出できます。しかし、この保護は Return-to-libc、ROP (Return-Oriented Programming)、または ret2ret のような技術によって回避可能であり、StackShield がローカル変数を保護しないことを示しています。
Stack Smash Protector (ProPolice) -fstack-protector
:
このメカニズムは、EBP の前に カナリア を配置し、ローカル変数を再配置してバッファをより高いメモリアドレスに配置し、他の変数を上書きしないようにします。また、ローカル変数の上にスタックで渡された引数を安全にコピーし、これらのコピーを引数として使用します。しかし、8 要素未満の配列やユーザーの構造内のバッファは保護されません。
カナリア は /dev/urandom
から派生したランダムな数またはデフォルト値 0xff0a0000
です。これは TLS (Thread Local Storage) に保存され、スレッド間で共有メモリ空間がスレッド固有のグローバルまたは静的変数を持つことを可能にします。これらの変数は最初に親プロセスからコピーされ、子プロセスは親や兄弟に影響を与えずにデータを変更できます。しかし、fork()
を使用して新しいカナリアを作成しない場合、すべてのプロセス(親と子)は同じカナリアを共有し、脆弱になります。i386 アーキテクチャでは、カナリアは gs:0x14
に保存され、x86_64 では fs:0x28
に保存されます。
このローカル保護は、攻撃に脆弱なバッファを持つ関数を特定し、これらの関数の先頭にカナリアを配置するコードを注入し、末尾でその整合性を確認します。
ウェブサーバーが fork()
を使用すると、カナリアをバイト単位で推測するブルートフォース攻撃が可能になります。しかし、fork()
の後に execve()
を使用すると、メモリ空間が上書きされ、攻撃が無効になります。vfork()
は、子プロセスが書き込みを試みるまで複製なしで実行できるため、プロセス作成とメモリ処理に異なるアプローチを提供します。
長さ
x64
バイナリでは、カナリアクッキーは 0x8
バイトの qword です。最初の 7 バイトはランダムで、最後のバイトは ヌルバイト です。
x86
バイナリでは、カナリアクッキーは 0x4
バイトの dword です。最初の 3 バイトはランダムで、最後のバイトは ヌルバイト です。
caution
両方のカナリアの最下位バイトはヌルバイトです。これは、スタックの最初に低いアドレスから来るため、文字列を読み取る関数はそれを読み取る前に停止します。
バイパス
カナリアを漏洩させ、その後自分の値で上書きします(例:バッファオーバーフロー)。
- カナリアが子プロセスでフォークされる場合、1 バイトずつ ブルートフォース することが可能かもしれません:
BF Forked & Threaded Stack Canaries
- バイナリに興味深い 漏洩または任意の読み取り脆弱性 がある場合、漏洩させることができるかもしれません:
- スタックに保存されたポインタの上書き
スタックがスタックオーバーフローに脆弱な場合、上書き可能な文字列や関数へのアドレスを含む可能性があります。これにより、スタックカナリアに到達することなく脆弱性を悪用できます。確認してください:
- マスターとスレッドカナリアの両方を変更
カナリアで保護されたスレッド関数のバッファ オーバーフロー を使用して、スレッドのマスターカナリアを変更できます。その結果、チェックが同じ(ただし変更された)2つのカナリアで使用されるため、緩和策は無効になります。
さらに、カナリアで保護されたスレッド関数のバッファ オーバーフロー を使用して、TLS に保存されたマスターカナリアを変更することもできます。これは、スレッドの スタック での bof を介して TLS が保存されているメモリ位置に到達することが可能であるためです。
その結果、チェックが同じ(ただし変更された)2つのカナリアで使用されるため、緩和策は無効になります。
この攻撃は次の書き込みで実行されます: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 エントリをダミー関数に変更し、カナリアが変更されてもプログラムがブロックされないようにできます。
この攻撃は次の書き込みで実行されます: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を提出してハッキングトリックを共有してください。