Rating:

> Cursed app
>
> 104
>
> If we want to say 100, should we start at 1 and count until 100?
>
> Download: [cursed_app.txz](https://0xd13a.github.io/ctfs/asis2019/cursed/cursed_app.txz)

This is a reversing challenge, we'll analyze it in [Ghidra](https://ghidra-sre.org/).

Decompilation of the code and a quick inspection brings up the following interesting function:

```c
...

undefined8 FUN_001010e0(undefined8 param_1,long param_2)

{

...

if (iVar2 != 0) {
puts("please locate license file, run ./app license_key");
/* WARNING: Subroutine does not return */
exit(0);
}
__stream = fopen(*(char **)(param_2 + 8),"r");
if (__stream != (FILE *)0x0) {
fseek(__stream,0,2);
lVar3 = ftell(__stream);
fseek(__stream,0,0);
__ptr = (char *)malloc((long)(int)lVar3);
if (__ptr != (char *)0x0) {
fread(__ptr,1,(long)(int)lVar3,__stream);
}
fclose(__stream);
iVar2 = ((int)*__ptr * 0xaf + 0x91) % 0x100;
if (((((((((iVar2 * iVar2 * 0x164 + 0x202 + iVar2 * 0xeb) % (iVar2 * 0x67 + 2) == 0) &&
(iVar2 = ((int)__ptr[1] * 0x5d + 0xda) % 0x100,
(iVar2 * iVar2 * 0x3da + 0x354 + iVar2 * 0x3c) % (iVar2 * 0x56 + 0x35f) == 0)) &&
(iVar2 = ((int)__ptr[2] * 5 + 0x95) % 0x100,
(iVar2 * iVar2 * 0x19e + 0x3aa + iVar2 * 0x49) % (iVar2 * 0xb9 + 0xb2) == 0)) &&
(((iVar2 = ((int)__ptr[3] * 0x35 + 0xd4) % 0x100,
(iVar2 * iVar2 * 0x210 + 0xba + iVar2 * 0x20c) % (iVar2 * 0x7e + 0x38) == 0 &&

...

(iVar2 = ((int)__ptr[0x3a] * 0x79 + 0x25) % 0x100,
(iVar2 * iVar2 * 0x2a9 + 0x349 + iVar2 * 0x203) % (iVar2 * 7 + 0xbb) == 0)))))) {
puts("Congratz! You got the correct flag!!");
bVar1 = true;
}
if (!bVar1) {
puts("Bummer! You got the wrong flag!!");
}
return 0;
}

...

```

Essentially it asks for a file, reads it in and checks checksums of ```0x3b``` characters to make sure they are correct.

As we look at the expressions in the big "if" statement it becomes obvious that the checksums of individual characters are independent of each other, and we can bruteforce each character seperately. All expressions have the same structure, so with a bit of editing we can build a table out of them and process characters one by one:

```python
rules = [
[0xaf, 0x91, 0x164, 0x202, 0xeb, 0x67, 2],
[0x5d, 0xda, 0x3da, 0x354, 0x3c, 0x56, 0x35f],
[5, 0x95, 0x19e, 0x3aa, 0x49, 0xb9, 0xb2],
[0x35, 0xd4, 0x210, 0xba, 0x20c, 0x7e, 0x38],
[0xb5, 0xd, 0x26a, 0x3ce, 0x130, 8, 0x27f],
[0x5b, 2, 5, 0x4b, 0x2f7, 0x30e, 0x55],
[0x43, 0x76, 0x37d, 0x1f1, 0xed, 0x106, 0xdd],
[0xe7, 0x74, 0x213, 0x3e5, 0x287, 0xf5, 0x184],
[0x77, 0xdf, 0x228, 0x2ce, 0x1e7, 10, 0x22a],
[0xcb, 0x88, 0x336, 0x3bd, 0x95, 0x78, 0x230],
[0x51, 0x96, 0x9d, 0x21a, 0x2b0, 0x144, 0x265],
[0x29, 0x8d, 0x56, 0xcb, 0x2db, 0x15, 0x203],
[0x73, 0x5f, 0x2df, 0x88, 0x178, 0x116, 0x262],
[0xf3, 0xe4, 0x31b, 0x37c, 0xdd, 0xca, 0x33b],
[0x4f, 0x51, 0x66, 0x366, 0x345, 0x234, 0xf9],
[0x7b, 0x8e, 0x12e, 0x282, 0x2b0, 5, 0xd5],
[0xa9, 0x59, 0xe, 0x2a8, 0x272, 0x96, 0x1c8],
[0xad, 0xe6, 0x33e, 0x12e, 0x214, 0x19f, 0x1f1],
[0xab, 0x9a, 0x10f, 0xe2, 0x72, 0x20, 0x292],
[0x4b, 0xb8, 0x366, 0x39, 0x35a, 0x37d, 0x1a8],
[0xf5, 0x5b, 0x375, 0x9d, 0x2f3, 0x6a, 0x3d7],
[0xed, 0x22, 0x36c, 0x173, 0x189, 0x66, 0x196],
[0x3d, 0x69, 0x3cb, 0x214, 0x3c0, 0x3e, 0x390],
[0x9f, 0x2c, 0x215, 0x7a, 0x1d8, 0x29, 0x32],
[0x77, 0xef, 0xa7, 0x308, 0x21f, 0x38, 0x290],
[0xb3, 0x70, 0xf8, 0x19e, 0x3ce, 0x87, 0x52],
[0x47, 0xae, 0x2f3, 0x115, 0x1cf, 10, 0x113],
[0xbf, 0x90, 0xe3, 0x234, 0x2a6, 0x37, 0x27a],
[0x51, 0x9b, 0x379, 0x330, 0x210, 0x173, 0x2ea],
[0x57, 200, 0x14d, 0x25, 0x2e0, 0x2e6, 0xd],
[0xa7, 0xa0, 0x27c, 0xd5, 200, 0x382, 0x265],
[0xe7, 0x66, 0x300, 0x2e2, 0x1a, 0x18a, 0x3e1],
[0x71, 0xd9, 0x8a, 0xfc, 0x34b, 0x14d, 0x244],
[0xaf, 9, 0x1ae, 0x2cb, 0x164, 0x69, 0x1fc],
[0xdb, 0xa6, 0xac, 0x32c, 0x2ca, 2, 0x124],
[0xb3, 0x39, 0x358, 0x2b9, 0x3be, 0x1f1, 0x3be],
[0x97, 0x1b, 0x394, 0x15, 0x397, 0x4b, 699],
[0x3d, 0xf0, 0x141, 0x1ec, 0x3b9, 0x78, 0x199],
[0x29, 0x76, 0x7b, 0x3c4, 0x10c, 0x4a, 0x14e],
[0x2d, 0x96, 0x264, 0x16c, 0x210, 0xd, 0x27d],
[0x4f, 0xd7, 0xd6, 0x3a6, 0x28, 0x3ba, 0xa6],
[0x3f, 0xa0, 0x388, 0x34d, 0x15a, 0xf0, 0x3d],
[0xd3, 0x72, 0x22f, 0x299, 0x22a, 0x93, 0x379],
[0x79, 2, 0x2cf, 0x32b, 0x3df, 0x82, 0x195],
[0x75, 0xe6, 0x21d, 300, 0x134, 0x27, 0x29],
[0x51, 0x52, 0x234, 0x229, 0x253, 0x23, 0x205],
[0x55, 0xa3, 0x3b0, 0x3b0, 0xe3, 0x8a, 0xd9],
[0xed, 0xa5, 0x203, 0x14b, 0x306, 0x24, 0x28c],
[0x81, 0x7f, 0x362, 0x14, 0x1a4, 0xb, 0x15a],
[0x19, 0xeb, 0xb8, 0x140, 0x67, 0x211, 0x17e],
[0x9b, 0x3a, 0x357, 0xa0, 0x33c, 0x46, 0x10e],
[0x55, 0xf0, 0x3b7, 0xd5, 0x234, 10, 0x207],
[0x49, 0x3d, 0x282, 0x362, 0x79, 7, 0x142],
[0x81, 0x56, 0x3d, 0x181, 0x326, 0x17, 0x14f],
[0x9b, 0xb1, 399, 0x24, 0xc4, 0x65, 0xda],
[0x99, 0x7e, 0x360, 0x2aa, 0x116, 0x3c, 0x142],
[0xe3, 0xf5, 0x123, 0x1f8, 0x152, 0x51, 700],
[0xc3, 0x16, 0x300, 0x13, 0x3ca, 0x148, 0x1e1],
[0x79, 0x25, 0x2a9, 0x349, 0x203, 7, 0xbb]]

out = ""
for x in rules:
for c in range(256):
v = (c * x[0] + x[1]) % 0x100
if (v * v * x[2] + x[3] + v * x[4]) % (v * x[5] + x[6]) == 0:
out += chr(c)
break
print out
```

When we run the script we quickly get the flag: ```ASIS{y0u_c4N_s33_7h15_15_34513R_7h4n_Y0u_7h1nk_r16h7?__!!!}```.

Original writeup (https://0xd13a.github.io/ctfs/asis2019/cursed/).