CSAW Quals 2020 not-malware

4 minute read


This is the next reversing challenge from CSAW Quals 2020 (first two are here).

This challenge gives you an application not_malware and instructions for nc. Because I did this after the actual CTF, I will assume that if I get a certain response (ouput of the flag, “correct”, etc…) from the binary, then I have solved the challenge.


I first started by running the program. It asks:

$ ./not_malware
What's your credit card number (for safekeeping) ?

As per usual, I entered a random number of A’s and hit return. Nothing. The program just exited.

Next, I opened up the binary in Ghidra. I’ll be copying interesting snippets here, but you can find the entire decompilation (edited) here. I’ll be using images and snippets from my edited version of the decompilation (after the reverse engineering), but will try to explain pretending not to know certain things (like not knowing what randint does).

The first function we hit looks like some anti-analysis (???) code, so I ignored it.

Segment 1

The first interesting segment is below:


In this section, addr is first set to 3. Then, the first 8 bytes of the user input is copied to local_store. local_store is then compared to the string located at the address of yeetbank + addr*9 (or 27). Looking at the disassembly, we see that local_store must be the same as softbank. Lastly, we see that after softbank, the next char must be :.

So at this point our input is softbank:.

Segment 2 (??)

The next interesting segment is below:


Before I changed the names of these variables, it was a little confusing what these 3 values were used for. So, just like during the reversing process, I’ll talk more about this in the next segment.

Segment 3


Looking at the third interesting segment, we see that the values from segment 2 are being used. Good, this will allow us to discern their use.

We can see that we have a loop for 20 iterations. At each iteration, we being by calling the function rand_int:

/* seed set; so deterministic */

long rand_int(uint seed)

  int retval;
  retval = rand();
  return (long)retval;

As you can see, the seed is set at each iteration by seed in segment 2. Next, the random number we get is copied as a string to randstr. Then, at index j, we set check[j] to randstr[idx]. Last, we update seed by seed_idx.

We learn a few things about segment 2 here. First, seed is used to seed a random number generator. idx is a constant value that will be used to see which random character is added to check. And seed_idx is used to update the seed at each iteration.

Cool, now we know what the values from segment 2 do? But, what does segment 3 now?

The rest of this segment checks the user input against the 20 chars located in check. So, we just need to reproduce check using the seed, idx, and seed_idx values we use.

To make it super simple, I started with just seed=0. I wrote a quick c file to see what the first random number generated would be.

#include <stdio.h>
#include <stdlib.h>

int main() {
	int d = rand();
	printf("%d\n", d);
	return 0;

To continue with the “let’s not try to hard” motto, I set seed_idx = 0 so we do not have to generate any more random numbers. We can just use the first one. It doesn’t really matter what idx is set to, but I chose 0 because it is the easiest index to remember. This solves 2 parts of our input.

First, we have the three values for segment 2, 000, making our input softbank:000:. Second, we have the next 20 chars, making our input softbank:000:11111111111111111111:.

Last but not least


This segment checks the remainder of the user input with local_ac = 0x646e65. A quick hex->ascii tells us this is dne. So, finally, we have that our user input must be



Using this as input gives us

$ ./not_malware
What's your credit card number (for safekeeping) ?
>> softbank:000:11111111111111111111:end

[1]+  Stopped                 ./not_malware

I assume this (along with the win function that is called) means solved the challenge and the flag would be returned if this was run on the challenge server.