Close

Reverse Engineering with Ghidra - SimTaco Floppy Challenge

A project log for AND!XOR DC27 Badge

The trilogy is done

hyr0nHyr0n 06/07/2019 at 02:210 Comments

So we gave it some time to rest, but it's time to walk through what our CypherCon hacking challenge was and the ways the folks who won were able to accomplish it. If we don't share, we don't learn. If you're thinking, WTF does this have to do with your electronic badge project we want to see that... we'll we're keeping that a sekret for a bit longer. So until the reveal, we put out hacking challenges for people to earn free badges.

Why hacking for badges? Because we want to encourage people to learn new things, reward hackers with blingy electronics that contain even more embedded security puzzles to learn new things. Philanthropic hacker karma with knowledge gained. They're free, you just have to earn them :) Also a big shout out to our Philanthropists and Sponsors who are helping us make this happen: Urbane Security, Macrofab, Mouser, and Rigado.

We made 40 of these Floppy disks loaded with a special binary and left them around the Wisconsin Conference center during CypherCon. Also this was inspired by the Floppy Disk badge @aprilwright made for DC26. Initially the first part of this challenge was, how the hell do you read the floppy? Conveniently, between the hundreds of hackers at the conference and it butting up against the Midwest Gaming Classic, there was a large collection of vintage computers around. Some folks tried putting the disks in, but were reminded...those computers weren't networked so how the hell would you get the file off anyway? Truth be told, if you don't have a stack of these laying around like Hyr0n does, then you go on Amazon and search for a "USB Floppy Drive." That simple. Now even though there are a dozen different brands, be forewarned they are all the same manufacturer and all are garbage. 1000000% Garbage where you have to pop in the disk just at the right time. Regardless they do work. So once a person got that disk being read by a computer, they found a file to copy off: "simtaco"

First things first, chmod +x that binary to make it executable, cross your fingers it's not not not malware...and run it.

So if you're thinking "42" - yeah that's the good cult reference, but no... this is a hacking challenge. You don't earn free badges that easily. For this we're gonna have to get up in that binaries guts. Last year I showed you my free open source software of choice for RE which was RadaRE2. We'll the NSA has spoiled us with their warez, because I've gone Ghidra and I'm never going back (sorry HexRays I dont have 1 BTC worth of license fees to shell out ANNUALLY for Ida). In case you aren't familiar with the name, the NSA open sourced their internal binary reverse engineering tool, Ghidra, back in February when Rob Joyce gave his talk at RSA. We were also curious in 2 months time how many people would flock to it. Actually every person who solved the challenge told us they were using Ghidra as well, which made all the sense to title this project log the way we did. Now there are ton's of write ups and tutorials on YouTube showing how to use Ghidra in depth. This post is NOT that. The intent of this is to show you just enough to peak your curiosity and show you that reverse engineering isn't black magic wizardry (like RF is). 

For your reference here's a copy of the binary to play along: http://bit.ly/2EQMHgH

Install Ghidra

This is going to assume you run the same Linux system we do, Ubuntu 18.04.2 

  1. Download Ghidra: https://ghidra-sre.org/
  2. Install Java OpenJDK 11
    1. sudo apt install openjdk-11-jdk
  3. Unzip your Ghidra download anywhere then run "./ghidraRun"
    1. If Ghidra says it can't find your JDK, then you don't have the right version of OpenJDK 11 installed. For a while "11" had JRE 10 bundled with it due to GA, but it was resolved a few weeks ago. So if you aren't up to date, you will have to manually install the OpenJDK 11 by doing the following...
    2. $ sudo add-apt-repository ppa:openjdk-r/ppa
      $ sudo apt upgrade
    3. Again you shouldn't have to do this. Make sure your repo and system is up to date before trying the install of openjdk-11-jdk it should be the correct version.

Setup A New Project

While this is pretty straight forward once you get the hang of it, many leave out the little details to explain the framework and how this works. Which can be a little frustrating and daunting for a first time user. Keep this in mine, Ghidra was setup to create reverse engineering projects with version control, to be shared (or not) among teams of people. So when setting up a new project, think of it in that way, you are creating a project and then you add a binary (or binaries) to it which you want to reverse engineer. 

  1. ./ghidraRun
  2. FIle -> New Project -> Non-Shared Project
  3. Pick a directory to host your project and give the project a name "ANDNXOR_SIMTACO" -> Finish
    1. Note its a common mistake to just point it to a pre-existing folder and assume it will import your binary. It wont. You have to manually add the files to your project.
  4. File -> Import File -> Browse your computer and pick the "simtaco" binary
    1. You'll get some binary import summary results. Read them, it's interesting metadata about the program.
  5. Most important and never talked about part: To open your binary with Ghidra (which has now been imported) you need to click "simtaco" and drag it on to the Ghidra dragon icon, then let go.

A new window will open and it will tell you "simtaco has not been analyzed. Would you like to analyze it now?" HELL YEAH. Accept the default options and just click "Analyze" on the next window.

To help with all these screenshots and text, we will do our best to record videos along the way. Here's a recording of everything I just explained.

So right off the bat, if you've never done this before, you're probably thinking "okay...wtf"

Think of the left pane of windows as shortcuts to your program variables, symbols, and data types. The middle window is "disassembled code" as in that binary in assembly. The far right is pseudo-C style version of the binary which is "decompiled code." For ground truth of it all, assembly is always the way to go. However many of us don't think in memory registers and jumps. So this program is simple enough that we'll be fine with the decompiler. Those windows will always show you the disassembled and decompiled versions of the area of code you are looking at. So lets go to the most important function: Main. On the symbol tree, expand FUNCTIONS, scroll down,  and choose "main." Things should start to look a but more familiar in the decompiled window pane. However since it is decompiled, it has no idea what the variable names were. That's part of the fun, once you start figuring out what stuff does,  right click and rename variables as you go along. To make this easier and avoid less detailed screenshots, I will copy/pasta the full decompiled code from Ghidra into a code block below. 

undefined8 main(void)

{
  int iVar1;
  char *__s;
  char *__command;
  long in_FS_OFFSET;
  int local_e8;
  stat local_c8;
  byte abStack52 [12];
  byte local_28 [4];
  undefined local_24;
  undefined local_23;
  undefined local_22;
  undefined local_21;
  undefined local_20;
  undefined local_1f;
  undefined local_1e;
  undefined local_1d;
  byte local_1c [4];
  undefined local_18;
  undefined local_17;
  undefined local_16;
  undefined local_15;
  undefined local_14;
  undefined local_13;
  undefined local_12;
  undefined local_11;
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  __s = (char *)malloc(10);
  __command = (char *)malloc(0x80);
  iVar1 = stat(".tmp_cache",&local_c8);
  system("clear");
  putchar(10);
  printf(
        " \x1b[1;37m\x1b[41m╔════════════════════════════════════════════════════════════════════════════════╗\n\x1b[0m"
        );
  printf(&DAT_00100ef0);
  printf(&DAT_00100ef0);
  printf(
        "  \x1b[1;37m\x1b[41m║\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0            THANK U 4 PLAYIN SIM-TACO 3D\xa0                   \xa0\xa0\xa0\xa0\xa0\xa0║░\n\x1b[0m"
        );
  printf(&DAT_00101038);
  printf(
        "  \x1b[1;37m\x1b[41m║\xa0\xa0\xa0\xa0\xa0\xa0\xa0            (DIS GAME IZ COPY RITE (C)2033 BYAND!XOR)\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0║░\n\x1b[0m"
        );
  printf(&DAT_00100ef0);
  printf(&DAT_00100ef0);
  printf(&DAT_00101158);
  printf(&DAT_001011e0);
  printf(&DAT_00101270);
  printf(&DAT_00100ef0);
  printf(&DAT_00100ef0);
  printf(
        "  \x1b[1;37m\x1b[41m║\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0 U CAN HAZ\xa0REGISTERDSIM-TACO FUR AZ LIL AZ 14.99 DEF-COIN\xa0\xa0\xa0  \xa0\xa0\xa0\xa0\xa0\xa0\xa0║░\n\x1b[0m"
        );
  printf(&DAT_00101390);
  printf(&DAT_00100ef0);
  printf(&DAT_00100ef0);
  printf(
        "  \x1b[1;37m\x1b[41m║\xa0\xa0\xa0\xa0\xa0\xa0INCASE U R DUMB AN JUS LOST UR LICENSE FILEZC REMINDUR HINT BELOW:\xa0\xa0\xa0\xa0\xa0\xa0\xa0║░\n\x1b[0m"
        );
  printf(
        "  \x1b[1;37m\x1b[41m║\xa0\xa0\xa0\xa0\xa0\xa0  ANZWR 2 TEH ULTIMATE QUESHUN OV LIFE, TEHUNIVERS, AN EVRYTHIN\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0║░\n\x1b[0m"
        );
  printf(&DAT_00100ef0);
  printf(&DAT_00100ef0);
  printf(
        " \x1b[1;37m\x1b[41m╚════════════════════════════════════════════════════════════════════════════════╝░\n\x1b[0m"
        );
  printf(&DAT_00101648);
  printf("\n\x1b[1;91m");
  if (iVar1 == 0) {
    puts("HACK THE PLANET!");
    local_28[0] = 0x53;
    local_28[1] = 0x4b;
    local_28[2] = 0x51;
    local_28[3] = 0x38;
    local_24 = 0x43;
    local_23 = 0x4b;
    local_22 = 0x55;
    local_21 = 0x58;
    local_20 = 0x4e;
    local_1f = 0x34;
    local_1e = 0x4b;
    local_1d = 0x44;
    local_1c[0] = 7;
    local_1c[1] = 0xe;
    local_1c[2] = 0x19;
    local_1c[3] = 0x7b;
    local_18 = 2;
    local_17 = 0xe;
    local_16 = 0x1e;
    local_15 = 0x11;
    local_14 = 0x14;
    local_13 = 0x78;
    local_12 = 2;
    local_11 = 1;
    printf("License Accepted: ");
    local_e8 = 0;
    while (local_e8 < 0xc) {
      abStack52[(long)local_e8] = local_28[(long)local_e8] ^ local_1c[(long)local_e8];
      printf("%c ",(ulong)(uint)(int)(char)abStack52[(long)local_e8]);
      local_e8 = local_e8 + 1;
    }
    putchar(10);
    puts("Email the code, screenshot, and detailed explanation of your hack to hyr0n@andnxor.com\n")
    ;
    remove(".tmp_cache");
  }
  else {
    printf("REZULT: ");
    gets(__s);
    iVar1 = strcmp(__s,"42");
    if (iVar1 == 0) {
      puts("YEZ!\n");
    }
    else {
      puts("NOEP!\n");
    }
    fopen(".tmp_cache","wx");
    system(__command);
    remove(".tmp_cache");
  }
  printf("\x1b[0m");
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

First Pass Analysis

The goal of this challenge was to find the sekret word, however we crafted it such that there were multiple ways of doing it. While the solutions were unique, everyone participating had to first understand what the program was doing. Hyr0n will now walk you through his approach, its not better or worse than others, just his methodology when doing this kind of thing.

This is the control flow graph of the program. It takes the code and groups it in to logical blocks, where the change in control (i.e. loops, if statements, etc) could fork the path from start to finish of execution. Starting with this, printing it out or putting it on a second monitor, and writing down what is going on will help you take a good top down approach to reverse engineering. Remember, engineering is synthesis, reverse engineering is analysis. Make logical assumptions, investigate, validate or invalidate them, and use whatever data is there to help peel this onion. Going through the code and grouping it by the graph blocks...

  1. Declare variables, Print some graphics, Check if a file exists (tmp_cache)
  2. (IF) that file exists print Hack The Planet and some sekret code
  3. To print the sekret code, xor two arrays of integers together, then cast as characters. Then delete the tmp_cache file.
  4. (ELSE) Get input from the keyboard,
  5. (IF) That input is the value "42" say YEZ, (ELSE) Say NOEP
  6. Open the file tmp_cache, run a system call to whatever the value "command" is, delete .tmp_cache
  7. Clean up and close out the program

Once we know how the program works at a high level, this is where we try and use it in unintended ways. Are there ways to trick the logic as is without modification of the binary? Are there ways to cleverly modify the binary? Yes to both. Now on to the submitted solutions, the winners credited in parens.

Solution 1 - Just Touch ".tmp_cache" (@Crypto_Lizard)

The first way to get the sekret code was to simply create a hidden file named ".tmp_cache."

How would you figure this out? Look at line 35 in the code.

  iVar1 = stat(".tmp_cache",&local_c8);

While the thing in quotes is an initial tip off, look up what the stat function actually does. 

It tries to read information about the file in the first function argument and stores the results in the second argument, returning a successful 0 if it was able to obtain information (i.e. the file exists) and -1 if not. Further on in the code, you see that the variable which stored that result "iVar1" (what Ghidra named it) has a fork in logic where you proceed to show the code or fail out.

if (iVar1 == 0) {
    puts("HACK THE PLANET!");
    //...IM ABBREVIATING THE CODE PASTE TO AVOID REDUNDANCY
    remove(".tmp_cache");
  }
  else {
    printf("REZULT: ");
    //...IM ABBREVIATING THE CODE PASTE TO AVOID REDUNDANCY
    remove(".tmp_cache");
  }

By seeing that in the code, it would tip you off to just create a blank file with that name before running it, the program would see .tmp_cache, and proceed to show the sekret code. Almost everyone submitted this solution first, but the win went to @Crypto_Lizard for jumping right on it.

Solution 2 - Modify JNZ to JZ (@syn_ack_zack)

The second solution is actually one of my favorite go to tricks, as well as one of the first Code -> Assembly conversions one learns when they get into RE. All statements boil down to binary logic and IF statements then boil down to the decision being TRUE or FALSE. But that is inefficient for a compiler to track both those values, so simply compare a result and see if it is ZERO or NOT ZERO. Whichever it is, you then jump to a different section of code. This second hack focuses on the same as the first, but instead of making the condition valid by adding a file, we're going to change the logic so the non-existence of ".tmp_cache" makes the statement true and the sekret code is displayed. See below for a comparison of the assembly vs. the decompiled code.

Before we jump into hacking it, there is something which unfortunately must be done. At the time this writing there is a bug in Ghidra...with patching. Of all things to have a bug with, that's a bad one and we hope the code maintainers are working to resolve it as we speak. If you try to modify the code and export a patch it will result in a segmentation fault. But there's a work around, that has some down side to it because it impacts the clarity of the decompiled code and assembly, only do this once you know there's something you want to patch. Close out of the CodeBrowser, go back to the main project screen when Ghidra launches, and delete the SimTaco file you imported.

Now, re-import the file and make a mental note of whats in the Language field.

x86 Architecture, Little Endian, 64 Bit, Default GCC

Now change the Format drop down from ELF to RAW Binary... and look, language is blank now. Click the three dots and search for x86 Architecture, Little Endian, 64 Bit, Default GCC. Hit okay and now the file is loaded in to your project (again). Drag it back on to the CodeBrowser (green Ghidra icon) and let's patch that file. Instantly you will notice all of your symbols are gone and can't simply find the MAIN function. Just scroll through them all until the code you recognize in the decompile window pops up.

For comparison you can see what this workaround method makes the assembly and decompiled code look like. Its not horrible, but not great either. Hopefully the NSA makes it their priority to fix soon (there's already a bug filed on Github).

Now simply right click on the "JNZ" (jump if not zero) in Ghidra, go through a little pop up, then change it's value to "JZ" (jump if zero) and hit enter. CTRL+S to save. Then type the letter O and you will get a pop up for Exporting simtaco: ensure the format is BINARY and change the output name to something like "simtaco_patch." Go open your terminal and CHMOD+X that file so it's executable and run it. BAM! You just hacked the planet and didn't even need that hidden license file to get the sekret code. Well done @syn_ack_zack.

Solution 3 - XOR Obfuscation (@mythdude155)

The third solution was to find the sekret code in the binary itself. Now that's usually a level 0 crackme challenge and we're not fond of simply dumping strings on a binary because it's too damn easy. So Hyr0n has a simple, but effective mitigation to dumping strings through XOR obfuscation. He uses the ASCII codes of the letters then XORs the message with a key. Then we put the private key and the encoded message as arrays of integers (knowing they will be cast and printed as characters), then run them through an XOR loop. XOR a message with a key, it's encoded. XOR that output with the key again, it's back to its original value. It's easy to undo if you know what to look for, but it thwarts simple string dumps. Let's look at the code again...

 if (iVar1 == 0) {
    puts("HACK THE PLANET!");
    local_28[0] = 0x53;
    local_28[1] = 0x4b;
    local_28[2] = 0x51;
    local_28[3] = 0x38;
    local_24 = 0x43;
    local_23 = 0x4b;
    local_22 = 0x55;
    local_21 = 0x58;
    local_20 = 0x4e;
    local_1f = 0x34;
    local_1e = 0x4b;
    local_1d = 0x44;
    local_1c[0] = 7;
    local_1c[1] = 0xe;
    local_1c[2] = 0x19;
    local_1c[3] = 0x7b;
    local_18 = 2;
    local_17 = 0xe;
    local_16 = 0x1e;
    local_15 = 0x11;
    local_14 = 0x14;
    local_13 = 0x78;
    local_12 = 2;
    local_11 = 1;
    printf("License Accepted: ");
    local_e8 = 0;
    while (local_e8 < 0xc) {
      abStack52[(long)local_e8] = local_28[(long)local_e8] ^ local_1c[(long)local_e8];
      printf("%c ",(ulong)(uint)(int)(char)abStack52[(long)local_e8]);
      local_e8 = local_e8 + 1;
    }
}

Again a lot of this can be intimidating at first even if you have a background in writing software, because compiler's do some really weird shit and no one ever bothers to check how the sausage is made. Above you see some arrays and a LOT of variables, leading up to a while loop that XOR's "^" them together. Make note at first that "local_e8" is a counter, treat it like your typical "i" or "j" used in for/while loops. So that loop starts at 0 and while it is less than "0xc", count++. In Ghidra if you select and hover the cursor over 0xc it will automagically show you it's value in other bases: it's 12 decimal....cuz that was "c" hex. Lets all remember how to count in hex... :) But even if you forget it will convert it for you.

So, we are going to start with the array's local_e8 and local_1c and iterate over them 12 times. But if you look at them declared above, they only have 4 array cells. You were taught that's a programming no no. Well it's okay for compilers. Those were originally arrays of size 12, but there's overhead associated with making it that big for something simple. So the compiler figured out, let's just make them 4 cells big and put variables on the stack right after them so you "purposely" over run the buffer. It's okay, they're adjoining on the stack. But that means a good methodology to recognizes patterns and work this backwards is...

So applying that, this is what we get:

So let's go on the internet and use a simple XOR calculator to see what happens when they run through that loop? (Reminder single character values need a 0 prepended to them and set the output to ASCII so you can read it)

In this case, looking through the decompiled binary was enough to let you see a private key and xor encoded message. Once you have those values, just manually do the calculation yourself to see what it was. If you followed the code, after this XOR operation the value was printed out as the sekret. Tip of the hat @mythdude155.

Solution 4 - Buffer Overflow (@d1g1t4l_t3mpl4r)

The last solution...no one got within the initial contest limits. We got the first three solutions and we were sad because this crackme was designed around a buffer overflow with the other possibilities added in after the fact to so there were multiple paths to success. Also we liked the idea of being able to fire off e-mails back at people, crushing their spirits with "Sorry, that solution has already been submitted. Keep hacking." 

(note this is what Hyr0n actually looks like if he shaves his beard off)

So we let everyone know, fine, we'll accept just ONE more. Keep hacking. What you had to notice in the code was a call to the system() function, a very very dangerous practice (just like strcpy and memcpy). The system function takes whatever you enter as text and executes a command on the system. W.T.F. We'll some coders are lazy and make front ends GUIs this way which makes it useful or you could get the other processes to run as well which your own program may rely upon. So take a look through the code. Initially it's just used to clear the screen at the very beginning.

system("clear");

Not really a big deal. It's typing clear at the screen. But it's used a second time towards the end.

system(__command);

Remember the last solution where the arrays were a bit weird from optimization, but it was okay because the variables were instantiated and placed on the stack next to one another? We'll take a look at the beginning of the code.

undefined8 main(void)

{
  int iVar1;
  char *__s;
  char *__command;
....
  __s = (char *)malloc(10);
  __command = (char *)malloc(0x80);
}

So the stack first contains an integer, then a character array, then another character array...Those are actually just the pointers which are placed on the stack. Given we use malloc, the actual memory space for those character arrays are right next to one another on the heap. So if we have input for __s which exceeds its buffer, it is going to overflow in to __command. Then system() will execute whatever is contained in there (i.e. don't overflow it with rm -rf /).  I just used malloc back to back to allocate memory directly (ya know to ensure they're both right there on the heap hanging out with one another).  That means __s overflows into __command when the input is greater than what __s can hold.

It is used below when comparing the user input to 42 for the secret of the universe. All of this is nice but how does it help us get the sekret code?

The .tmp_cache file is created temporarily then deleted before the program closes.

    fopen(".tmp_cache","wx");
    system(__command);
    remove(".tmp_cache");

So if we can prevent that remove call from occurring, .tmp_cache is never deleted, and you break into the branch where the sekret code is displayed. What command could we run to do that...

Overflow simtaco by recursively executing simtaco.

Figuring all of this out, is why @d1g1t4l_t3mpl4r is a gentleman and a scholar.

In Closing...

Whether you found one of the floppy discs, succeed in this binary cracking challenge, witnessed from twitter, or even just stumbled upon this post, we hope it you enjoyed it and possibly learned something new. Above all, you should go and download Ghidra and start tearing apart binaries. Best way to start, is just write a simple program, then analyze it to see what your code looks like as assembly or pseudo C decompiled. It get's easier after a while. This was also a very benign application of all the capabilities Ghidra has, we really just had you decompile the binary to look at the code and generate a patch. The intent was to have a crackme challenge someone could solve in an evening and possibly spur some interest into a new field of security they maybe haven ventured in before. Challenges like this is what we like to pack in the badge, among other things like blinky lights and REDACTED. If you're into these kind of things, we will be giving away our badges at hacker summer camp this year due to the generosity of our Philanthropists and Sponsors.

Below is the original C code from the binary for comparison. Enjoy!

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>l
#include <string.h>

int main()
{
   //Initialize
   #define RED     "\x1b[1;91m"
   #define BG_RED  "\x1b[41m"
   #define WHITE   "\x1b[1;37m"
   #define RESET   "\x1b[0m"
   char output[12];
   char *imput;
   char *systemcommand;
   imput=(char *)malloc(10);
   systemcommand=(char *)malloc(128);
   struct stat status;
   int exists = stat(".tmp_cache", &status);

   //GFX
   system("clear");
   printf("\n");
   printf("  " WHITE BG_RED "╔════════════════════════════════════════════════════════════════════════════════╗\n" RESET);
   printf("  " WHITE BG_RED "║                                                                                ║░\n" RESET);
   printf("  " WHITE BG_RED "║                                                                                ║░\n" RESET);
   printf("  " WHITE BG_RED "║                          THANK U 4 PLAYIN SIM-TACO 3D                          ║░\n" RESET);
   printf("  " WHITE BG_RED "║                      SHAREWAREZ EDISHUN - SHARE WIT FRENDZ                     ║░\n" RESET);
   printf("  " WHITE BG_RED "║                   (DIS GAME IZ COPY RITE (C) 2033 BY AND!XOR)                  ║░\n" RESET);
   printf("  " WHITE BG_RED "║                                                                                ║░\n" RESET);
   printf("  " WHITE BG_RED "║                                                                                ║░\n" RESET);
   printf("  " WHITE BG_RED "║                OH HEI DIS SHARE WAREZ PROGRAM FAILZ AZ REGISTERD               ║░\n" RESET);
   printf("  " WHITE BG_RED "║                  THAR R -1337 DAIS REMAININ ON UR TRIAL PERIOD                 ║░\n" RESET);
   printf("  " WHITE BG_RED "║                        YER UNEEEK EYE DEE CODE IZ : 12345                      ║░\n" RESET);
   printf("  " WHITE BG_RED "║                                                                                ║░\n" RESET);
   printf("  " WHITE BG_RED "║                                                                                ║░\n" RESET);
   printf("  " WHITE BG_RED "║           U CAN HAZ REGISTERD SIM-TACO FUR AZ LIL AZ 14.99 DEF-COIN            ║░\n" RESET);
   printf("  " WHITE BG_RED "║                             (SUCH DEALZ, MUCH VALUE)                           ║░\n" RESET);
   printf("  " WHITE BG_RED "║                                                                                ║░\n" RESET);
   printf("  " WHITE BG_RED "║                                                                                ║░\n" RESET);
   printf("  " WHITE BG_RED "║      INCASE U R DUMB AN JUS LOST UR LICENSE FILEZ C REMINDUR HINT BELOW:       ║░\n" RESET);
   printf("  " WHITE BG_RED "║        ANZWR 2 TEH ULTIMATE QUESHUN OV LIFE, TEH UNIVERS, AN EVRYTHIN          ║░\n" RESET);
   printf("  " WHITE BG_RED "║                                                                                ║░\n" RESET);
   printf("  " WHITE BG_RED "║                                                                                ║░\n" RESET);
   printf("  " WHITE BG_RED "╚════════════════════════════════════════════════════════════════════════════════╝░\n" RESET);
   printf("   " WHITE BG_RED "░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░\n" RESET);
   printf("\n" RED);

   //Look for flag
   if(exists==0){
      //The flag exists, ekoz was recursively called or they just made the flag file
      printf("HACK THE PLANET!\n");

      //Lets fuck with people who dump strings and at least XOR the output
      //Hope they know what an XOR operation looks like in machine language :)
      
      //ASCII Value of key "SKQ8CKUXN4KD"
      char enc_key[12]={83,75,81,56,67,75,85,88,78,52,75,68};

      //ASCII Value of key XOR'd with "TEHCAEKIZLIE"
      char msg[12]={7, 14, 25, 123, 2, 14, 30, 17, 20, 120, 2, 1};

      printf("License Accepted: ");

      for (int i=0; i<12; i++){
         output[i] = enc_key[i] ^ msg[i];
         printf("%c ",output[i]);
      }
      
      printf("\n");
      printf("Email the code, screenshot, and detailed explanation of your hack to hyr0n@andnxor.com\n\n");

      //Remove the flag we/they created
      remove(".tmp_cache");
   }
   else{
      printf("REZULT: "); //Red Herring
      gets(imput);
      if(strcmp(imput, "42")==0)
         printf("YEZ!\n\n");
      else
      {
         printf("NOEP!\n\n");
      }

      //Create the flag
      FILE *fp = fopen(".tmp_cache","wx");
      
      //Mischief
      system(systemcommand);

      //Remove the flag we/they created
      remove(".tmp_cache");
   }
   printf(RESET);
   return 0;
}

Discussions