---
title: 'Cyber Apocalypse 2023 - The Cursed Mission | Writeup'
---
Cyber Apocalypse 2023 - The Cursed Mission Writeup
===


## Reversing / Hunting License
>STOP! Adventurer, have you got an up to date relic hunting license? If you don't, you'll need to take the exam again before you'll be allowed passage into the spacelanes!
[rev_hunting_license.zip](rev_hunting_license.zip)
---
#### Analysis
This challenge gave us an Interactive license binary.

```C=
ptr = sym.imp.readline("Okay, first, a warmup - what\'s the first password? This one\'s not even hidden: ");
iVar1 = sym.imp.strcmp(ptr, "PasswordNumeroUno");
if (iVar1 != 0) {
sym.imp.puts("Not even close!");
// WARNING: Subroutine does not return
sym.imp.exit(0xffffffff);
}
```
For the first `password` is `PasswordNumeroUno`.
```C=
s2 = 0;
var_ch = 0;
sym.reverse(&s2, "0wTdr0wss4P", 0xb);
ptr = sym.imp.readline("Getting harder - what\'s the second password? ");
iVar1 = sym.imp.strcmp(ptr, &s2);
if (iVar1 != 0) {
sym.imp.puts("You\'ve got it all backwards...");
// WARNING: Subroutine does not return
sym.imp.exit(0xffffffff);
}
```
```shell
# echo "0wTdr0wss4P" | rev
P4ssw0rdTw0
```
For the second `password` are flipping. Now we just flip it with `rev` in terminal and we’re done with the second password `P4ssw0rdTw0`.
```C=
var_30h = 0;
var_28h = 0;
var_20h._0_1_ = 0;
sym.xor(&var_30h, "G{zawR}wUz}r\x7f222\x13", 0x11, 0x13);
ptr = sym.imp.readline("Your final test - give me the third, and most protected, password: ");
iVar1 = sym.imp.strcmp(ptr, &var_30h);
if (iVar1 != 0) {
sym.imp.puts("Failed at the final hurdle!");
// WARNING: Subroutine does not return
sym.imp.exit(0xffffffff);
}
```
We can see the third password is based on an `XOR` check. The `sym.xor` call where `t2` is stored.
```asm
│ 0x00401357 b913000000 mov ecx, 0x13 ; 19 ; int64_t arg4
│ 0x0040135c ba11000000 mov edx, 0x11 ; 17 ; uint32_t arg3
│ 0x00401361 be70404000 mov esi, obj.t2 ; 0x404070 ; "G{zawR}wUz}r\x7f222\x13" ; int64_t arg2
│ 0x00401366 4889c7 mov rdi, rax ; int64_t arg1
│ 0x00401369 e8c9feffff call sym.xor
│ 0x0040136e bfe8214000 mov edi, str.Your_final_test___give_me_the_third__and_most_protected__password:_ ; 0x4021e8 ; "Your final test - give me the third, and most protected, password: "
```
I use `radare2` to check this.
```asm
[0x00401090]> x/s obj.t2
0x00404070 G{zawR}wUz}r222
```
then using `python` to reveal the string.
```python=
t2 = "G{zawR}wUz}r\x7f222\x13"
xor = 0x13
password = ""
for char in t2:
password += chr(ord(char) ^ xor)
print(password.strip('\x00'))
```
For the third `password` is `ThirdAndFinal!!!`.
Next working on the remote service.

#### Solver script
:::spoiler Click to show details
```python=
#!/usr/bin/env python3
from pwn import *
jawab = {
'1' : b"elf",
'2' : b"x86-64",
'3' : b"libreadline.so.8",
'4' : b"0x401172",
'5' : b"5",
'6' : b"PasswordNumeroUno",
'7' : b"0wTdr0wss4P",
'8' : b"0wTdr0wss4P"[::-1],
'9' : b"0x13",
}
t2 = "G{zawR}wUz}r222"
xor = 0x13
final = ""
for char in t2:
final += chr(ord(char) ^ xor)
# print(final)
r = remote('142.93.38.14', 32115)
print(r.recvuntil(b'?').decode())
r.sendline(jawab['1'])
print(r.recvuntil(b'?').decode())
r.sendline(jawab['2'])
print(r.recvuntil(b'?').decode())
r.sendline(jawab['3'])
print(r.recvuntil(b'?').decode())
r.sendline(jawab['4'])
print(r.recvuntil(b'?').decode())
r.sendline(jawab['5'])
print(r.recvuntil(b'?').decode())
r.sendline(jawab['6'])
print(r.recvuntil(b'?').decode())
r.sendline(jawab['7'])
print(r.recvuntil(b'?').decode())
r.sendline(jawab['8'])
print(r.recvuntil(b'?').decode())
r.sendline(jawab['9'])
print(r.recvuntil(b'?').decode())
r.sendline(str(final).strip('\x00').encode())
r.recv()
print(r.recvS())
print(r.recvS())
```
:::
:::success
Flag:`HTB{l1c3ns3_4cquir3d-hunt1ng_t1m3!}`
:::
---
## Reversing / Cave System
>Deep inside a cave system, 500 feet below the surface, you find yourself stranded with supplies running low. Ahead of you sprawls a network of tunnels, branching off and looping back on themselves. You don't have time to explore them all - you'll need to program your cave-crawling robot to find the way out...
[rev_hunting_license.zip](rev_hunting_license.zip)
---
#### Analysis
After opening the executable `cave` in `Ghidra` we are presented with an huge `if` expression.
> DECOMPILED CODE - main :
:::spoiler Click to show details
```asm=
ulong main(void)
{
int32_t iVar1;
ulong s1;
ulong var_78h;
ulong var_70h;
ulong var_68h;
ulong var_60h;
ulong var_58h;
ulong var_50h;
ulong var_48h;
ulong var_40h;
ulong var_38h;
ulong var_30h;
ulong var_28h;
ulong var_20h;
ulong var_18h;
ulong var_10h;
ulong var_8h;
s1 = 0;
var_78h = 0;
var_70h = 0;
var_68h = 0;
var_60h = 0;
var_58h = 0;
var_50h = 0;
var_48h = 0;
var_40h = 0;
var_38h = 0;
var_30h = 0;
var_28h = 0;
var_20h = 0;
var_18h = 0;
var_10h = 0;
var_8h = 0;
sym.imp.printf("What route will you take out of the cave? ");
sym.imp.fgets(&s1, 0x80, _reloc.stdin);
iVar1 = sym.imp.memcmp(&s1, "HTB{", 4);
if (((((((iVar1 == 0) && (var_70h._5_1_ * var_50h == '\x14')) && (var_60h - var_60h._4_1_ == -6)) &&
((((((var_60h._5_1_ - var_68h._2_1_ == -0x2a && (var_70h - var_50h == '\b')) &&
((var_50h._7_1_ - var_78h == -0x2b &&
((var_68h._2_1_ * s1._7_1_ == -0x13 && (s1._4_1_ * var_68h == -0x38)))))) &&
((var_60h._2_1_ ^ var_68h._4_1_) == 0x55)) &&
((((var_68h._6_1_ - var_50h._7_1_ == '4' && (var_48h._3_1_ + var_50h._2_1_ == -0x71)) &&
(var_58h._4_1_ + var_68h._3_1_ == -0x2a)) &&
(((var_70h._1_1_ ^ var_78h._6_1_) == 0x31 && (var_48h * var_70h._4_1_ == -0x54)))))) &&
((((var_48h._2_1_ - var_68h._2_1_ == -0x3e &&
(((var_68h._2_1_ ^ s1._6_1_) == 0x2f && ((var_78h._6_1_ ^ var_60h._7_1_) == 0x5a)))) &&
((var_58h._4_1_ ^ var_60h._7_1_) == 0x40)) &&
(((((var_58h == var_68h._2_1_ && (var_70h._7_1_ + var_50h._1_1_ == -0x68)) &&
(var_70h._7_1_ * var_48h._3_1_ == 'h')) &&
((s1._1_1_ - var_68h._4_1_ == -0x25 && (var_68h - var_68h._5_1_ == -0x2e)))) &&
((var_60h._6_1_ - var_68h == '.' &&
(((var_60h ^ var_70h._6_1_) == 0x1a && (var_58h._4_1_ * s1._4_1_ == -0x60)))))))))))) &&
(((((var_60h._6_1_ * var_68h._3_1_ == '^' &&
(((var_78h._7_1_ - var_58h == -0x38 && ((var_50h._1_1_ ^ var_50h._5_1_) == 0x56)) &&
((var_68h._2_1_ ^ var_58h._5_1_) == 0x2b)))) &&
((((((var_50h._6_1_ ^ var_78h._1_1_) == 0x19 && (var_68h._4_1_ - var_58h._7_1_ == '\x1a')) &&
((var_50h._2_1_ + var_70h._3_1_ == -0x5f &&
((var_60h._5_1_ + var_48h._1_1_ == 'V' && ((var_68h._5_1_ ^ var_70h._2_1_) == 0x38)))))) &&
((var_58h._4_1_ ^ var_48h._4_1_) == 9)) &&
(((((var_78h._7_1_ * var_60h._6_1_ == 'y' && ((var_60h._5_1_ ^ var_68h._6_1_) == 0x5d)) &&
(s1._2_1_ * var_60h == '\\')) &&
((var_78h._2_1_ * var_70h._2_1_ == '9' && (var_68h._5_1_ == var_70h._5_1_)))) &&
((var_60h._3_1_ * var_70h._5_1_ == '/' &&
((var_78h * var_60h._5_1_ == -0x55 && (var_60h._7_1_ + var_68h._2_1_ == -0x6d)))))))))) &&
(((((((var_68h._2_1_ ^ var_60h._2_1_) == 0x73 &&
((((var_70h._4_1_ ^ var_68h._7_1_) == 0x40 && (var_68h._1_1_ + var_70h == -0x57)) &&
((var_60h._7_1_ ^ var_48h._3_1_) == 0x15)))) &&
(((s1 + var_48h._3_1_ == 'i' && (var_60h._2_1_ + var_58h._6_1_ == -0x5b)) &&
(((var_68h._6_1_ ^ var_50h._4_1_) == 0x37 &&
((s1 * var_68h._4_1_ == '\b' && (var_60h._2_1_ - var_48h == -0x3b)))))))) &&
(var_70h._2_1_ + var_48h._4_1_ == -0x1c)) &&
(((((var_60h._3_1_ ^ var_58h) == 0x6e && (var_48h * var_70h == -0x54)) &&
(var_50h._6_1_ - var_58h._7_1_ == '\r')) &&
(((var_68h._6_1_ + var_50h._7_1_ == -100 && (s1._6_1_ + var_60h._1_1_ == -0x2c)) &&
((s1._7_1_ * var_68h._5_1_ == -0x13 &&
(((var_48h ^ var_68h._5_1_) == 0x38 && (s1._1_1_ * var_60h._5_1_ == 'd')))))))))) &&
(((var_48h ^ var_48h._2_1_) == 0x46 &&
((((((s1._2_1_ * var_70h._3_1_ == '&' && ((var_68h._2_1_ ^ var_70h._6_1_) == 0x2b)) &&
(s1._1_1_ + s1._7_1_ == -0x79)) &&
(((var_68h._3_1_ ^ s1) == 0x2a && (var_70h._5_1_ - s1._1_1_ == '\v')))) &&
(var_68h._3_1_ + var_50h._6_1_ == -0x32)) &&
(((var_70h._1_1_ ^ var_78h._5_1_) == 0x3b && (var_70h._3_1_ - var_48h._2_1_ == '\x12')))))))))) &&
((((var_70h._1_1_ == var_78h._2_1_ &&
(((var_78h._6_1_ - var_48h._2_1_ == 'M' && (var_58h._2_1_ * var_50h._4_1_ == 'N')) &&
(var_50h._2_1_ == var_60h)))) &&
(((var_58h._7_1_ ^ var_50h._3_1_) == 0x38 && (var_60h._6_1_ + var_68h._1_1_ == -0x6c)))) &&
(var_58h._1_1_ + var_50h._4_1_ == -0x31)))))) &&
((((var_58h._4_1_ == var_70h._4_1_ && (var_78h._4_1_ + var_68h._1_1_ == 'f')) &&
((var_48h._4_1_ + var_60h._4_1_ == -0xf &&
(((var_58h._1_1_ - var_70h._5_1_ == '\x11' && (var_60h._4_1_ - var_50h._1_1_ == 'D')) &&
(var_78h._1_1_ - var_60h._3_1_ == 'D')))))) &&
((((var_50h._5_1_ ^ var_50h._3_1_) == 1 && ((var_60h._2_1_ ^ var_48h._1_1_) == 0xd)) &&
(((var_78h._3_1_ - var_68h._4_1_ == -0x15 &&
((((var_70h._7_1_ + var_68h == -0x67 && (var_68h + var_78h._5_1_ == -0x6b)) &&
((var_78h._4_1_ - s1 == -0x17 &&
((((var_60h._2_1_ + var_68h._7_1_ == '`' && (s1._5_1_ + var_50h._5_1_ == -0x6a)) &&
(var_50h._1_1_ * var_58h._2_1_ == '`')) &&
((var_50h * var_70h._5_1_ == '\x14' && (var_68h._3_1_ - var_50h._4_1_ == '\x03')))))))) &&
(var_48h._1_1_ + var_70h._4_1_ == -0x6b)))) &&
(((var_78h._2_1_ * var_50h._5_1_ == -0x26 && (s1._1_1_ + var_58h._1_1_ == -0x3c)) &&
((var_58h._7_1_ - s1._1_1_ == '\v' &&
(((var_58h._3_1_ == var_70h._3_1_ && (var_60h._7_1_ + var_58h._7_1_ == -0x6d)) &&
(var_78h._4_1_ * var_48h._2_1_ == 'Q')))))))))))))) &&
((((var_78h * var_68h._2_1_ == 'A' && (var_58h._6_1_ - var_68h._7_1_ == 'E')) &&
(s1._7_1_ + var_60h._5_1_ == 'h')) &&
((((var_60h._4_1_ + s1._4_1_ == -0x44 && (var_68h._7_1_ + var_60h == -0x5e)) &&
((var_68h._1_1_ + s1._5_1_ == 'e' &&
(((var_58h._3_1_ * var_68h._5_1_ == -0x13 && ((var_78h._5_1_ ^ var_58h._5_1_) == 0x10)) &&
(var_50h - var_78h._4_1_ == ';')))))) &&
((((var_70h._7_1_ - var_78h == '\t' && ((s1._7_1_ ^ var_58h._2_1_) == 0x41)) &&
(s1._5_1_ - var_58h._3_1_ == -3)) &&
(((((var_48h._4_1_ ^ var_70h._2_1_) == 0x1a && ((s1._1_1_ ^ s1._3_1_) == 0x2f)) &&
((var_70h._1_1_ - var_60h._7_1_ == '+' &&
((((var_78h + var_70h._4_1_ == -0x2d && (var_78h._3_1_ * var_50h._5_1_ == -0x28)) &&
(var_68h._3_1_ + s1._6_1_ == -0x2e)) &&
((s1._5_1_ + s1._3_1_ == -0x55 && (var_60h._3_1_ - var_58h._7_1_ == -0x2e)))))))) &&
((var_70h ^ var_60h._1_1_) == 0x10)))))))))) {
sym.imp.puts("Freedom at last!");
}
else {
sym.imp.puts("Lost in the darkness, you\'ll wander for eternity...");
}
return 0;
}
```
:::
The whole thing can then be solved be replacing known values and calculating other unknowns until we have all values solved.
So, I decide to make automation solver for this.
#### Solver script
> solver_cave1.py :
:::spoiler Click to show details
```python=
import sys
import angr
import pwn
def run_binary(solution, path_to_binary):
if type(solution) == str:
solution = bytes(solution, "utf-8")
print(f"[+] Found: {solution.decode()}".strip('\x00'))
elf = pwn.ELF(path_to_binary, checksec=False)
pty = pwn.process.PTY
io = elf.process(stdin=pty, stdout=pty, level="warn")
io.recvuntil(b"? ")
io.sendline(solution)
output = io.recvline().decode().splitlines()[0].strip('\x00')
print(f"[+] {output}")
def main():
path_to_binary = "./cave"
project = angr.Project(path_to_binary, main_opts={'base_addr': 0})
initial_state = project.factory.entry_state(
add_options={
angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS,
},
)
simulation = project.factory.simgr(initial_state)
target = 0x00001aba
notgood = 0x00001ac8
simulation.explore(find=target, avoid=notgood)
if simulation.found:
solution_state = simulation.found[0]
solution = solution_state.posix.dumps(sys.stdin.fileno())
run_binary(solution, path_to_binary)
else:
raise Exception("Could not find the solution")
if __name__ == "__main__":
main()
```
:::
:::success
Flag:`HTB{H0p3_u_d1dn't_g3t_th15_by_h4nd,1t5_4_pr3tty_l0ng_fl4g!!!}`
:::
---
## Reversing / Needle in a Haystack
>You've obtained an ancient alien Datasphere, containing categorized and sorted recordings of every word in the forgotten intergalactic common language. Hidden within it is the password to a tomb, but the sphere has been worn with age and the search function no longer works, only playing random recordings. You don't have time to search through every recording - can you crack it open and extract the answer?
[rev_needle_haystack.zip](rev_needle_haystack.zip)
---
#### Analysis
> DECOMPILED CODE - main :
```asm=
ulong main(void)
{
uint uVar1;
int32_t iVar2;
ulong var_4h;
sym.imp.setbuf(_reloc.stdout, 0);
sym.imp.printf("Hit enter to select a recording: ");
sym.imp.getchar();
uVar1 = sym.imp.time(0);
sym.imp.srand(uVar1);
for (var_4h._0_4_ = 0; var_4h < 3; var_4h._0_4_ = var_4h + 1) {
sym.imp.putchar(0x2e);
sym.imp.sleep(1);
}
iVar2 = sym.imp.rand();
sym.imp.printf("\"%s\"\n", *(obj.words + (iVar2 + (iVar2 / 0xcb) * -0xcb) * 8));
return 0;
}
```
The program is fairly simple. First it does a `small processing` animation and then chooses a random word out of a word list. The assumption is that inside the `word` list the flag might be hidden. Trying to find with `strings` command, found what we want. :tada:
```
└─# strings haystack | grep 'HTB'
HTB{d1v1ng_1nt0_th3_d4tab4nk5}
```
:::success
Flag:`HTB{d1v1ng_1nt0_th3_d4tab4nk5}`
:::
---
###### tags: `Cyber Apocalypse 2023` `HTB` `Writeup` `Documentation`