Rating:

# not_malware

This is a writeup that uses plain old static reverse engineering. No angr: even though it did speed my solve up just a little, it isn't necessary.
No dynamic analysis, mostly because I haven't learned gdb.

## Annotated Main Function that Ghidra decompiled
```
undefined8 FUN_001012bc(void)

{
// *Section 0*
int iVar1; //A lot of variables that we'll deal with later
size_t sVar2;
undefined8 uVar3;
double dVar4;
char local_b6 [10];
undefined4 local_ac;
char local_a8 [32];
char local_88 [4];
char local_84;
char local_83;
char local_82;
char local_81;
char local_80;
char local_7f;
char local_7e;
char local_7d;
char local_7c;
char local_7b;
char local_7a;
char local_79;
char local_78;
char local_77;
char local_76;
char local_75;
char local_68 [8];
char local_60;
char local_5f;
char local_5e;
char local_5d;
char local_5c;
char acStack91 [20];
char local_47;
char acStack70 [30];
char local_28 [8];
int local_20;
int local_1c;
int local_18;
int local_14;
uint local_10;
int local_c;

FUN_001012a6(); //Implements security measures against VMs, ptrace debugging, and LD_PRELOAD (don't worry about it)

// *Section 1: Get's your input, stores in local_68

printf("What\'s your credit card number (for safekeeping) ?\n>> ");
fgets(local_68,0x3c,stdin); //Gets up to 60 chars of input (including newline). We'll soon discover that's way too much
sVar2 = strlen(local_68);
if (0x3c < sVar2) {
puts("Well this was unnecessary.");
/* WARNING: Subroutine does not return */
exit(1);
}

// *Section 2: Checks for "softbank:"

local_18 = 0x10;
dVar4 = pow(16.00000000,0.50000000); //evaluates to 4
local_18 = (int)(dVar4 - 1.00000000); //changes local_18 to 3.
local_c = 0;
while (local_c < 8) { //Transfers the first 8 chars of input into its own buffer
local_28[local_c] = local_68[local_c];
local_c = local_c + 1;
}
local_28[local_c] = '\0';
iVar1 = strncmp(local_28,"yeetbank" + (long)local_18 * 9,8); //Compares your first 8 chars.
// It uses yeetbank's pointer and adds 9 * local_18 (3) = 27, which is "softbank"
// when you can calculate when you double click on yeetbank and jump to the data section.
if (iVar1 != 0) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_60 != ':') { //must be followed by a colon, so "softbank:"
puts("Get out.");
/* WARNING: Subroutine does not return */
exit(1);
}

// *Section 3: Initial settings set

local_10 = (int)local_5f - 0x30; //Looks for 3 numbers and -48 to get from the char '0' in ascii to 0.
local_1c = (int)local_5e + -0x30;
local_20 = (int)local_5d + -0x30;
if (local_5c != ':') { //Another colon
puts("Get out.");
/* WARNING: Subroutine does not return */
exit(1);
}

// *Section 4: Signature Generation from settings

local_14 = 0;
while (local_14 < 0x14) { //Runs 20 times, so the signature is 20 chars long
uVar3 = FUN_00101288((ulong)local_10); //Uses local_10 as seed and returns first random output.
snprintf(local_b6,10,"%ld",uVar3); //snprintf stores uVar3 as a buffer in long integer format with length 10
local_88[local_14] = local_b6[local_20];//Extracts from the buffer one digit according to local_20 (0-9). Stores into local_88 buffer
local_10 = local_10 + local_1c; //local_10 seed is incremented by local_1c
local_14 = local_14 + 1;
}

// *Section 5: Signature Comparison

local_c = 0;
while (local_c < 0x14) { //Copies over next 20 chars from input string (your signature) and stores it in buffer local_a8.
local_a8[local_c] = local_68[local_c + 0xd];
local_c = local_c + 1;
}
if (local_a8[0] != local_88[0]) { //Compares every character between your signature and the "random" generated signature.
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[16] != local_78) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[11] != local_7d) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[3] != local_88[3]) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[7] != local_81) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[15] != local_79) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[1] != local_88[1]) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[12] != local_7c) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[19] != local_75) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[13] != local_7b) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[14] != local_7a) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[5] != local_83) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[9] != local_7f) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[8] != local_80) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[18] != local_76) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[6] != local_82) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[17] != local_77) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[2] != local_88[2]) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[10] != local_7e) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_a8[4] != local_84) {
/* WARNING: Subroutine does not return */
exit(1);
}
if (local_47 != ':') { //Colon again
puts("Get out.");
/* WARNING: Subroutine does not return */
exit(1);
}

// *Section 6: End

local_c = 0;
local_ac = 0x646e65;
while( true ) {
if (2 < local_c) {
puts("Thanks!");
FUN_00101229(); //Prints the flag Yay!
return 0;
}
if (*(char *)((long)&local_ac + (long)local_c) != local_68[local_c + 0x22]) break; //Checks for "end" the string
local_c = local_c + 1;
}
/* WARNING: Subroutine does not return */
exit(1);
}
```

## Descriptive Analysis
Based on the analysis, the input string must be: `softbank:XXX:NNNNNNNNNNNNNNNNNNNN:end`
Where X represents our initial settings and N is our signature
The first X is the initial seed.
The second X is how much the seed changes for each signature number.
The third X is what index from the generated long to choose.

The thing is, if the seed remains the same, the first generated number will also remain the same since the function reinitializes rand() with srand().
That means the easiest thing to do is make the second X = 0.
For my solution I ended up using 101.

## Brute Force or Quick Script
From here, you can copy out the section 4 and run it with tweaks to find the random number.
```
#include <stdio.h>
#include <stdlib.h>

int main(void) {
int v59 = 1;
int v56 = 0;
int v55 = 1;
char v5[10];
for (int j = 0; j <= 19; ++j )
{
srand(v59);
long v3 = rand();
snprintf(v5, 10uLL, "%ld", v3);
printf ("%c\n", v5[v55]);
v59 += v56;
}
return 0;
}
```
Or you can just bruteforce 0-9 and see which one works.
For 101, the random number happens to be 8.

## Solution:

```
What's your credit card number (for safekeeping) ?
>> softbank:101:88888888888888888888:end
Thanks!
flag{th4x_f0r_ur_cr3d1t_c4rd}
```

Original writeup (https://github.com/jyu78749/CTFwriteups/blob/master/CSAWQuals2020-not_malware.md).