Flux Capacitor
The Flux Capacitor in Dr. Brown's old car is acting up, leaving him stuck in the wrong timeline. Maybe the “data” inside it can help him get the DeLorean running again. Author: c0smic

Di sini kita diberi file stripped elf
~/ctf/beectf/rev/fluxcapacitor
❯ file chall 09:53:34
chall: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=692d65dfc73cb3865f92959ec407ae58140231ac, for GNU/Linux 3.2.0, strippedNah aku langsung buka dogbolt.org untuk decompile ini secara online, karena aku males buka IDA.
Ini output decompilenya (banyak)
/* This file was generated by the Hex-Rays decompiler version 9.4.0.260714.
Copyright (c) 2007-2025 Hex-Rays <info@hex-rays.com>
Detected compiler: GNU C++
*/
#include <defs.h>
//-------------------------------------------------------------------------
// Function declarations
__int64 (**init_proc())(void);
void sub_1020();
// void free(void *ptr);
// int putchar(int c);
// char *strncpy(char *dest, const char *src, size_t n);
// __int64 __fastcall __isoc23_strtoull(_QWORD, _QWORD, _QWORD); weak
// int puts(const char *s);
// int printf(const char *format, ...);
// char *fgets(char *s, int n, FILE *stream);
// void *calloc(size_t nmemb, size_t size);
// __int64 ptrace(enum __ptrace_request request, ...);
// int setvbuf(FILE *stream, char *buf, int modes, size_t n);
// int atoi(const char *nptr);
// void __noreturn exit(int status);
// int _cxa_finalize(void *);
void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)());
FILE **sub_1130();
__int64 sub_1160();
FILE **sub_11A0();
__int64 sub_11E0();
__int64 sub_11E9();
int __fastcall sub_121D(__int64 a1, unsigned __int64 a2);
unsigned __int64 __fastcall sub_12DD(_BYTE *a1);
void term_proc();
// int _libc_start_main(int (*main)(int, char **, char **), int argc, char **ubp_av, void (*init)(), void (*fini)(), void (*rtld_fini)(), void *stack_end);
// int __cxa_finalize(void *);
// __int64 ITM_deregisterTMCloneTable(void); weak
// __int64 _gmon_start__(void); weak
// __int64 ITM_registerTMCloneTable(void); weak
//-------------------------------------------------------------------------
// Data declarations
_UNKNOWN main;
_BYTE byte_2030[48] =
{
26,
89,
4,
13,
89,
4,
53,
58,
31,
4,
51,
94,
53,
14,
89,
6,
90,
24,
89,
94,
4,
53,
91,
83,
82,
95,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
}; // weak
_BYTE byte_2060[56] =
{
-77,
-96,
111,
103,
64,
37,
65,
5,
-99,
-112,
114,
123,
119,
34,
74,
34,
-110,
-12,
126,
20,
102,
60,
94,
80,
-110,
-73,
83,
84,
96,
80,
94,
60,
-126,
-112,
105,
71,
39,
16,
73,
60,
-107,
-81,
104,
22,
37,
16,
9,
87,
-126,
-68,
119,
0,
0,
0,
0,
0
}; // weak
const char byte_2155 = '\0'; // idb
void *off_4068 = &off_4068; // idb
FILE *stdout; // idb
FILE *stdin; // idb
char byte_4088; // weak
//----- (0000000000001000) ----------------------------------------------------
__int64 (**init_proc())(void)
{
__int64 (**result)(void); // rax
result = &_gmon_start__;
if ( &_gmon_start__ != nullptr )
return (__int64 (**)(void))_gmon_start__();
return result;
}
// 4108: using guessed type __int64 _gmon_start__(void);
//----- (0000000000001020) ----------------------------------------------------
void sub_1020()
{
JUMPOUT(0);
}
// 1026: control flows out of bounds to 0
//----- (0000000000001100) ----------------------------------------------------
// positive sp value has been detected, the output may be wrong!
void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)())
{
__int64 v3; // rax
int v4; // esi
__int64 v5; // [rsp-8h] [rbp-8h] BYREF
char *retaddr; // [rsp+0h] [rbp+0h] BYREF
v4 = v5;
v5 = v3;
_libc_start_main((int (*)(int, char **, char **))main, v4, &retaddr, nullptr, nullptr, a3, &v5);
__halt();
}
// 1106: positive sp value 8 has been found
// 110D: variable 'v3' is possibly undefined
//----- (0000000000001130) ----------------------------------------------------
FILE **sub_1130()
{
return &stdout;
}
// 4100: using guessed type __int64 ITM_deregisterTMCloneTable(void);
//----- (0000000000001160) ----------------------------------------------------
__int64 sub_1160()
{
return 0;
}
// 4110: using guessed type __int64 ITM_registerTMCloneTable(void);
//----- (00000000000011A0) ----------------------------------------------------
FILE **sub_11A0()
{
FILE **result; // rax
if ( byte_4088 == 0 )
{
if ( &__cxa_finalize != nullptr )
_cxa_finalize(off_4068);
result = sub_1130();
byte_4088 = 1;
}
return result;
}
// 4088: using guessed type char byte_4088;
//----- (00000000000011E0) ----------------------------------------------------
// attributes: thunk
__int64 sub_11E0()
{
return sub_1160();
}
//----- (00000000000011E9) ----------------------------------------------------
__int64 sub_11E9()
{
__int64 result; // rax
result = ptrace(PTRACE_TRACEME, 0, 1, 0);
if ( result < 0 )
exit(1);
return result;
}
//----- (000000000000121D) ----------------------------------------------------
int __fastcall sub_121D(__int64 a1, unsigned __int64 a2)
{
__int64 v5; // [rsp+18h] [rbp-18h]
int i; // [rsp+2Ch] [rbp-4h]
for ( i = 0; i < a2; ++i )
{
v5 = *(char *)(i + a1);
if ( i <= 189 || i > 217 )
printf("%llu, ", v5);
else
printf("%llu, ", v5 ^ (i % 7 + 55));
}
return putchar(10);
}
//----- (00000000000012DD) ----------------------------------------------------
unsigned __int64 __fastcall sub_12DD(_BYTE *a1)
{
_BYTE *v1; // rax
__int64 i; // [rsp+18h] [rbp-10h]
unsigned __int64 v5; // [rsp+20h] [rbp-8h]
v5 = 5381;
for ( i = 0; ; ++i )
{
v1 = a1++;
if ( *v1 == 0 )
break;
v5 = (0x9E3779B97F4A7C15LL * i) ^ ((33 * v5 + (unsigned __int8)*v1) >> 13) ^ (33 * v5 + (unsigned __int8)*v1);
}
return v5;
}
//----- (000000000000135D) ----------------------------------------------------
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
char v4[32]; // [rsp+0h] [rbp-B0h] BYREF
char nptr[16]; // [rsp+20h] [rbp-90h] BYREF
char s[79]; // [rsp+30h] [rbp-80h] BYREF
unsigned __int8 v7; // [rsp+7Fh] [rbp-31h]
unsigned __int64 v8; // [rsp+80h] [rbp-30h]
unsigned __int64 v9; // [rsp+88h] [rbp-28h]
int v10; // [rsp+94h] [rbp-1Ch]
char *dest; // [rsp+98h] [rbp-18h]
__int64 j; // [rsp+A0h] [rbp-10h]
__int64 i; // [rsp+A8h] [rbp-8h]
sub_11E9();
setvbuf(stdout, nullptr, 2, 0);
dest = (char *)calloc(0xFAu, 1u);
if ( dest == nullptr )
return 1;
for ( i = 0; byte_2030[i] != 0; ++i )
dest[i + 190] = byte_2030[i] ^ 0x6A;
puts("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]");
puts("[][] [][]");
puts("[][] FLUX CAPACITOR TEMPORAL CALIBRATION SYSTEM v1.21 [][]");
puts("[][] [][]");
puts("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]");
puts(&byte_2155);
puts("Enter your calibration note:");
if ( fgets(s, 64, stdin) == nullptr )
return 1;
if ( s[0] == 10 )
{
puts("Critical Error");
return 0;
}
else
{
strncpy(dest, s, 0x30u);
puts("How many bytes of memory state do you want to inspect?");
if ( fgets(nptr, 16, stdin) != nullptr )
{
if ( nptr[0] == 10 )
{
puts("Critical Error");
return 0;
}
else
{
v10 = atoi(nptr);
printf("Inspecting %d bytes from Flux Memory:\n", v10);
sub_121D((__int64)dest, v10);
puts("\nEnter the 64-bit Flux Hash to initiate Time Travel:");
if ( fgets(v4, 32, stdin) != nullptr )
{
if ( v4[0] == 10 )
{
puts("Critical Error");
return 0;
}
else
{
v9 = __isoc23_strtoull(v4, 0, 10);
v8 = sub_12DD(dest + 190);
if ( v9 == v8 && v9 != 0 )
{
puts("\n1.21 GIGAWATTS ACHIEVED!");
puts("Temporal Displacement Initialized! Great Scott!");
for ( j = 0; byte_2060[j] != 0; ++j )
{
v7 = v9 >> (8 * ((unsigned __int8)j & 7u));
putchar(v7 ^ byte_2060[j]);
}
putchar(10);
}
else
{
puts("\nTemporal Hash Mismatch! You are stuck in 1955!");
}
free(dest);
return 0;
}
}
else
{
return 1;
}
}
}
else
{
return 1;
}
}
}
// 1060: using guessed type __int64 __fastcall __isoc23_strtoull(_QWORD, _QWORD, _QWORD);
// 2030: using guessed type _BYTE byte_2030[48];
// 2060: using guessed type _BYTE byte_2060[56];
//----- (00000000000016B8) ----------------------------------------------------
void term_proc()
{
;
}
// nfuncs=42 queued=12 decompiled=12 lumina nreq=0 worse=0 better=0
// ALL OK, 12 function(s) have been successfully decompiledSetelah kita baca function mainnya, dapat kita simpulkan kalau byte_2060 itu isinya adalah flag asli.
else
{
v9 = __isoc23_strtoull(v4, 0, 10);
v8 = sub_12DD(dest + 190);
if ( v9 == v8 && v9 != 0 )
{
puts("\n1.21 GIGAWATTS ACHIEVED!");
puts("Temporal Displacement Initialized! Great Scott!");
for ( j = 0; byte_2060[j] != 0; ++j )
{
v7 = v9 >> (8 * ((unsigned __int8)j & 7u));
putchar(v7 ^ byte_2060[j]);
}
putchar(10);
}
Nah, di sini itu merupakan target string kita. Jadi kita harus tau apa hasil dari ini agar kita bisa mendapatkan hash untuk mendapatkan flagnya. Jadi dia mengambil byte_2030 sebagai value yang nanti akan di XOR yang nanti hasilnya adalah ciphertext asli.
for ( i = 0; byte_2030[i] != 0; ++i )
dest[i + 190] = byte_2030[i] ^ 0x6A;

Di sini si AI sudah membuatkan script biar aku gak usah repot repot ngerakit script sendiri. Tapi output si AI ini salah. Seharusnya outputnya adalah p3ng3n_PunY4_d3l0r34n_1985
>>> byte_2030 = [
... 26, 89, 4, 13, 89, 4, 53, 58, 31, 4, 51, 94, 53, 14, 89, 6,
... 90, 24, 89, 94, 4, 53, 91, 83, 82, 95, 0, 0, 0, 0, 0, 0,
... 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
... ]
...
... target_string = ''.join(chr(x ^ 0x6A) for x in byte_2030 if x != 0)
... print(target_string)
...
p3ng3n_PunY4_d3l0r34n_1985
Sekarang kita lihat kembali isi dari snippet biar masuk ke win.
else
{
v9 = __isoc23_strtoull(v4, 0, 10);
v8 = sub_12DD(dest + 190);
if ( v9 == v8 && v9 != 0 )
{
puts("\n1.21 GIGAWATTS ACHIEVED!");
puts("Temporal Displacement Initialized! Great Scott!");
for ( j = 0; byte_2060[j] != 0; ++j )
{
v7 = v9 >> (8 * ((unsigned __int8)j & 7u));
putchar(v7 ^ byte_2060[j]);
}
putchar(10);
}
Bisa dilihat kalau ada sub_12DD untuk compute si hashnya ini. Isi function tersebut adalah
//----- (00000000000012DD) ----------------------------------------------------
unsigned __int64 __fastcall sub_12DD(_BYTE *a1)
{
_BYTE *v1; // rax
__int64 i; // [rsp+18h] [rbp-10h]
unsigned __int64 v5; // [rsp+20h] [rbp-8h]
v5 = 5381;
for ( i = 0; ; ++i )
{
v1 = a1++;
if ( *v1 == 0 )
break;
v5 = (0x9E3779B97F4A7C15LL * i) ^ ((33 * v5 + (unsigned __int8)*v1) >> 13) ^ (33 * v5 + (unsigned __int8)*v1);
}
return v5;
}
Jadi tinggal ngereverse function hash ini dengan target string yang benar tadi. Aku pakai script yang dibuat sama AI tapi scriptnya dia itu salah dari key dan caranya. Karena outputnya itu melebihi 64 bits, kata si AI the Python implementation has a problem with the arithmetic.

~/ctf/beectf/rev/fluxcapacitor
❯ cat hash.py 10:33:48
def compute_hash(s):
v5 = 5381
MASK = (1 << 64) - 1 # 64-bit mask
for i, ch in enumerate(s):
# All operations need to be 64-bit
term1 = (0x9E3779B97F4A7C15 * i) & MASK
term2 = (33 * v5 + ord(ch)) & MASK
v5 = term1 ^ ((term2 >> 13) & MASK) ^ term2
v5 &= MASK # Keep it 64-bit
return v5
target = "p3ng3n_PunY4_d3l0r34n_1985"
hash_value = compute_hash(target)
print(hash_value)~/ctf/beectf/rev/fluxcapacitor
❯ python3 hash.py 10:34:02
7150136296559265265Aku mengambil inspirasi snippet solver AI deepseek yang sudah jadi sama dia.
Karena kita sudah tau target key dan hashnya, kita bisa run terus masukkin valuenya.
~/ctf/beectf/rev/fluxcapacitor 42s
❯ ./chall 10:11:29
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
[][] [][]
[][] FLUX CAPACITOR TEMPORAL CALIBRATION SYSTEM v1.21 [][]
[][] [][]
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
Enter your calibration note:
p3ng3n_PunY4_d3l0r34n_1985
How many bytes of memory state do you want to inspect?
64
Inspecting 64 bytes from Flux Memory:
112, 51, 110, 103, 51, 110, 95, 80, 117, 110, 89, 52, 95, 100, 51, 108, 48, 114, 51, 52, 110, 95, 49, 57, 56, 53, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Enter the 64-bit Flux Hash to initiate Time Travel:
7150136296559265265
1.21 GIGAWATTS ACHIEVED!
Temporal Displacement Initialized! Great Scott!
BeeCTF{flUx_cApAc1t0r_d3crYpt3d_sUcc3ss_djb21s34sy}Sebenarnya di sini aku ada 2 cara untuk ngesolve. Karena si AI ini tiba tiba ngasih solver lengkap AI ini sekalian ngeextract flagnya juga. Seperti ini:
#!/usr/bin/env python3
byte_2030 = [
26, 89, 4, 13, 89, 4, 53, 58, 31, 4, 51, 94, 53, 14, 89, 6,
90, 24, 89, 94, 4, 53, 91, 83, 82, 95, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
]
byte_2060 = [
-77, -96, 111, 103, 64, 37, 65, 5,
-99, -112, 114, 123, 119, 34, 74, 34,
-110, -12, 126, 20, 102, 60, 94, 80,
-110, -73, 83, 84, 96, 80, 94, 60,
-126, -112, 105, 71, 39, 16, 73, 60,
-107, -81, 104, 22, 37, 16, 9, 87,
-126, -68, 119, 0, 0, 0, 0, 0
]
def compute_hash(s):
v5 = 5381
MASK = (1 << 64) - 1 # 64-bit mask
for i, ch in enumerate(s):
# All operations need to be 64-bit
term1 = (0x9E3779B97F4A7C15 * i) & MASK
term2 = (33 * v5 + ord(ch)) & MASK
v5 = term1 ^ ((term2 >> 13) & MASK) ^ term2
v5 &= MASK # Keep it 64-bit
return v5
# Get the target string
target = ''.join(chr(x ^ 0x6A) for x in byte_2030 if x != 0)
print(f"Target string: {target}")
# Compute the hash
hash_val = compute_hash(target)
print(f"Hash value: {hash_val} (0x{hash_val:016x})")
# Decrypt the flag
flag = ""
for i, val in enumerate(byte_2060):
if val == 0:
break
if val < 0:
val += 256
v7 = (hash_val >> (8 * (i & 7))) & 0xFF
flag += chr(v7 ^ val)
print(f"Flag: {flag}")output:
~/ctf/beectf/rev/fluxcapacitor
❯ python3 solve.py 10:34:07
Target string: p3ng3n_PunY4_d3l0r34n_1985
Hash value: 7150136296559265265 (0x633a6314240ac5f1)
Flag: BeeCTF{flUx_cApAc1t0r_d3crYpt3d_sUcc3ss_djb21s34sy}

