➜ ~

Playing Hacks and Stuffs!


Project maintained by h4ckyou Hosted on GitHub Pages — Theme by mattgraham

Fetch The Flag CTF

image

This is my writeup for some of the challenges i solved

I did solve all reverse engineering but i was really busy with school so hence my writeup coming late

Challenge Solved (not based on difficulty)

Crab Shell

Checking file type image

Running strings we get this image

This is a rust compiled program, we can also confirm by grepping it image

Running it we get this image

It asks for a 16 byte key and it does validate the input length

Loading it up in IDA here’s the main function image

I’m not so much familiar with rust reversing cause i don’t know rust but i’ve looked at one or two decompilation before so i’m certain that the main program logic at crabshell::main

Decompiling it we have this image image

Looks so cryptic lmao!

Reading through it step by step it’s clear that it will first print some text then receive our input image

Next it will make sure the received input length is 16 then it compares the input with some hardcoded value, if all the bytes matches it will then compute the md5 hash and print it out image

So the important part is here:

  {
    if ( *(_BYTE *)v1 == 49
      && *(_QWORD *)(v1 + 1) == 0x1F221731232D1F26LL
      && *(_DWORD *)(v1 + 9) == 1684542258
      && *(_BYTE *)(v1 + 13) == 100
      && *(_BYTE *)(v1 + 14) == 104
      && *(_BYTE *)(v1 + 15) == 104 )
    {

We simply just need to make sure the bytes it checks matches

Since IDA is so awesome it already defined the right data type making life easier for us

So v1 is the buffer where it stores our input

Just a quick note:

With this we know that:

- v1[0] = 49
- v1[1:9] = 0x1F221731232D1F26
- v1[9:13] = 1684542258
- v1[13] = 100
- v1[14] = 104
- v1[15] = 104

We can just throw that in python and print it’s bytes representation

import struct

v1 = [0] * 16

qword = 0x1F221731232D1F26
dword = 0x64681332

value1 = struct.pack("<Q", qword)
value2 = struct.pack("<I", dword)

v1[0] = 49
v1[1:9] = value1
v1[9:13] = value2
v1[13] = 100
v1[14] = 104
v1[15] = 104

expected = bytes(v1)

print(expected, len(expected))

with open("a.out", "wb") as f:
    f.write(expected)

Running it works and we get the flag image

Flag: flag{cc811d4486decc3379dd13688a46603f}

Letters To Num

We are given two files image

We can make assumption that the letter2nums.elf file encoded the original flag and encflag.txt is the result

Loading it up in IDA here’s the main function image

First it calls the readFlag function passing a filename and an output buffer as the parameter image

The function simply reads the flag.txt file and stores the content in flag_buf

Next it calls the c function passing some text as first parameter, the flag_buf as the second parameter and an output buffer buf as the third parameter image

What this simply does is to serializes the first message along with the plaintext flag into an output buffer

Then finally it calls the writeFlag function which takes an output filename and the buffer containing what we want to encode image

The function first opens the filename with flag set as writable then it gets the length of the buf by calling function sl image

The sl function calculates the length of the buf recursively

Then finally it iterates through the size of the buf in chunks of 2 and calls the encodeChars function on buf[i] and buf[i+1] where the output is then stored in the file stream opened earlier image

The encodeChars function really doesn’t do much

__int64 __fastcall encodeChars(char byte1, char byte2)
{
  int result; // eax

  result = byte1 << 8;                          // upper byte
  LOWORD(result) = byte2;
  return (byte1 << 8) | (unsigned int)result;
}

It takes two bytes (byte1 and byte2) and packs them into a 16-bit integer

We can easily recover the plaintext

Here’s my solve

array = []

with open("encflag.txt", "r") as f:
    for line in f.readlines():
        value = line.strip()
        array.append(int(value))

decoded = b""

for i in range(len(array)):
    value = array[i].to_bytes(2, byteorder="big")
    decoded += value

print(decoded)

Running it we get the flag image

Flag: flag{3b050f5a716e51c89e9323baf3a7b73b}

Math For Me

We are given just a single executable image

If we run it we’re asked to input a specific number image

Loading it up in IDA here’s the main function image

Basically based on the number provided it will validate if it’s right then uses that number to generate the flag

That means the main thing is check_number image

Just a very basic math

(5 * a1 + 4) / 2 == 52

We just need to solve for a1 in the equation

(5 * a1 + 4) = (52 * 2)
5 * a1 = (52 * 2) - 4
a1 = ((52 * 2) - 4) // 5
a1 = 20

This means the special number is 20 image

Flag: flag{h556cdd`=ag.c53664:45569368391gc}

PShell

We are given a powershell file image

I saw it will base64 decoded the $encoded variable so i just decoded it myself image

It will base64 decode another string then compare the environment variable MAGIC_KEY with Sup3rS3cr3t! and if it matches it prints the decoded value

Yet again i decoded it myself image

Flag: flag{45d23c1f6789badc1234567890123456}

It’s Go Time

We are given just a binary image

Running Detect It Easy on it we see it’s a Go compiled binary image

Running it we are asked to input some key image

This is similar to the rust challenge

Also i am not familiar with Go rev so this challenge was much difficult to me but the overall idea was easy

Loading it up in IDA here’s the main function image image

Hmmm, i don’t understand, but we can make assumption that it just reads the input and probably does some check?

To confirm I checkced the available functions and saw this

image

The main.validateByte function looks interesting so i checked it image

Before i moved on to anything else i needed to make sure it was actually being used by the program so i checked the xrefs and got this image

It seems main.gowrap1 calls the function so i went there image

I also checked the xrefs to this function image

I see it’s loaded in main.main which is all good since this means the main.main function will later call the main.validateByte function

Now we can dig deep in the validate function

// main.validateByte
void __golang main_validateByte(uint8 input, int index, chan_chan_left__main_validationResult_0 results)
{
  char v3; // [rsp+0h] [rbp-1Ah]
  char v4; // [rsp+1h] [rbp-19h]
  int elem; // [rsp+2h] [rbp-18h] BYREF
  bool v6; // [rsp+Ah] [rbp-10h]

  if ( index >= (unsigned __int64)qword_592B08 )
    runtime_panicIndex();
  v4 = ~*((_BYTE *)main_expectedBytes + index);
  v3 = (input + index) ^ 0x42;
  time_Sleep(10000000LL);
  elem = index;
  v6 = v4 == v3;
  runtime_chansend1((runtime_hchan_0 *)results, &elem);
}

First it makes sure that the index is not greater than or equal to 16 image

Then it extracts some bytes from main_expectedBytes[index] and takes the bitwise NOT operator on the result then it does input[index] + index xored with 0x42 and compared with the value in v4

We just need to extract the value stored in main_expectedBytes and do the reverse operation of it image

Here’s my solve

import struct

enc_bytes = [0xcbc68c9994cd9785, 0xcc938f9e98c79bca]
buf = struct.pack("<Q", enc_bytes[0]) + struct.pack("<Q", enc_bytes[1])
key = 0x42

flag = ""

for i in range(0, len(buf)):
    value = ((~buf[i] & 0xff) ^ key) - i
    flag += chr(value)

with open("a.out", "w") as f:
    f.write(flag)

Running it works image

Flag: flag{78b229bed60e12514c94e85126b43ec4}

That’s all, thanks for reading

GG to my team mates they were on fire 🔥