HTB Cyberapocalypse 2025 - EndlessCycle

Challenge Description
EndlessCycle is a reverse engineering challenge from Cyber Apocalypse CTF 2024. The program appears to trap the user in an endless loop, but actually contains a flag hidden in the binary, encrypted with a XOR operation.
Binary Analysis
By analyzing the binary with a disassembler, we discovered it contains a set of encrypted data. These data are located in the .data
section of the binary and are manipulated by a XOR encryption algorithm.
Here is an excerpt of the assembly code that hand
les these data:
; Récupération de l'adresse des données chiffrées
mov rax, [rel data_address]
; Boucle de déchiffrement XOR
.loop:
mov edx, [rax]
xor edx, 0xbeefcafe ; Clé XOR
mov [rax], edx
add rax, 4
cmp rax, [rel data_end_address]
jb .loop
This code performs a XOR operation on 4-byte blocks. The encrypted memory area actually contains the challenge flag.
Extracting Data from the Binary
To extract the encrypted data from the binary, we created an analysis script:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
unsigned char code[] = {
0x55, 0x48, 0x89, 0xe5, 0x68, 0x3e, 0x21, 0x01, 0x01, 0x81, 0x34, 0x24, 0x01, 0x01, 0x01, 0x01,
0x48, 0xb8, 0x74, 0x68, 0x65, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x50, 0x48, 0xb8, 0x57, 0x68, 0x61,
0x74, 0x20, 0x69, 0x73, 0x20, 0x50, 0x6a, 0x01, 0x58, 0x6a, 0x01, 0x5f, 0x6a, 0x12, 0x5a, 0x48,
0x89, 0xe6, 0x0f, 0x05, 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, 0x49, 0x89, 0xe4, 0x31, 0xc0,
0x31, 0xff, 0x31, 0xd2, 0xb6, 0x01, 0x4c, 0x89, 0xe6, 0x0f, 0x05, 0x48, 0x85, 0xc0, 0x7e, 0x32,
0x6a, 0x1a, 0x58, 0x4c, 0x89, 0xe1, 0x48, 0x01, 0xc8, 0x81, 0x31, 0xfe, 0xca, 0xef, 0xbe, 0x48,
0x83, 0xc1, 0x04, 0x48, 0x39, 0xc1, 0x72, 0xf1, 0x4c, 0x89, 0xe7, 0x48, 0x8d, 0x35, 0x12, 0x00,
0x00, 0x00, 0x48, 0xc7, 0xc1, 0x1a, 0x00, 0x00, 0x00, 0xfc, 0xf3, 0xa6, 0x0f, 0x94, 0xc0, 0x0f,
0xb6, 0xc0, 0xc9, 0xc3, 0xb6, 0x9e, 0xad, 0xc5, 0x92, 0xfa, 0xdf, 0xd5, 0xa1, 0xa8, 0xdc, 0xc7,
0xce, 0xa4, 0x8b, 0xe1, 0x8a, 0xa2, 0xdc, 0xe1, 0x89, 0xfa, 0x9d, 0xd2, 0x9a, 0xb7
};
int codeSize = sizeof(code);
for (int startOffset = 0x80; startOffset < 0x95; startOffset++) {
printf("Offset 0x%02x: ", startOffset);
unsigned char encryptedData[32] = {0};
for (int i = 0; i < 32 && startOffset + i < codeSize; i++) {
encryptedData[i] = code[startOffset + i];
}
for (int i = 0; i < 32; i += 4) {
unsigned int block = 0;
for (int j = 0; j < 4 && i + j < 32; j++) {
block |= ((unsigned int)encryptedData[i + j]) << (j * 8);
}
block ^= 0xbeefcafe;
for (int j = 0; j < 4 && i + j < 32; j++) {
char c = (block >> (j * 8)) & 0xFF;
if (c >= 32 && c <= 126)
printf("%c", c);
else
printf(".");
}
}
printf("\n");
}
return 0;
}
Exploitation
By analyzing the data at different offsets in the binary and applying the XOR operation with the key 0xbeefcafe
, we were able to recover the hidden flag. The exploitation proceeds in several steps:
- Extracting the encrypted data from the binary
- Identifying the exact offset where the encrypted flag is located (around offset 0x8C)
- Applying the XOR operation on 4-byte blocks with the key 0xbeefcafe
- Converting the decrypted values to ASCII characters
Here is a complete script to extract and display the flag:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE *f = fopen("challenge", "rb");
if (!f) {
perror("Impossible d'ouvrir le binaire");
return 1;
}
fseek(f, 0x2000, SEEK_SET);
unsigned char buffer[1024];
size_t bytesRead = fread(buffer, 1, sizeof(buffer), f);
fclose(f);
printf("Lecture de %zu octets depuis le binaire\n", bytesRead);
for (size_t offset = 0; offset < bytesRead - 32; offset += 4) {
printf("Offset 0x%04zx: ", offset);
for (int i = 0; i < 32; i += 4) {
if (offset + i < bytesRead - 4) {
unsigned int block =
(buffer[offset + i]) |
(buffer[offset + i + 1] << 8) |
(buffer[offset + i + 2] << 16) |
(buffer[offset + i + 3] << 24);
block ^= 0xbeefcafe;
for (int j = 0; j < 4; j++) {
char c = (block >> (j * 8)) & 0xFF;
if (c >= 32 && c <= 126)
printf("%c", c);
else
printf(".");
}
}
}
printf("\n");
if (offset > 100) break;
}
return 0;
}
The Flag
By executing our analysis tool, we were able to retrieve the flag:
$ ./extract_flag
...
Offset 0x008c: HTB{l00k_b3y0nd_th3_w0rld}
...
The flag for this challenge is: HTB{l00k_b3y0nd_th3_w0rld}