彩票游戏代码漏洞利用原理探究:输入16位数字为何能中奖?
问题描述
我在对一段C语言彩票游戏代码做漏洞利用时,发现输入16个不同数字就能中奖。我查看了entry和results数组的内存地址,但搞不懂二者的关联,也不确定是不是和漏洞有关。想问问这个现象是不是内存位置导致的,具体原理是什么?
目标代码
#include <stdio.h> #include <stdlib.h> #include<time.h> int main(int argc, char *argv[]) { int entry[6]; int results[6]; int i = 0, tmp = 0; /* Generate power balls */ srand(time(NULL)); for (int i = 0; i < 6; i++) { results[i] = rand() % 99; } printf("RULE: You are to enter a sequence of six two-digit numbers between 10 and 99.\n"); printf(" - The numbers should be separated by a single space.\n"); printf(" - The seventh number should be -1, indicating the completion of the sequence\n"); printf("Enter the numbers:\n"); while(tmp != -1) { scanf("%d", &tmp); if (tmp == -1) break; entry[i] = tmp; i++; } /* Check results */ int match = 0; for (int i = 0; i < 6; i++) { printf("The lottery number is: %d\n", results[i]); printf("Your guess is: %d\n", entry[i]); if (results[i] == entry[i]) { match++; } } if (match != 6){ printf("Unfortunately, there has been a mismatch! Better luck next time!\n"); } else { printf("Congratulations, all the numbers match! You have won a gazillion dollars\n"); } return 0; }
漏洞原理分析
这个现象确实是栈内存布局越界覆盖导致的,核心逻辑拆解如下:
1. 局部变量的栈内存排列规律
C语言中,函数的局部变量会被编译器分配在栈空间中,通常按声明顺序反向排列(不同编译器细节可能有差异,但核心逻辑一致)。这段代码里,main函数的局部变量栈布局(从高地址到低地址)大致为:
tmp(int类型,占4字节)i(int类型,占4字节)results[6](6个int,共24字节)entry[6](6个int,共24字节)
2. 无边界限制的数组越界写入
代码的输入循环完全没有限制i的最大值:只要输入的不是-1,就会持续执行entry[i] = tmp; i++;。而entry数组只有6个元素,合法下标范围是0-5。当i超过5后,写入操作就会越界,覆盖entry数组之后的栈内存——也就是results数组的空间。
3. 输入16个数字中奖的具体逻辑
我们可以通过内存偏移计算来理解:
- 当
i从6开始,每输入一个数字,就会覆盖results数组的一个元素(i=6对应results[0],i=7对应results[1],直到i=11覆盖results[5])。 - 继续输入数字,
i会超过11,开始覆盖i和tmp自身的内存。当i被覆盖为0后,后续输入的数字会重新从entry[0]开始写入,把之前的entry数组内容也覆盖成新输入的值。 - 最后输入
-1结束循环时,entry和results数组的6个元素已经被你输入的数字统一覆盖成相同值,所以比对时match等于6,直接触发中奖逻辑。
本质就是利用无限制的数组越界写入,把原本随机生成的results数组改成和entry数组完全一致的内容,从而实现“全匹配”中奖。
内容的提问来源于stack exchange,提问作者user19980968
相关产品推荐
相关产品推荐

