👨‍💻
f3dai blog
  • 🧑about
  • Articles
    • ✨Artificial Intelligence
      • Using Gemini to query MITRE ATT&CK
      • Mapping AI safety regulation
      • Poisoning Models
      • Threat modelling generative AI
      • o1 coding capabilities
      • Multi-agent adversarial AI systems
      • Deep reinforcement learning for red teaming
    • ⚙️ICS / OT
      • Consequence-driven Cyber-informed Engineering (CCE)
      • Energy plant cyber simulation
      • OT threat landscape
    • ☁️Cyber engineering
      • Building a cyber lab
        • 1️⃣Design
        • 2️⃣Deploy
        • 3️⃣Test
        • 4️⃣Automating
      • Threat modelling
      • Automating incident response
    • 🚩Capture The Flag
      • Hackthebox - Golfer - Reversing
      • Hackthebox - Behind the Scenes - Reversing
      • Hackthebox - Bypass - Reversing
      • Harder - TryHackMe Walkthrough
    • 🎓Career
      • Domains and roles
Powered by GitBook
On this page
  • File Analysis
  • Decompile - Ghidra

Was this helpful?

  1. Articles
  2. Capture The Flag

Hackthebox - Behind the Scenes - Reversing

File Analysis

fedai@ubuntu:~/hackthebox/Behind the Scenes/rev_behindthescenes$ file behindthescenes 
behindthescenes: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=e60ae4c886619b869178148afd12d0a5428bfe18, for GNU/Linux 3.2.0, not stripped

It’s an ELF file, so we can try and run it:

fedai@ubuntu:~/hackthebox/Behind the Scenes/rev_behindthescenes$ ./behindthescenes 
./challenge <password>
fedai@ubuntu:~/hackthebox/Behind the Scenes/rev_behindthescenes$ ./behindthescenes meow
fedai@ubuntu:~/hackthebox/Behind the Scenes/rev_behindthescenes$ 

It’s expecting an argument, but nothing interesting happens. Let’s run strings to see if there is anything interesting:

fedai@ubuntu:~/hackthebox/Behind the Scenes/rev_behindthescenes$ strings behindthescenes 
/lib64/ld-linux-x86-64.so.2
libc.so.6
strncmp
puts
__stack_chk_fail
printf
strlen
sigemptyset
memset
sigaction
__cxa_finalize
__libc_start_main
GLIBC_2.4
GLIBC_2.2.5
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
u+UH
[]A\A]A^A_
./challenge <password>
> HTB{\%s}
:*3$"
GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
completed.8060
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
main.c
__FRAME_END__
__init_array_end
_DYNAMIC
__init_array_start
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
strncmp@@GLIBC_2.2.5
_ITM_deregisterTMCloneTable
puts@@GLIBC_2.2.5
sigaction@@GLIBC_2.2.5
_edata
strlen@@GLIBC_2.2.5
__stack_chk_fail@@GLIBC_2.4
printf@@GLIBC_2.2.5
memset@@GLIBC_2.2.5
__libc_start_main@@GLIBC_2.2.5
__data_start
segill_sigaction
sigemptyset@@GLIBC_2.2.5
__gmon_start__
__dso_handle
_IO_stdin_used
__libc_csu_init
__bss_start
main
__TMC_END__
_ITM_registerTMCloneTable
__cxa_finalize@@GLIBC_2.2.5
.symtab
.strtab
.shstrtab
.interp
.note.gnu.property
.note.gnu.build-id
.note.ABI-tag
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.plt.sec
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.dynamic
.data
.bss
.comment
fedai@ubuntu:~/hackthebox/Behind the Scenes/rev_behindthescenes$ 

These 2 lines are interesting:

./challenge <password>
> HTB{%s}

It should print the flag through the variable / format specifier “%s”. There are also various other printf functions that also send formatted output to stdout.

Let’s try ltrace which intercepts and records the dynamic library calls which are called by the executed process and the signals which are received by that process.

fedai@ubuntu:~/hackthebox/Behind the Scenes/rev_behindthescenes$ ltrace ./behindthescenes meow
--- SIGILL (Illegal instruction) ---
--- SIGILL (Illegal instruction) ---
--- SIGILL (Illegal instruction) ---
+++ exited (status 0) +++

Nothing interesting happens. Let’s take a look at strace now which lets you observe a given process in detail, printing its system calls as they occur.

fedai@ubuntu:~/hackthebox/Behind the Scenes/rev_behindthescenes$ strace ./behindthescenes meow
execve("./behindthescenes", ["./behindthescenes", "meow"], 0x7ffe27cdaba8 /* 51 vars */) = 0
brk(NULL)                               = 0x560176faf000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffe8a9ae9e0) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=68515, ...}) = 0
mmap(NULL, 68515, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ffa988d9000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300A\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\30x\346\264ur\f|Q\226\236i\253-'o"..., 68, 880) = 68
fstat(3, {st_mode=S_IFREG|0755, st_size=2029592, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffa988d7000
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\30x\346\264ur\f|Q\226\236i\253-'o"..., 68, 880) = 68
mmap(NULL, 2037344, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ffa986e5000
mmap(0x7ffa98707000, 1540096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7ffa98707000
mmap(0x7ffa9887f000, 319488, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19a000) = 0x7ffa9887f000
mmap(0x7ffa988cd000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7ffa988cd000
mmap(0x7ffa988d3000, 13920, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ffa988d3000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7ffa988d8540) = 0
mprotect(0x7ffa988cd000, 16384, PROT_READ) = 0
mprotect(0x5601768c6000, 4096, PROT_READ) = 0
mprotect(0x7ffa98917000, 4096, PROT_READ) = 0
munmap(0x7ffa988d9000, 68515)           = 0
rt_sigaction(SIGILL, {sa_handler=0x5601768c4229, sa_mask=[], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7ffa98728090}, NULL, 8) = 0
--- SIGILL {si_signo=SIGILL, si_code=ILL_ILLOPN, si_addr=0x5601768c42e6} ---
rt_sigreturn({mask=[]})                 = 0
--- SIGILL {si_signo=SIGILL, si_code=ILL_ILLOPN, si_addr=0x5601768c430b} ---
rt_sigreturn({mask=[]})                 = 0
--- SIGILL {si_signo=SIGILL, si_code=ILL_ILLOPN, si_addr=0x5601768c4432} ---
rt_sigreturn({mask=[]})                 = 4
exit_group(0)                           = ?
+++ exited with 0 +++

Can’t see anything interesting.

Decompile - Ghidra

Time for Ghidra! I want to have a look at the decompiled code to understand what it’s doing.

I firstly look at main.

Line 16 on the decompiled code is just an infinite loop:

invalidInstructionException();

Looking at this function takes us to this assembly code:

It just says UD2. No idea what this is but looking it up explains that it’s some kind of error / invalid opcode - “This instruction is provided for software testing to explicitly generate an invalid opcode.”

More research I found this article:

The submitted issue explains that ghidra “doesn’t go further than this instruction”, unlike objdump or gdb (other decompilers). This is true as we can see loads of uncompiled assembly code. Simply select this, right click, and decompile.

We can then see various strncmp operations which is used to compare at most the first n characters of two strings.

There are multiple strncmp operations, each one spells out a different section of the flag.

Itz_0nLy_UD2
PreviousHackthebox - Golfer - ReversingNextHackthebox - Bypass - Reversing

Last updated 1 year ago

Was this helpful?

ud2

strcmp
🚩
https://github.com/NationalSecurityAgency/ghidra/issues/4113