the-eye
I believe we’ve reached the end of our journey. All that remains is to collapse the innumerable possibilities before us.
The program initializes the pseudo-random engine with the current time, then shuffles the flag a few times and prints it:
The shuffle function just generates a random number and performs some swaps:
Since the current time is used as a seed, we can sync our time with the server by calling time(NULL)
as the same time. Then, calls to rand()
will mirror the ones on the server.
We can test this using libdebug
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
libc = ctypes.CDLL("/usr/lib/libc.so.6")
io = debugger("./the-eye")
io.run()
io.breakpoint(0x137e)
io.breakpoint(0x13b9)
io.cont()
process_time = io.regs.rax
io.cont()
flag = io.memory[io.regs.rdi, 28].decode()
log.success(flag)
flag = list(flag)
time = libc.time(None)
assert time == process_time
The assert passes, so our theory is correct. Now we need to reverse the shuffling algorithm. We just need to generate all numbers at the beginning and, starting with the last one and going backwards, reverse the shuffling algorithm. The loop in shuffle
goes backwards, so we need to go forwards.
Also, since the time on the server might differ a bit, we can bruteforce the seed by offsetting it a bit. We know the flag format, so we know when it was successfully decrypted.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import ctypes
from pwn import *
from libdebug import debugger
def shuffle(list_, rands):
for i in range(len(list_)):
rand = rands[i]
list_[i], list_[rand % (i + 1)] = list_[rand % (i + 1)], list_[i]
libc = ctypes.CDLL("/usr/lib/libc.so.6")
# io = debugger("./the-eye")
# io.run()
# io.breakpoint(0x137e)
# io.breakpoint(0x13b9)
# io.cont()
# process_time = io.regs.rax
# io.cont()
# flag = io.memory[io.regs.rdi, 28].decode()
# log.success(flag)
# flag = list(flag)
#
# time = libc.time(None)
# assert time == process_time
# libc.srand(process_time)
io = remote("chall.lac.tf", 31313)
# io = process("./the-eye")
flag = io.recvline().strip().decode()
log.info(flag)
flag = list(flag)
def solve(flag, seed):
libc.srand(seed)
flag = flag[:]
rands = [libc.rand() for _ in range(len(flag) * 22)][::-1]
for i in range(22):
shuffle(flag, rands[i * len(flag):((i + 1) * len(flag))])
flag = "".join(flag)
if "lactf{" in flag:
log.success(flag)
for i in range(1000):
solve(flag, libc.time(None) + i)
solve(flag, libc.time(None) - i)