Recently I completed Tier 1 of Target’s Cyber Defense Challenge offered to members of the WiCys (Women in Cybersecurity) organization. It was a CTF comprised of four categories: cryptography/steganography, reverse engineering, USB forensics, and cyber threat intelligence. In this second part, I will go over the challenges in the reverse engineering section. In my opinion, this was the most technical challenge as knowledge of basic assembly (x86) and the C programming language was required.

Shoutout to Lan Che for bringing up the alternative solutions for A5M and Yarrr, would suggest looking at writeups :3

Challenges

A5M

100 points

My reversing skills are not what they use to be. Can you analyze the assembly code and recover the flag?

*TODO: Go more in depth with tracing through the assembly

In this challenge, a file called A5M.bin was given although it was determined that it was a simple txt file after running the file command. The file included some assembly. I decided to statically analyze the file and trace through the assembly line by line while keeping track of the stack.

I translated the assembly into C code to make it easier for me to understand:

long long int var1 = 1893775824357884702; 
long long int var2 = 739178745589344000;
long long int var3 = 1087083870128062999;
long long int var4 = 8032295758502981496; // "xorxorxor"
unsigned short var5 = 114; 
unsigned int var6 = 21;
    
unsigned char str1[] = {0x1e, 0x03, 0x13, 0x1f, 0x14, 0x0b, 0x48, 0x1a, 0x00, 0x27, 0x5f, 0x1c, 0x27, 0x17, 0x42, 0x0a, 0x30, 0x05, 0x19, 0x16, 0x0f};  
  
unsigned char str2[] = {0x78, 0x6f, 0x72, 0x78, 0x6f, 0x72, 0x78, 0x6f, 0x72};  
  
for (int i = 0; i < var6; i++) {  
	unsigned char ch1 = str1[i];  
	int index = i % strlen(str2);  
	unsigned char ch2 = str2[index];  
	str1[i] = ch1 ^ ch2;  
}  
  
puts(str1);

Flag: flag{y0ur_0n_x0r_way}

EDIT: Alternative way: just add the header and run it in tio.run

Programming language: gcc, x64, Linux

Header:

.intel_syntax noprefix
.section .data
.section .text
.globl main

r04c4

100 points

It seems I skipped RE101. I may need to brush up on my C programming before analyzing the code.

TODO: Go more in depth explaining rc4

The attached file was a C program.

At first look, a few things stood out.

  • k refers to the key. The characters, when printed out, resulted in r0tc4. I was wondering if it was intentional as the title of the challenge was r04c4.
unsigned char k[]="\162\x30\164\x63\64";
  • c holds the text as follows:
c[]={0x54,0206,0xdb,0242,0xd7,0151,0x38,0114,0x59,0235,0xd9,0340,0xeb,0100,0x84,0365,0xbd,0237,0x39,0143,0xa3,0243 }; // a mix of hex (0x) and octal (0) values
  • d() refers to the method for decrypting (and encrypting) the message. There was a call to d() in main, but no arguments were provided, so I added d(k, c, p) where k is the key, c is the message to be decrypted, and p is the array to be filled with the decrypted text.

Running the code as it is gives me a bunch of garbled text. Looking at the code further, as I know d() is a method for encryption/decryption, I wanted to figure out what cipher it was using. As the title of the challenge hinted, I eventually discovered that it was the rc4 cipher. I researched the cipher and traced through d() and realized that the process was almost the exact same except that in the r04c4 program, the size of the buffer was 400 rather than 256 as stated in the rc4 cipher. When I modified the buffer size, I got the following:

MzkuM3fkK2jjqwAspzZ0sD

It appears that I was closer, but that it had another layer of obfuscation. Here’s where the characters of the key k came to play; r0t was a hint towards what type of encoding/encryption was used. I thought it was the ROT13 cipher again, but that seemed to simple. After experimenting, I found that it was encoded using Base64 with the alphabet being ROT13.

Flag: flag{1_l0v3_rc4}

Sc0rf1g

200 points

The reverse engineering team is on vacation… They were working on extracting what they thought was a config from a Shiny Scorpion payload. We need you to confirm this!

This was one of the challenges I struggled more on…(it was actually the last challenge I needed to solve). To be honest, I had to guess quite a bit on this one. I wonder if there was a less guessy approach to it.

The attached file was a binary that the clue hinted at was a config from a malicious payload. At first I tried different extractors, but wasn’t getting anywhere, so I kept researching. I uploaded the file to CyberChef to check the entropy. image The Shannon entropy was 7.186777424475342, which indicated that it might be either encrypted or compressed.

I also looked at the file through an hex editor, https://hexed.it/. The only clue I could find there was that the there was a repeated string at the end of the file. I assumed that this could be the key. Now I just need to find how it was encrypted.

image Here, I brute forced it a little bit. I went through all the encryption methods until I settled on XOR. The decoded output was mostly garbage with a few human readable strings, so I knew that I was getting close. I played around with the key until I landed on 0x4669569c9a870431 which gave me human readable text (attached in the appendix). From there, I copied the string until the null terminator:

MzkuM3gmnQShrI9mLmOlpTxjoy9mqQShM3AsLJquZJ59

Using the magic recipe in CyberChef, I found that it was base64 encoded.

Flag: flag{sh1ny_sc0rpi0n_st1ngs_aga1n}

Yarrr

200 points

Shiver me timbers, it seems the Cap’n o’ this here file ‘as ‘idden a treasure! Can ye navigate the code to ’elp find it?

TODO go more indepth in the process of understanding the decompiled and assemblly

The yarrr file given was executable (just make sure you give it executable permissions) and that the outpit is initially :(. I tried using gdb to step through but I ended up going with static analysis because the decompiled code was easy to understand. I decompiled the file using https://dogbolt.org/. From the raw output, there were nested conditionals that stipulated that argv, which is an array of strings that are passed from the command line to a program, needed to match the output of a certain array, which was v8 in my code. image If the condition matched, the string would go through some XOR operations, which printed out the flag.

Flag: flag{ye_w0n_that_a222gum3nt}

A funny side note was that I actually got the flag, but I didn’t realize I did, so I kept working on it until I gave up and submitted only to realize that I had the flag.

EDIT: Alternative path

──(kali㉿kali)-[~/Downloads/target_ctf/rev_eng]
└─$ ./yarrr 2 d c 1 a 7 1 5 1 c c e 2 4 8 b 0 1 0 b b d 0 6 d e 2 b 4 2 5 4
flag{ye_w0n_that_a222gum3nt}

Web2ut3

300 points

The IR team found what appears to be a login page for Shiny Scorpion…

First, I prettified the html to make it more human readable using the link:  https://webformatter.com/html

I noticed that at the end of the script were some strings that seemed to be sha256 hashes. image

I checked https://hashes.com/en/decrypt/hash for the hashes although you can also use hashcat.

f5b3c8c432e54fdb1f92e6a4977f2d8c118f6cb3990e775978d6de786b2be067:$HEX[d181d0bad0bed180d0bfd0b8d0bed0bd]  
28a5056223c6dccaee649380e40ec8c6829772138ab7d64e0739d34b5504f307:redSCORPION

The HEX indicated that there was another layer of hex, so I put it in cyberchef with the UTF8 encoding:

скорпион

With this, when I submitted the login with the username of скорпион and the password redSCORPION, I went to the console in page inspect for the flag.

image

Flag: flag{y0u_r0ck3d_that_0n3}

Appendix

A5M

Raw notes of how I traced through A5M. Definitely overkill, but a nice way for me to review assembly! image image image

Sc0rpf1g

Entire output of the decoded config text image

Yarrr

The raw modified decompiled code

#include <stdio.h>
#include <stdint.h>
int main() {
  // signed int i; // [rsp+10h] [rbp-60h]
  char *size_4; // [rsp+18h] [rbp-58h]
  __int64_t v6[4]; // [rsp+20h] [rbp-50h]
  int v7; // [rsp+38h] [rbp-38h]
  char v8[40]; // [rsp+40h] [rbp-30h]
  // unsigned __int64_t v9 = __readfsqword(0x28u); // Read memory from a location specified by an offset relative to the beginning of the FS segment

  v6[0] =  0x6A544E1A56020854LL;
  v6[1] = 0x16595C463A0D5346LL;
  v6[2] = 0x5B4503505002506FLL;
  v6[3] = v7;
  v7 = 524684119;
  size_4 = (char *)malloc(0x1CuLL);

  v8[0] = 50;
  v8[1] = 100;
  v8[2] = 99;
  v8[3] = 49;
  v8[4] =97;
  v8[5] =55;
  v8[6] = 49;
  v8[7] =53;
  v8[8] = 49;
  v8[9] =99;
  v8[10] =99;
  v8[11] =101;
  v8[12] =50;
  v8[13] =52;
  v8[14] =56;
  v8[15] =98;
  v8[16] =48;
  v8[17] =49;
  v8[18] =48;
  v8[19] =98;
  v8[20] =98;
  v8[21] =100;
  v8[22] =48;
  v8[23] =54;
  v8[24] =100;
  v8[25] =101;
  v8[26] =50;
  v8[27] =98;
  v8[28] =52;
  v8[29] =50;
  v8[30] =53;
  v8[31] =52;

  for (int i = 0; i < 28; i++) {
    size_4[i] =v8[i & 0x1F] ^ * (char *)((long long) &v6 + (long)i);
  }
  puts(size_4);
  return 0;
  
}