Tags: crypto math

Rating:

Notice that ' '(chr(32)) becomes 0 after passing stov(),
we can construct a string with ' 's and only one chr(33) in each half, so

$$\begin{bmatrix} a_{11}& a_{12} &\dots & a_{1n}\\ a_{21}& a_{22} &\dots & a_{2n}\\ a_{31}& a_{32} &\dots & a_{3n}\\ \vdots & \vdots& \ddots & \vdots\\ a_{n1}& a_{n2} &\dots & a_{nn} \end{bmatrix} \begin{bmatrix} 0\\ \vdots\\ x_j=1\\ \vdots\\ 0 \end{bmatrix}= \begin{bmatrix} a_{1j}\\ a_{2j}\\ a_{3j}\\ \vdots\\ a_{nj} \end{bmatrix}$$

(The latex may be broken here, please refer to the original writeup)

In each query, we can reveal two columns of A, so in 10 queries, we can reveal all data in A. Then you can just use A to encrypt fakeflag2 and get the flag.

py
#!/usr/local/bin/python3

import numpy as np

n = 20

A = np.matrix([[0 for i in range(n)] for i in range(n)])

def stov(s):
return np.array([ord(c)-32 for c in s])

def vtos(v):
return ''.join([chr(v[0,i]+32) for i in range(n)])

def encrypt(s):
return vtos(np.matmul(A, stov(s))%95)

from pwn import *
# context(log_level='debug')

r = remote('lac.tf',31140)
# r = process(['python','chall.py'])

r.recvuntil(b'On the hill lies a stone. It reads:\n')
r.recvline()
r.recvline()
r.recvuntil(b'\nA mysterious figure offers you 10 attempts at decoding the stone:')
for i in range(10):
r.sendline(b' '*i+b'!'+b' '*(19-i)+b' '*(i+10)+b'!'+b' '*(9-i))
r.recvuntil(b'Incorrect:\n')
r1 = stov(r.recvline().decode().strip('\n'))
r2 = stov(r.recvline().decode().strip('\n'))
for j in range(n):
A[j,i] = r1[j]
A[j,i+10] = r2[j]

r.recvuntil(b"Create a new stone that decodes to the following:\n")
fakeflag2 = r.recvline().strip().decode()
f3 = encrypt(fakeflag2[:n])
f4 = encrypt(fakeflag2[n:])

r.recvuntil(b'Enter the first half: ')
r.sendline(f3.encode())
r.recvuntil(b'Enter the second half: ')
r.sendline(f4.encode())

r.interactive()

# lactf{tHeY_SaiD_l!NaLg_wOuLD_bE_fUN_115}


Original writeup (https://tiefsee5037008.github.io/posts/LA-CTF-Writeup/#hill-easy).