Tags: c++ rev 

Rating: 5.0

## Secret door

We were given a [zip](https://gr007.tech/writeups/2023/backdoor/rev/secret_door/public.zip) file that contained two files. One is the [challenge](https://gr007.tech/writeups/2023/backdoor/rev/secret_door/chall.out) binary and the other is an encoded binary [data](https://gr007.tech/writeups/2023/backdoor/rev/secret_door/encoded.bin) file that we need to decode.

```sh
backdoor/rev/secret_door on  master [!?]
❯ tree
.
├── chall.out
├── encoded.bin
└── public.zip
```

A c++ binary can be really annoying to reverse with gidhra. But I will just show some relevant codes that are interesting to the workflow of the binary.

```c
buf = operator.new[](0x44);
piVar3 = func_4(buff,argv[1]);
buf = func_3(piVar3,sus);
cVar1 = func_2(buf);
if (cVar1 == '\0') {
std::operator<<(std::cout,"Wrong door");
}
else {
func_1(*buf,buf[0x10]);
}
```

Here, we see that there is a new buffer of size 0x44 being created. Then some functions are called with this new buffer and our input argument 1 as parameters.
The check only fails if `func_2` returns 0. Let's peek into func_2 to see what it does.

```c
undefined8 func_2(int *key)

{
undefined8 uVar1;

if (((((((*key == 0x4e) && (key[1] != (*key == 0xf))) && (key[2] == 0x78)) &&
((key[3] != (key[2] == 0x1f) && (key[4] == 0x78)))) &&
((key[5] != (key[4] == 0xb) && ((key[6] == 0x74 && (key[6] != (key[7] == 6))))))) &&
(key[8] == 100)) &&
((((key[9] != (key[8] == 0x21) && (key[10] == 99)) && (key[0xb] != (key[10] == 0x22))) &&
(((key[0xc] == 0x78 && (key[0xd] == key[0xc])) &&
((key[0xe] == 0x72 && ((key[0xf] == key[0xe] + 1 && (key[0x10] == 0x21)))))))))) {
uVar1 = 1;
}
else {
uVar1 = 0;
}
return uVar1;
}
```

It is clear that our input should be such that we need to pass this check and then the binary will call another function with the **first** and **0x10th** character of the newly created and modified through some functions. But if we look closely, we know what the 1st and 0x10th characters should be. They are matched against a fixed value inside `func_2`. They are `0x4e` and `0x21` respectively.

Now let's see what happens inside `func_1`

```c

/* func_1(int, int) */

/* DISPLAY WARNING: Type casts are NOT being printed */

undefined8 func_1(int param_1,int param_2)

{
byte *pbVar1;
long lVar2;
long in_FS_OFFSET;
allocator<char> local_48d;
uint i;
istreambuf_iterator local_488 [2];
allocator *local_480;
istreambuf_iterator<> local_478 [16];
allocator local_468 [32];
basic_string<> local_448 [32];
basic_ofstream<> local_428 [512];
basic_string local_228 [520];
long local_20;

local_20 = *(in_FS_OFFSET + 0x28);
std::allocator<char>::allocator();
/* try { // try from 0010273e to 00102742 has its CatchHandler @ 0010292d */
std::__cxx11::basic_string<>::basic_string<>(local_448,"encoded.bin",local_468);
std::allocator<char>::~allocator(local_468);
/* try { // try from 0010276b to 0010276f has its CatchHandler @ 001029a5 */
std::basic_ifstream<>::basic_ifstream(local_228,local_448);
std::allocator<char>::allocator();
std::istreambuf_iterator<>::istreambuf_iterator(local_478);
std::istreambuf_iterator<>::istreambuf_iterator(local_488);
/* try { // try from 001027da to 001027de has its CatchHandler @ 0010294e */
std::vector<>::vector<>(local_468,local_488[0],local_480);
std::allocator<char>::~allocator(&local_48d);
for (i = 0; i < 90246; i += 1) {
if ((i & 1) == 0) {
pbVar1 = std::vector<>::operator[](local_468,i);
*pbVar1 = *pbVar1 ^ param_1;
}
else {
pbVar1 = std::vector<>::operator[](local_468,i);
*pbVar1 = *pbVar1 ^ param_2;
}
}
/* try { // try from 00102885 to 00102889 has its CatchHandler @ 0010297e */
std::basic_ofstream<>::basic_ofstream(local_428,1069148);
std::vector<>::size(local_468);
lVar2 = std::vector<>::data(local_468);
/* try { // try from 001028be to 001028d1 has its CatchHandler @ 00102966 */
std::basic_ostream<>::write(local_428,lVar2);
std::basic_ofstream<>::close();
std::basic_ofstream<>::~basic_ofstream(local_428);
std::vector<>::~vector(local_468);
std::basic_ifstream<>::~basic_ifstream(local_228);
std::__cxx11::basic_string<>::~basic_string(local_448);
if (local_20 != *(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}

```

Looks like they are opening our encoded file and decoding it with xoring it with the two parameters. Note that no other characters of the buffer created matters. Nor does our key input matter. We should be able to call our function with setting our own parameters inside gdb.

```sh
backdoor/rev/secret_door
❯ la
total 236K
-rwxrwxr-x 1 groot groot 44K Dec 12 11:31 chall.out*
-rw-rw-r-- 1 groot groot 89K Dec 12 11:31 encoded.bin
-rw-r--r-- 1 groot groot 94K Dec 16 18:04 public.zip

backdoor/rev/secret_door
❯ gdb chall.out
gef➤ start
gef➤ call (void)func_1(0x4e, 0x21)
gef➤ q

backdoor/rev/secret_door took 31s
❯ la
total 328K
-rwxrwxr-x 1 groot groot 44K Dec 12 11:31 chall.out*
-rw-rw-r-- 1 groot groot 89K Dec 12 11:31 encoded.bin
-rw-r--r-- 1 groot groot 94K Dec 16 18:04 public.zip
-rw-r--r-- 1 groot groot 89K Dec 25 20:41 the_door.jpg

```

The door looks like this:

[secret_door](https://gr007.tech/writeups/2023/backdoor/rev/secret_door/the_door.jpg)

flag: `flag{0p3n3d_7h3_s3cr3t_r3d_d00r}`

Original writeup (https://gr007.tech/writeups/2023/backdoor/index.html#secret-door).