Playing Hacks and Stuffs!
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
Checking file type
Running strings we get this
This is a rust compiled program, we can also confirm by grepping it
Running it we get this
It asks for a 16 byte key and it does validate the input length
Loading it up in IDA here’s the main function
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
Looks so cryptic lmao!
Reading through it step by step it’s clear that it will first print some text then receive our input
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
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
Flag: flag{cc811d4486decc3379dd13688a46603f}
We are given two files
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
First it calls the readFlag
function passing a filename and an output buffer as the parameter
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
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
The function first opens the filename with flag set as writable
then it gets the length of the buf
by calling function sl
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
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
Flag: flag{3b050f5a716e51c89e9323baf3a7b73b}
We are given just a single executable
If we run it we’re asked to input a specific number
Loading it up in IDA here’s the main function
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
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
Flag: flag{h556cdd`=ag.c53664:45569368391gc}
We are given a powershell file
I saw it will base64 decoded the $encoded
variable so i just decoded it myself
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
Flag: flag{45d23c1f6789badc1234567890123456}
We are given just a binary
Running Detect It Easy
on it we see it’s a Go compiled binary
Running it we are asked to input some key
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
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
The main.validateByte
function looks interesting so i checked it
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
It seems main.gowrap1
calls the function so i went there
I also checked the xrefs
to this function
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
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
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
Flag: flag{78b229bed60e12514c94e85126b43ec4}
That’s all, thanks for reading
GG to my team mates they were on fire 🔥