n00bzunit3d 2024 crypto/Random
Welcome to my series of writeups for n00bzunit3d 2024 capture-the-flag competition. In this post, we look at the crypto/Random
challenge.
The challenge takes an input string and “randomly” shuffles it. If the shuffled string is at least 10 characters long and in ascending order, the challenge gives us the flag. Let us look at the challenge code
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include<chrono>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<string>
#include<fstream>
#include<thread>
#include<map>
using namespace std;
bool amazingcustomsortingalgorithm(string s) {
int n = s.size();
for (int i = 0; i < 69; i++) {
cout << s << endl;
bool good = true;
for (int i = 0; i < n - 1; i++)
good &= s[i] <= s[i + 1];
if (good)
return true;
random_shuffle(s.begin(), s.end());
this_thread::sleep_for(chrono::milliseconds(500));
}
return false;
}
int main() {
string s;
getline(cin, s);
map<char, int> counts;
for (char c : s) {
if (counts[c]) {
cout << "no repeating letters allowed passed this machine" << endl;
return 1;
}
counts[c]++;
}
if (s.size() < 10) {
cout << "this machine will only process worthy strings" << endl;
return 1;
}
if (s.size() == 69) {
cout << "a very worthy string" << endl;
cout << "i'll give you a clue'" << endl;
cout << "just because something says it's random mean it actually is" << endl;
return 69;
}
random_shuffle(s.begin(), s.end());
if (amazingcustomsortingalgorithm(s)) {
ifstream fin("flag.txt");
string flag;
fin >> flag;
cout << flag << endl;
}
else {
cout << "UNWORTHY USER DETECTED" << endl;
}
}
The challenge uses random_shuffle() to shuffle the string 69 times. It then checks if the shuffled string is in ascending order according to their ASCII values.
We start with entering input 0123456789
, which lets me see how to characters have been shuffled.
Output:
.
.
.
9360274158
9380765124
0123456789
Is the the output we get from the shuffling. The challenge hints that the shuffling may not be truly random. In addition, we know C++ random functions use a seed to determine their randomness. We do not see a seed being set each time so maybe the results are reproducable.
We run the challenge again and give the same input 0123456789
. And we get the same output.
.
.
.
9360274158
9380765124
0123456789
So the order of shuffling always remains the same between each runs. We can use this and work backwards to enter a string that gets shuffled to an ascending order string.
We wrote a simple script to get the right sequence. Which was 4759106328
. Running the challenge with the input gives
9360274158
9380765124
0123456789
n00bz{REDACTED}