{ "topic": "buffer-overflow", "type": "code_reading", "schema_version": "1.0.0", "generated": "2026-09-17T00:00:00+08:00", "questions": [ { "id": "cr-001", "type": "code_reading", "difficulty": 2, "tags": [ "缓冲区溢出", "栈溢出" ], "code": "#include \n#include \n\nvoid vulnerable_function(char *input) {\n char buffer[64];\n strcpy(buffer, input);\n printf(\"Input received: %s\\n\", buffer);\n}\n\nint main(int argc, char *argv[]) {\n if (argc != 2) {\n printf(\"Usage: %s \\n\", argv[0]);\n return 1;\n }\n vulnerable_function(argv[1]);\n return 0;\n}", "language": "c", "sub_questions": [ { "index": 1, "type": "single_choice", "question": "这段代码存在什么安全漏洞?", "options": { "A": "SQL 注入漏洞", "B": "缓冲区溢出漏洞", "C": "跨站脚本(XSS)漏洞", "D": "整数溢出漏洞" }, "answer": "B", "explanation": "vulnerable_function 中使用 strcpy() 将用户输入复制到大小为 64 字节的 buffer 中。由于 strcpy() 不检查输入长度,当 argv[1] 的长度超过 63 字节(含 '\\0' 终止符)时,会发生缓冲区溢出,覆盖栈上 buffer 之后的数据。这是典型的栈缓冲区溢出漏洞。" }, { "index": 2, "type": "single_choice", "question": "如果 argv[1] 的长度为 200 字节,在 32 位 x86 系统上,溢出数据可能覆盖以下哪些内容?(不考虑编译器保护)", "options": { "A": "仅 buffer 数组的相邻变量", "B": "buffer 数组、保存的 EBP 和函数返回地址", "C": "仅函数返回地址", "D": "全局变量区的数据" }, "answer": "B", "explanation": "buffer[64] 位于栈上,溢出 200 字节的数据会依次覆盖:buffer 之后的栈空间、保存的 EBP(帧指针,通常 4 字节)、函数返回地址(4 字节),以及 main 函数的栈帧内容。200 字节远超 buffer 大小,足以覆盖返回地址及更多栈内容。注意这里假设没有 Stack Canary 等保护。" }, { "index": 3, "type": "single_choice", "question": "如何修复这段代码中的安全漏洞?", "options": { "A": "将 buffer 大小改为 256", "B": "使用 strncpy(buffer, input, sizeof(buffer)) 并确保字符串以 '\\0' 结尾", "C": "在 strcpy 之前检查 strlen(input) < 64 即可,无需更换函数", "D": "将 buffer 声明为 static 变量" }, "answer": "B", "explanation": "最正确的修复是使用有长度限制的安全函数。strncpy(buffer, input, sizeof(buffer)) 限制复制的字节数不超过 buffer 大小,并且需要确保 buffer[sizeof(buffer)-1] = '\\0' 以保证字符串终止。选项 A 只是增大了缓冲区但未消除漏洞。选项 C 的检查存在 TOCTOU(检查与使用之间的时间窗口)问题,且仍有竞态风险。选项 D 改变存储位置但不解决溢出问题。" }, { "index": 4, "type": "short_answer", "question": "假设该程序使用 gcc -fstack-protector-strong 编译,当发生栈溢出时程序的行为会有什么变化?请简要解释。", "answer": "使用 -fstack-protector-strong 编译后,编译器会在 buffer 和保存的 EBP 之间插入一个 Stack Canary 随机值。当 buffer 发生溢出时,溢出数据会先覆盖 canary 值。在函数返回之前,程序会检查 canary 是否被修改。如果 canary 被篡改,程序会调用 __stack_chk_fail() 函数,输出错误信息(如 '*** stack smashing detected ***')并终止程序(abort),从而阻止攻击者利用溢出劫持执行流。", "explanation": "Stack Canary 是一种编译器级别的栈溢出检测机制。编译器在函数的局部变量和保存的寄存器/返回地址之间插入一个随机的 canary 值。函数返回前检查该值的完整性,若被修改则立即终止程序。这能有效检测并阻止栈溢出攻击,但攻击者仍可能通过信息泄露获取 canary 值来绕过此保护。" } ], "explanation": "", "source": null, "related": [], "question": "请阅读以下代码,分析其中的安全问题并回答相关问题。" } ] }