- Running the ELF prompted us to enter a flag.
- If we entered any random string it simply said
Incorrect!
- I opened up the ELF in Ghidra and asked for it to analyze it.
- I analyzed all the stripped Functions. and found the the 3 necessary functions; the rest being useless.
- I analyzed the code and renamed essentials variables for understanding (also renamed function names).
- Here is the cleaned-up code for the 3 functions:
main
, flag-checker
, flag-checker-2
.
void main(int argc,char **argv){
int check_value;
size_t input_len;
long canary_offset;
char flag_buffer [40];
long stack_canary;
stack_canary = *(long *)(canary_offset + 0x28);
printf("Enter the flag: ");
fgets(flag_buffer,35,stdin);
input_len = strcspn(flag_buffer,"\n");
flag_buffer[input_len] = '\0';
flag_checker(flag_buffer);
if (check_value == 0) {
puts("Incorrect!");
}
else {
puts("Correct!");
}
if (stack_canary != *(long *)(canary_offset + 0x28)) {
__stack_chk_fail();
}
return;
}
void flag_checker(char *flag_input){
size_t length-of-flag;
long SF;
int i;
char buffer [40];
long SC;
SC = *(long *)(SF + 0x28);
length-of-flag = strlen(flag_input);
if (length-of-flag == 34) {
flag-checker-2(flag_input,buffer);
for (i = 0; (i < 34 && (buffer[i] == (&DAT_00102020)[i])); i = i + 1) {
}
}
if (SC == *(long *)(SF + 0x28)) {
return;
}
__stack_chk_fail();
}
void flag-checker-2(char *flag_input,char *buffer){
int i;
for (i = 0; i < 34; i = i + 1) {
buffer[i] = (flag_input[i] ^ 90U) + (char)i;
buffer[i] = buffer[i] << 3 | (byte)buffer[i] >> 5;
}
return;
}
- But even after analyzing all these things. i couldn’t get the flag because the
DAT_00102020
is not disassembled. - So i opened the file in
Radare2
and started analyzing it. Here is the analyzing breakdown/summary:
(kali@LEOPARD-PC)-[~/CTF-Events/Nullcon-CTF-2025/REV]$ r2 -A flag-checker
...
[0x00001100]> afl
...
0x00001100 1 37 entry0
0x00001318 6 173 main
0x00001090 1 11 fcn.00001090
0x00001130 4 34 fcn.00001130
0x000011e9 4 145 fcn.000011e9
0x0000127a 11 158 fcn.0000127a
...
[0x00001100]> s main
[0x00001318]> pdf
...
│ 0x0000137a 488d45d0 lea rax, [s1]
│ 0x0000137e 4889c7 mov rdi, rax ; char *arg1
│ 0x00001381 e8f4feffff call fcn.0000127a
│ 0x00001386 85c0 test eax, eax
│ ┌─< 0x00001388 7411 je 0x139b
│ │ 0x0000138a 488d05c40c.. lea rax, str.Correct_ ; 0x2055 ; "Correct!"
...
[0x00001318]> s fcn.0000127a
[0x0000127a]> pdf
...
│ ╎││ 0x000012dd 488d0d3c0d.. lea rcx, [0x00002020]
│ ╎││ 0x000012e4 0fb60408 movzx eax, byte [rax + rcx]
│ ╎││ 0x000012e8 38c2 cmp dl, al
│ ┌────< 0x000012ea 7407 je 0x12f3
│ │╎││ 0x000012ec b800000000 mov eax, 0
│ ┌─────< 0x000012f1 eb0f jmp 0x1302
│ ││╎││ ; CODE XREF from fcn.0000127a @ 0x12ea(x)
...
[0x0000127a]> px 34 @0x12f3
- offset - F3F4 F5F6 F7F8 F9FA FBFC FDFE FF 0 1 2 3456789ABCDEF012
0x000012f3 8345 cc01 837d cc21 7ed1 b801 0000 0048 .E...}.!~......H
0x00001303 8b55 f864 482b 1425 2800 0000 7405 e8aa .U.dH+.%(...t...
0x00001313 fdff ..
[0x0000127a]>
- Now we have the flag but it is in encrypted form. So quicky wrote this script to decode the flag:
def reverse_flag_checker(buffer):
flag_input = bytearray(34)
for i in range(34):
temp = buffer[i]
temp = (temp >> 3) | (temp << 5) & 0xFF
flag_input[i] = (temp - i) ^ 0x5A
return bytes(flag_input)
buffer_hex = "f8a8b8216073908380c39b80ab0959d321d3dbd8fb4999e0793c4c492c29ccd4dc42"
buffer = bytes.fromhex(buffer_hex)
original_flag = reverse_flag_checker(buffer)
print(original_flag.decode())
- Executing this python3 script gave me the flag.
FLAG: ENO{R3V3R53_3NG1N33R1NG_M45T3R!!!}
- The two files that they provided us with were:
import random
def encode_flag(flag, key):
xor_result = [ord(c) ^ key for c in flag]
chunk_size = 4
chunks = [xor_result[i:i+chunk_size] for i in range(0, len(xor_result), chunk_size)]
seed = random.randint(0, 10)
random.seed(seed)
random.shuffle(chunks)
scrambled_result = [item for chunk in chunks for item in chunk]
return scrambled_result, chunks
def main():
flag = "REDACTED"
key = REDACTED
scrambled_result, _ = encode_flag(flag, key)
print("result:", "".join([format(i, '02x') for i in scrambled_result]))
if __name__ == "__main__":
main()
result: 1e78197567121966196e757e1f69781e1e1f7e736d6d1f75196e75191b646e196f6465510b0b0b57
- I wrote a script to brute force the key and seed with the given
result
. After analyzing all 2560
results found that the key was 42
and seed was 10
. Here is the script code:
import random
def reverse_scramble(scrambled_result, seed, chunk_size=4):
random.seed(seed)
num_chunks = len(scrambled_result)
chunks = [scrambled_result[i:i + chunk_size] for i in range(0, len(scrambled_result), chunk_size)]
indices = list(range(num_chunks))
random.shuffle(indices)
unshuffled_chunks = [None] * num_chunks
for i, idx in enumerate(indices): unshuffled_chunks[idx] = chunks[i]
unscrambled_result = [item for chunk in unshuffled_chunks for item in chunk]
return unscrambled_result
def decode_flag(scrambled_result, key, seed):
unscrambled_result = reverse_scramble(scrambled_result, seed)
decoded_result = [chr(byte ^ key) for byte in unscrambled_result]
return ''.join(decoded_result)
scrambled_hex = "1e78197567121966196e757e1f69781e1e1f7e736d6d1f75196e75191b646e196f6465510b0b0b57"
scrambled_result = [int(scrambled_hex[i:i+2], 16) for i in range(0, len(scrambled_hex), 2)]
key = 42
seed = 10
flag = decode_flag(scrambled_result, key, seed)
print("Decoded flag:", flag)
- Executing the Script gave me the flag:
FLAG: ENO{5CR4M83L3D_3GG5_4R3_1ND33D_T45TY!!!}
- I download the
usbnet.pcapng
file and directly uploaded it to CyberChef
. - and Imported the
Extract Files
Module from the list. CyberChef
found a PNG
file embed inside of a packet.
- Downloaded and Opened up the file. It was a QR Code.
- Scanning the QR Code gave me the Flag.
FLAG: ENO{USB_ETHERNET_ADAPTER_ARE_COOL_N!C3}
- Opening the link showed a simple interface, representing pages of the book.
- It showed all the pages from
2 to 10
except 1
.
- The source code was just simple
PHP
connecting SQL
Database to the frontend. - It check if the
min
is less then or equal to 1
or max
is greater then 10
.
<?php
ini_set("error_reporting", 0);
ini_set("display_errors",0);
if(isset($_GET['source'])) {
highlight_file(__FILE__);
}
include "flag.php";
$db = new SQLite3('/tmp/db.db');
try {
$db->exec("CREATE TABLE pages (id INTEGER PRIMARY KEY, title TEXT UNIQUE, content TEXT)");
$db->exec("INSERT INTO pages (title, content) VALUES ('Flag', '" . base64_encode($FLAG) . "')");
$db->exec("INSERT INTO pages (title, content) VALUES ('Page 1', 'This is not a flag, but just a boring page.')");
$db->exec("INSERT INTO pages (title, content) VALUES ('Page 2', 'This is not a flag, but just a boring page.')");
$db->exec("INSERT INTO pages (title, content) VALUES ('Page 3', 'This is not a flag, but just a boring page.')");
$db->exec("INSERT INTO pages (title, content) VALUES ('Page 4', 'This is not a flag, but just a boring page.')");
$db->exec("INSERT INTO pages (title, content) VALUES ('Page 5', 'This is not a flag, but just a boring page.')");
$db->exec("INSERT INTO pages (title, content) VALUES ('Page 6', 'This is not a flag, but just a boring page.')");
$db->exec("INSERT INTO pages (title, content) VALUES ('Page 7', 'This is not a flag, but just a boring page.')");
$db->exec("INSERT INTO pages (title, content) VALUES ('Page 8', 'This is not a flag, but just a boring page.')");
$db->exec("INSERT INTO pages (title, content) VALUES ('Page 9', 'This is not a flag, but just a boring page.')");
$db->exec("INSERT INTO pages (title, content) VALUES ('Page 10', 'This is not a flag, but just a boring page.')");
} catch(Exception $e) {
//var_dump($e);
}
if(isset($_GET['p']) && str_contains($_GET['p'], ",")) {
[$min, $max] = explode(",",$_GET['p']);
if(intval($min) <= 1 ) {
die("This post is not accessible...");
}
try {
$q = "SELECT * FROM pages WHERE id >= $min AND id <= $max";
$result = $db->query($q);
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
echo $row['title'] . " (ID=". $row['id'] . ") has content: \"" . $row['content'] . "\"<br>";
}
}catch(Exception $e) {
echo "Try harder!";
}
} else {
echo "Try harder!";
}
?>
<html>
<head>
<title>Paginator</title>
</head>
<body>
<h1>Paginator</h1>
<a href="/?p=2,10">Show me pages 2-10</a>
<p>To view the source code, <a href="/?source">click here.</a>
</body>
</html>
- Simply using modular arithmetic to get
1
as result revealed the base64 encoded flag.
- Decoded the flag with
CyberChef
.
FLAG: ENO{SQL1_W1th_0uT_C0mm4_W0rks_SomeHow!}