random & Kindergarten
Cryptography · Харуул Занги U18: 2022 · unknown
random
Problem
Description:
XOR use custom random function
🧠 Understanding the Script
Initialization:
n
is initialized as the current Unix time divided by 10000. This meansn
starts with a value based on when the script is run.xor
is an empty list that will store the XORed values of the flag and the generated key.
random()
Function:This function generates a pseudo-random number by performing a series of arithmetic operations on
n
.The operations include additions, multiplications, XORs, and modulo operations.
Finally, it returns
n % 100
, ensuring the result is between 0 and 99.
XOR()
Function:Generates a key list where each element is a random number from the
random()
function. The length of the key matches the length of the flag.Performs an XOR operation between each byte of the flag and the corresponding key byte, storing the result in the
xor
list.
Reading the Flag:
Reads the flag from
flag.txt
and strips any extra whitespace.
Execution:
Calls
XOR()
and prints the resulting XOR list.
🎯 Goal
We need to recover the original flag from this XOR list. To do this, we need to reverse the XOR operation, which requires knowing the key used. Since the key is generated based on the random()
function, which depends on the initial n
(derived from the time the script was run), we need to find the correct n
that was used.
👽 Approach
Understand the
random()
Function:The
random()
function is deterministic given the same initialn
. It performs a series of operations to generate the nextn
and returnsn % 100
.The sequence of
n
values (and thus the key) depends solely on the initialn
.
Brute-Force Initial
n
:Since
n
is derived from the Unix time divided by 10000, it's a large but not infinite range.However, the exact time isn't provided, so we need to find
n
such that when we generate the key and XOR it with the givenxor
list, we get a meaningful flag (likely starting withflag{
).
Generate Possible
n
Values:Unix time is the number of seconds since January 1, 1970. As of now (2023), it's around 1.6 billion.
n = int(time.time() / 10000)
would be around 160,000 to 170,000 for recent times.We can brute-force
n
in this range, generate the key, and see if the decrypted flag makes sense.
Decryption Process:
For a candidate
n
, generate the key sequence of the same length as thexor
list (36 bytes).XOR each element of the
xor
list with the corresponding key byte to get the original flag bytes.Check if the result is a printable string, especially starting with
HZ
.
Exploitation Code
Kindergarten
Cryptography · Харуул Занги: 2024 · zjzoloo
🧠 Understanding the Code
Characters Used (
CHILDREN
):CHILDREN
is a string containing printable characters (letters and digits) plus'\\='
. So, it's[a-zA-Z0-9\\=]
, totaling 64 characters (sincestring.printable[:62]
is 62, plus 2 more).
Finite Field (
GF(64)
):Z = list(GF(64))
creates a list of elements in the finite field of order 64. This means each element inZ
corresponds to a unique element inGF(64)
.
Mapping Characters to Field Elements (
maptokindergarten
):maptokindergarten(c)
takes a characterc
fromCHILDREN
and returns the corresponding element fromZ
based on its index inCHILDREN
.
Key Generation (
keygen
):keygen(l)
generates a key by selectingl
random non-zero elements fromZ
(sincerandint(1, 63)
excludes 0) and multiplies them together (math.prod(key)
). Here,l=14
, so the key is the product of 14 random non-zero elements fromGF(64)
.
Encryption (
encrypt
):First, the message (
msg
) is base64 encoded (m64
).Then,
pkey
is computed askey**5 + key**3 + key**2 + 1
.For each byte
m
in the base64 encoded message:Convert
m
to a character, map it toGF(64)
usingmaptokindergarten
.Multiply this by
pkey
inGF(64)
.Find the index of the resulting element in
Z
and get the corresponding character fromCHILDREN
.
Concatenate all these characters to form the encrypted string
enc
.
Given Output:
Output: HudnBsx03TGdBIK4NS50=vlo=8NoMouoMSCdBLm9yoK41vl03M0Q
🎯 Goal
We need to recover the original flag
from the given enc
output, knowing how encrypt
works.
👽 Approach
To decrypt, we need to reverse the encryption process:
Understand
pkey
:pkey = key**5 + key**3 + key**2 + 1
.Since operations are in
GF(64)
,pkey
is a polynomial inGF(64)
.
Decryption Steps:
For each character in
enc
, find its index inCHILDREN
to get the correspondingGF(64)
element.To reverse the multiplication by
pkey
, we need to multiply by the inverse ofpkey
inGF(64)
.Then, map the resulting
GF(64)
element back to a character inCHILDREN
.Finally, decode the resulting base64 string to get the original
flag
.
Finding
pkey
:The challenge is that we don't know
key
, but we knowkey
is the product of 14 random non-zero elements inGF(64)
.However,
GF(64)
is a field, so every non-zero element has a multiplicative inverse.The size of
GF(64)
is small (64 elements), so we can brute-force possiblekey
values.
Brute-Forcing
key
:Since
key
is the product of 14 non-zero elements, and multiplication inGF(64)
is closed,key
is also a non-zero element.There are 63 possible non-zero elements for
key
.For each possible
key
, computepkey
, then its inverse, and try to decryptenc
.
Checking Valid Decryption:
After decrypting, we'll get a base64 string. Decoding this should give us printable characters (the flag).
We can check if the decoded result makes sense (e.g., starts with
HZ
).
Exploitation Code
To run the exploit
sage exp.sage
Last updated