SealedRune

Category: Reverse

Difficulty: very easy

Description

Elowen has reached the Ruins of Eldrath, where she finds a sealed rune stone glowing with ancient power. The rune is inscribed with a secret incantation that must be spoken to unlock the next step in her journey to find The Dragon’s Heart.

Required Knowledge

  • C programming

  • Reverse binary file

Solve Walkthrough

1. Basic File Checks

First, I do basic file check using file command.

./challenge: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=47f180529af15b5a7d4601583b2944010ae6e092, for GNU/Linux 4.4.0, not stripped

From the output above, this is a 64-bit dynamically linked ELF binary. Let's see for others binary protections.

[*] '/home/hurtz4eva/Nextcloud/CTF/international/htb-cyber-apocalypse/2025/rev/02_SealedRune/rev_sealedrune/challenge'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        PIE enabled
    Stripped:   No

Same as rev challenge before "EncryptedScroll", the binary mostly have all protections, except Partial RELRO.

2. Analyze the Binary

Let's see the decompiled code inside the binary. I'm using Ghidra for this case.

undefined8 main(void)

{
  long in_FS_OFFSET;
  undefined1 input [56];
  long canary;
  
  canary = *(long *)(in_FS_OFFSET + 0x28);
  anti_debug();
  display_rune();
  puts(&DAT_00102750);
  printf("Enter the incantation to reveal its secret: ");
  __isoc99_scanf(%49s,input);
  check_input(input);
  if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

The logic behind the program is pretty simple:

  • Our input will compare with the secret message. If our input is same with the secret message, then the flag will appears.

  • The secret message can be found inside the decode_secret function. String incantation is stored in the $RDI register. The secret message is encoded with base64 and reversed.

3. Decrypt the Secret Message

The image above is the encoded secret message in hex format (stored in $RDI register). The combination of each hex characters is 65h 6Dh 46h 79h 5Ah 6Dh 5Ah 31h 62h 6Bh 64h 73h 5Ah 57h 46h 57h 00h. If we try to decode all hex characters, the output will be emFyZmZ1bkdsZWFW. Okay, its seems like base64 encoded string, the output of decoded string is zarffunGleaV. We're not done yet, we've to reverse the decoded string, so the final secret message is VaelGnuffraz.

If we input the correct secret message, then we got the flag. Here's my solver script.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from pwn import *
from base64 import b64decode

def solve(encoded_secret_msg) -> bytes:   
    # 1. Decode the hex encoded string.
    hex_decoded = bytes.fromhex(encoded_secret_msg.replace("h", "").replace(" ", "")).decode()
    
    # 2. Decode the base64 encoded string.
    base64_decoded = b64decode(hex_decoded)
    
    # 3. Reverse the decoded string.
    reversed_string = base64_decoded[::-1]
    
    return reversed_string

if __name__ == "__main__":
    encoded_secret_msg = "65h 6Dh 46h 79h 5Ah 6Dh 5Ah 31h 62h 6Bh 64h 73h 5Ah 57h 46h 57h 00h"
    decoded_secret_msg = solve(encoded_secret_msg)
    
    # Input the decoded secret message into the program.
    exe = ELF('./challenge', checksec=0)
    context.binary = exe
    # context.log_level = "DEBUG"
    
    # Start the process
    io = exe.process()
    io.sendline(decoded_secret_msg)
    
    # Print the flag
    search_flag = re.search(r'HTB{.*}', io.recvall(timeout=1).decode())
    flag = search_flag.group(0) if search_flag else None
    print(f"Flag --> {flag}") if flag else print("Flag not found")
    
    io.close()

Flag

HTB{run3_m4g1c_r3v34l3d}

Last updated