Stack Canaries
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
StackGuardは、EIP (Extended Instruction Pointer)の前に特別な値であるcanaryを挿入します。具体的には0x000aff0d
(null、改行、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もローカル変数を保護しないことを示しています。
-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バイトを1バイトずつ推測するブルートフォース攻撃が可能になります。しかし、fork()
の後にexecve()
を使用すると、メモリ空間が上書きされ、攻撃が無効になります。vfork()
は、子プロセスが書き込みを試みるまで複製なしで実行できるため、プロセス作成とメモリ処理に異なるアプローチを提供します。
x64
バイナリでは、canaryクッキーは**0x8
バイトのqwordです。最初の7バイトはランダムで、最後のバイトはnullバイト**です。
x86
バイナリでは、canaryクッキーは**0x4
バイトのdwordです。最初の3バイトはランダムで、最後のバイトはnullバイト**です。
両方のcanaryの最下位バイトはnullバイトです。なぜなら、それはスタックの最初に来るため、文字列を読み取る関数はそれを読み取る前に停止します。
canaryを漏洩させ、その後自分の値で上書きします(例:バッファオーバーフロー)。
子プロセスでcanaryがフォークされる場合、1バイトずつブルートフォースすることが可能かもしれません:
バイナリに興味深い漏洩または任意の読み取り脆弱性がある場合、漏洩させることが可能かもしれません:
スタックに保存されたポインタを上書きする
スタックがスタックオーバーフローに脆弱な場合、上書き可能な文字列や関数のアドレスを含む可能性があります。これにより、canaryに到達することなく脆弱性を悪用できます。確認してください:
マスター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/
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)