- Published on
1753CTF 2025 - REV - Ancient Memory
- Authors
- Name
- Grzechu
Challenge

Solution
import torch
import torch.nn as nn
import random
import string
FLAG_LENGTH = 26
CHARSET = string.printable[:95] # Bez znaków kontrolnych
CORRECT_FLAG = "1753c{xxxxxxx_xx_xx_xxxxx}" # używane do paddingu, nie do porównania
# Ładowanie modelu
class FlagSimilarityModel(nn.Module):
def __init__(self):
super(FlagSimilarityModel, self).__init__()
self.model = nn.Sequential(
nn.Linear(FLAG_LENGTH * 128, 256),
nn.ReLU(),
nn.Linear(256, 128),
nn.ReLU(),
nn.Linear(128, 64),
nn.ReLU(),
nn.Linear(64, 1),
nn.Sigmoid()
)
def forward(self, x):
return self.model(x)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = FlagSimilarityModel().to(device)
model.load_state_dict(torch.load("model.pt", map_location=device)['model_state_dict'])
model.eval()
# Zamiana flagi na one-hot tensor
def flag_to_tensor(flag):
padded_flag = flag[:FLAG_LENGTH].ljust(FLAG_LENGTH, 'x')
X = torch.zeros(FLAG_LENGTH, 128)
for i, char in enumerate(padded_flag):
X[i, ord(char)] = 1
return X.flatten().to(device)
# Predykcja similarity
def predict_flag_score(flag):
with torch.no_grad():
input_tensor = flag_to_tensor(flag)
score = model(input_tensor.unsqueeze(0)).item()
return score
# Mutacja flagi
def mutate_flag(flag):
idx = random.randint(0, FLAG_LENGTH - 1)
new_char = random.choice(CHARSET)
return flag[:idx] + new_char + flag[idx + 1:]
# Główna pętla ewolucyjna
def evolve_flag(iterations=10000):
best_flag = ''.join(random.choices(CHARSET, k=FLAG_LENGTH))
best_score = predict_flag_score(best_flag)
print(f"Start: {best_flag} | Score: {best_score:.6f}")
for i in range(iterations):
new_flag = mutate_flag(best_flag)
new_score = predict_flag_score(new_flag)
if new_score > best_score:
best_flag = new_flag
best_score = new_score
print(f"[{i}] New best: {best_flag} | Score: {best_score:.6f}")
if best_score > 0.999:
break
print(f"\nFinal guess: {best_flag} | Score: {best_score:.6f}")
if __name__ == "__main__":
evolve_flag()
End lines of the result:
[4468] New best: <753c[Yr1tt3n_1njm#_brt1n} | Score: 0.934130
[4768] New best: <753c{Yr1tt3n_1njm#_brt1n} | Score: 0.937444
[4798] New best: <753c{wr1tt3n_1njm#_brt1n} | Score: 0.943044
[4915] New best: <753c{wr1tt3n_1njmd_brt1n} | Score: 0.943385
[5300] New best: 1753c{wr1tt3n_1njmd_brt1n} | Score: 0.946521
[5719] New best: 1753c{wr1tt3n_1njmd_bra1n} | Score: 0.952286
[6546] New best: 1753c{wr1tt3n_1n_md_bra1n} | Score: 0.957028
[7304] New best: 1753c{wr1tt3n_1n_my_bra1n} | Score: 0.961432
Final guess: 1753c{wr1tt3n_1n_my_bra1n} | Score: 0.961432
But it wasn't a flag, little leetspeak and flag is 1753c{wr1tt3n_1n_my_br41n}
.