---
# System prepended metadata

title: Cyber Apocalypse 2023 - The Cursed Mission | Writeup
tags: [Writeup, Cyber Apocalypse 2023, Documentation, HTB]

---

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

Cyber Apocalypse 2023 - The Cursed Mission Writeup 
===

![Awesome](https://awesome.re/badge.svg)

![Cyber Apocalypse 2023](https://ctf.hackthebox.com/storage/ctfs/banner-821.jpg)

## 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.
![Interactive Binary](https://i.imgur.com/3zanQ9P.png)

```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.
![Answer](https://i.imgur.com/WMKVWrR.png)

#### 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`