整数溢出漏洞详解:网络安全小白从零入门

文章目录

    • [1. 什么是整数溢出?](#1. 什么是整数溢出?)
    • [2. 整数溢出的原理(二进制视角)](#2. 整数溢出的原理(二进制视角))
    • [3. 常见整数类型位宽一览](#3. 常见整数类型位宽一览)
    • [4. 整数溢出在网络安全中的危害](#4. 整数溢出在网络安全中的危害)
    • [5. 真实世界案例](#5. 真实世界案例)
    • [6. CTF例题:菜狗杯 - 茶歇区](#6. CTF例题:菜狗杯 - 茶歇区)
      • [攻击 Payload](#攻击 Payload)
    • [7. 如何防范整数溢出?(开发者必备 checklist)](#7. 如何防范整数溢出?(开发者必备 checklist))
    • [8. 总结与学习建议](#8. 总结与学习建议)

1. 什么是整数溢出?

整数溢出(Integer Overflow) 是指:计算机用固定长度的二进制位(bit)来存储整数,当运算结果超出这个"容器"的容量时,就会发生"溢出"------数值被截断或回绕,导致程序行为异常。

比喻

想象一个只能显示两位数字的汽车里程表(00~99):

  • 当前是 99 公里
  • 开了 1 公里后 → 本该是 100,但表只能存两位数字 → 直接回绕成 00

计算机的整数类型(int、long、uint 等)就像这个里程表,每种类型都有固定的"位宽"(bit width),超过上限就会"洒出来"。


2. 整数溢出的原理(二进制视角)

计算机内存中,整数是用二进制补码存储的。

示例:8位无符号整数(uint8,范围 0~255)

  • 255 的二进制:11111111
  • 执行 255 + 1
    • 计算结果:1 00000000(9位)
    • 8位容器只能存低8位 → 00000000(即 0)

代码演示(Python 模拟 8 位溢出)

python 复制代码
def uint8_add(a: int, b: int) -> int:
    return (a + b) & 0xFF  # 保留低8位,模拟溢出

print(uint8_add(255, 1))   # 输出: 0
print(uint8_add(200, 100)) # 输出: 44 (300 - 256 = 44)

有符号整数(补码表示)

有符号整数最高位是符号位(0=正,1=负)。
32位有符号 int(int32) 范围:

  • 最小值:-21474836480x80000000
  • 最大值:21474836470x7FFFFFFF

溢出示例

c 复制代码
// C语言示例(编译运行可验证)
#include <stdio.h>
#include <limits.h>

int main() {
    int max = INT_MAX;           // 2147483647
    printf("MAX: %d\n", max);
    printf("MAX + 1: %d\n", max + 1);  // 输出: -2147483648(溢出回绕到最小负数)
    return 0;
}

3. 常见整数类型位宽一览

位宽 类型 最小值 最大值
8位 uint8 0 255
8位 int8 -128 127
16位 uint16 0 65,535
16位 int16 -32,768 32,767
32位 uint32 0 4,294,967,295
32位 int32 -2,147,483,648 2,147,483,647
64位 uint64 0 18,446,744,073,709,551,615
64位 int64 -9,223,372,036,854,775,808 9,223,372,036,854,775,807

PHP 中 :64位系统下 int 默认就是 int64 ,可通过 PHP_INT_MAX 常量获取最大值。

php 复制代码
<?php
echo PHP_INT_MAX;        // 输出: 9223372036854775807
var_dump(PHP_INT_MAX + 1); // 输出: float(9.223372036854776E+18)
// PHP 7+ 会自动转为 float,但乘法运算中仍可能产生回绕
?>

4. 整数溢出在网络安全中的危害

溢出本身不会让程序崩溃,但它会让逻辑判断失效,成为攻击者的切入点:

  1. 绕过大小/数量限制

    文件上传检查 if ($size > 2*1024*1024),若 $size 接近 PHP_INT_MAX,乘以系数后溢出 → 检查失效。

  2. 缓冲区溢出(Buffer Overflow)

    计算内存分配大小时溢出,导致实际分配内存远小于预期,后续写入数据覆盖其他内存 → 可执行任意代码(RCE)。

  3. 数组索引越界

    用溢出后的负数作为数组下标,读取敏感内存。

  4. 逻辑绕过(权限、价格、计数器)

    游戏货币、区块链转账、电商折扣计算等都可能被刷。

经典代码漏洞示例(文件大小检查绕过)

php 复制代码
<?php
$max_size = 2 * 1024 * 1024; // 2MB
$file_size = $_FILES['file']['size']; // 用户可控

// 危险!未做溢出检查
if ($file_size > $max_size) {
    die("文件太大!");
}

move_uploaded_file(...); // 实际可上传超大恶意文件
?>

改进版(推荐)

php 复制代码
<?php
$file_size = (float) $_FILES['file']['size']; // 转为 float 避免溢出

if ($file_size > 2 * 1024 * 1024 || $file_size < 0) {
    die("文件大小非法!");
}

// 乘法前显式检查
if ($file_size > PHP_INT_MAX / 10) {  // 防止后续乘法溢出
    trigger_error("潜在整数溢出!", E_USER_WARNING);
    die("操作拒绝");
}
?>

5. 真实世界案例

  • OpenSSH 整数溢出(2000s)size * 1024 溢出导致分配 0 字节缓冲区 → 远程代码执行。
  • Ariane 5 火箭爆炸:64位浮点数转16位整数时溢出,火箭自毁(损失5亿美元)。
  • 区块链智能合约 :许多 Solidity 合约因 uint256 溢出被刷币(后引入 SafeMath 库)。
  • 游戏外挂:数量/金钱计算溢出,实现无限刷资源。

6. CTF例题:菜狗杯 - 茶歇区

这道题完美体现了"整数溢出绕过限制":

  • 题目背景:你有 1024 FP(资金),每种食物得分 = 消耗 FP(比率 1:1)。目标得分 > 114514 才能出 flag。
  • 正常情况下:最多得 1024 分 → 不可能。
  • 漏洞点 :后台用 int64 计算 FP = FP - count * costscore = count * score

攻击 Payload

第一次提交(触发 FP 溢出):

  • 咖啡(e)填:932337203685477581(18位,刚好让 count * cost 溢出)
  • 其他食物填 0

第二次提交

  • 再次填相同数字(或 1000000000000000000)
  • 提交后 FP 变成极大正数,得分轻松超过 114514,flag 弹出。

Python 模拟器(本地复现)

python 复制代码
PHP_INT_MAX = 9223372036854775807
FP = 1024
count = 932337203685477581
cost = 1

# 第一次购买(模拟溢出)
new_fp = FP - (count * cost)          # PHP 中可能回绕成负数或极大值
print("第一次后 FP:", new_fp)          # 通常为极大正数

# 第二次购买
score = count * 10                    # 咖啡得分10
print("最终得分:", score)             # 远超114514

Burp Suite 抓包技巧

  1. 正常提交一次,抓到 POST 数据。
  2. 用 Repeater 重复发送两次 payload。
  3. 修改 e=932337203685477581

正常做法(不用BP)参考:ctfshow菜狗杯wp2(新手必刷)(Web部分)


7. 如何防范整数溢出?(开发者必备 checklist)

  1. 输入强制类型转换

    php 复制代码
    $user_input = (float) $_POST['count']; // 优先用 float
  2. 乘法前显式检查

    php 复制代码
    if ($count > 0 && $cost > PHP_INT_MAX / $count) {
        die("数值过大,拒绝操作!");
    }
  3. 使用安全库

    • PHP:gmp 扩展处理任意精度整数。
    • C/C++:SafeInt__int128
    • Python:原生支持无限大整数,无需担心。
  4. 边界检查 + 日志

    所有用户输入必须经过 is_numeric() + 范围检查 + trigger_error

  5. 代码审计 checklist

    • 文件大小(filesize()
    • 数组索引(isset() + count()
    • 内存分配(str_repeat($str, $size)
    • 循环计数器

8. 总结与学习建议

整数溢出本质是:"计算机的整数不是数学上的无限大,而是有容量上限的固定容器,装不下就会洒出来,洒出来的那一刻就是漏洞。"

下一步行动

  1. 本地搭建 PHP 环境,运行上面的所有代码示例。
  2. 去 CTF 平台搜"整数溢出"标签,再刷 2-3 道题。
  3. 阅读 OWASP Top 10 中的"注入"和"安全配置错误"章节。
  4. 推荐书籍:《白帽子讲 Web 安全》、《C 语言安全编程》。

最后思考:安全从来不是"加固",而是"从设计之初就考虑边界"。下次写任何数量、价格、索引相关的代码,都提醒自己问一句:"这个数会不会溢出?"

参考

  • PHP 官方文档:PHP_INT_MAX
  • 文章《PHP的整数溢出漏洞:在处理文件大小或数组索引时的边界检查与位宽问题》
  • 菜狗杯 2025 茶歇区题目
相关推荐
其实防守也摸鱼3 小时前
CTF密码学综合教学指南--第三章
开发语言·网络·python·安全·网络安全·密码学
其实防守也摸鱼3 小时前
CTF密码学综合教学指南--第四章
网络·笔记·安全·网络安全·密码学·ctf
DevilSeagull3 小时前
电脑上安装的服务会自动消失? 推荐项目: localhostSCmanager. 更好管理你的服务!
测试工具·安全·react·vite·localhost·hono·trpc
@insist1234 小时前
信息安全-防火墙技术演进全景:从代理NAT 到下一代及专项防火墙
网络·安全·web安全·软考·信息安全工程师·软件水平考试
不会编程的懒洋洋6 小时前
C# P/Invoke 基础
开发语言·c++·笔记·安全·机器学习·c#·p/invoke
时空系7 小时前
第10篇:归属权与借用——Rust的安全保障 Rust中文编程
开发语言·安全·rust
Chockmans7 小时前
春秋云境CVE-2017-3506
安全·web安全·网络安全·系统安全·安全威胁分析·春秋云境·cve-2017-3506
开开心心就好7 小时前
近200个工具的电脑故障修复合集
安全·智能手机·pdf·电脑·consul·memcache·1024程序员节
一拳一个娘娘腔8 小时前
精通Metasploit Framework:网络安全攻防实战与全链路渗透解析
安全
一切皆是因缘际会8 小时前
下一代 AI 架构:基于记忆演化与单向投影的安全智能系统
大数据·人工智能·深度学习·算法·安全·架构