First of all, we need to look at the README, as it contains the hint to the solutions.
cat README
Diffuse this bomb!
When you have all the password use it as "thor" user with ssh.
HINT:
P
2
b
o
4
NO SPACE IN THE PASSWORD (password is case sensitive).
We downloaded bomb binary and decompiled it using ghidra. You can look the whole source file
The code of this phase is pretty straightforward:
void phase_1(char *arg)
{
int i = strings_not_equal(arg, "Public speaking is very easy.");
if (i != 0) {
explode_bomb();
}
return;
}
As we see, the argument should be equal to Public speaking is very easy.
This level is easy too. First, six numbers are read in the array[7] (0 element is not used).
void phase_2(char *arg) {
int i;
int arr[7];
read_six_numbers(arg, (int)(arr + 1));
if (arr[1] != 1) {
explode_bomb();
}
i = 1;
do {
if (arr[i + 1] != (i + 1) * arr[i]) {
explode_bomb();
}
i = i + 1;
} while (i < 6);
return;
}
Then, in the cycle we see, that every element is depending on the previous one.
arr[i + 1] = i + 1 * arr[i];
From this formula we could understand, that each element equals factorial of current i:
1! == 0! == 1
2! = 1! * 2 = 2
3! = 2! * 3 = 2 * 3 = 6
4! = 3! * 4 = 6 * 4 = 24
5! = 4! * 5 = 24 * 5 = 120
6! = 5! * 6 = 120 * 6 = 720
So, the solution here is string that contains list of factorials: 1 2 6 24 120 720
As we can understand from the hint, the second char should be b
.
Let's watch to related cases:
void phase_3(char *arg) {
int i;
uchar c;
uint n1;
uchar c2;
int n2;
i = sscanf(arg, "%d %c %d", (int *)&n1, &c2, &n2);
if (i < 3) {
explode_bomb();
}
switch (n1) {
case 1:
c = 'b';
if (n2 != 0xd6) {
explode_bomb();
}
break;
case 2:
c = 'b';
if (n2 != 0x2f3) {
explode_bomb();
}
break;
case 7:
c = 'b';
if (n2 != 0x20c) {
explode_bomb();
}
break;
}
if (c != n2) {
explode_bomb();
}
return;
}
Possible answers:
1 b 214
2 b 755
7 b 524
Here's the source code of this phase:
int func4(int arg) {
int i, j;
if (arg < 2) {
j = 1;
} else {
j = func4(arg - 2) + func4(arg - 1);
}
return j;
}
void phase_4(char *arg) {
int num;
int i = sscanf(arg, "%d", &num);
if ((i != 1) || (num < 1)) {
explode_bomb();
}
i = func4(num);
if (i != 0x37) {
explode_bomb();
}
return;
}
We see, that a number passed to the function and the result should be 0x37 or 55
to pass this stage.
func4
calculates fibonacci sequence for the given arg
(arr[i] = arr[i-1] + arr[i-2]).
We need result to be 55
, so the index we should pass is:
0 1 2 3 4 5 6 7 8 9
0 1 1 2 3 5 8 13 21 34 55
Answer: 9
void phase_5(char *arg) {
int i;
char arr[6];
i = string_length(arg);
if (i != 6) {
explode_bomb();
}
i = 0;
do {
arr[i] = "isrveawhobpnutfg"[(char)(arg[i] & 0xf)];
i = i + 1;
} while (i < 6);
i = strings_not_equal(arr, "giants");
if (i != 0) {
explode_bomb();
}
return;
}
As we can see, the result string should be equal to giants
.
This string is formed from another string using the string we pass to get indices.
The index is getting from the low bits of every char.
Let's write all this into the table:
char | index | bin index | ASCII chars which low bits matches bin index | |||
---|---|---|---|---|---|---|
g | 15 | 1111 | o | |||
i | 0 | 0000 | p | P | 0 | |
a | 5 | 0101 | e | E | u | U |
n | 11 | 1011 | k | K | ; | |
t | 13 | 1101 | m | M | ||
s | 1 | 0001 | q | Q | 1 | A |
All the combinations work to pass the stage, but only one used for password.
Answer: opekmq
We didn't want to read all the src code and understand it, so we just brute force it.
This phase takes a six unique numbers from 1
to 6
and the first one is 4
, so it perfectly matches the brute force exploit.
There are some unused functions in binary that creates socket and sending message, but I could not make up something with them.
$ cat instr
Public speaking is very easy.
1 2 6 24 120 720
1 b 214
9
opekmq
4 2 6 3 1 5
The pre-last and pre-pre-last element should be chagned according to the forum
I really do not understand why them do not fix that...
So we finally can move forward...
Password: Publicspeakingisveryeasy.126241207201b2149opekmq426135
ssh thor@$IP