HTB CTF Writeup (Power Greed) – Exploitation – Part 1

Introduction

It is no small secret that reverse engineering is an important tool in an exploiter’s kit.
You can’t simply craft shellcode out of thin air, you must understand the binary and its actions before you find that one vulnerability.

In this article, we will explore the exploitation method for breaking HTB’s business CTF 2025’s Power Greed challenge. We will discuss memory management issues and a few mitigation techniques.

In the cybersecurity industry, CTFs are a format of competition (Capture the Flag).  They are a way for cybersecurity experts, penetration testers and hackers to test their skills by completing a series of challenges.

This challenge’s category is “PWN” which refers to RE & binary exploitation. You need to understand x64 assembly for full comprehensibility though we will attempt not to dig too deep into it.

The challenge is completed when the contestant attains a “flag” which is usually a text that when submitted to the CTF’s management page – awards you with points.

Tools used

  1. IDA
  2. Linux’s “file” command
  3. Python – The pwntools library
  4. GDB

Research

We start by downloading the challenge's ZIP directory and notice that it contains a single file: 
challenge/power_greed 
 
Executing the command file ./power_greed Output of the "file" linux command on the binary

So we have a 64bit ELF (Software for Linux/Unix systems). We also notice that the file is “not stripped“. This means that we have debug symbols which would heavily assist us in understanding the logic of the software. We boot up IDA (Reverse engineering and memory analysis tool, often used for Forensics & Incident Response) and load the binary.

The “main” function

The main function's assembly graph

This shows a few functions (diagnostics, panel, log_console, info). We first notice that there’s a check for the number of arguments the software has. If the number isn’t 0, the software leaves immediately.  This is great, it means that the remote server executing this software isn’t running it with arguments which may complex our understanding of the binary. It increases complexity when arguments affect the flow of the program. In our case – no arguments means less complexity.

The “panel” function

IDA graph of panel, but without renames

The function starts with pushing a weird string to the stack “\x1B[1;33m”. We recognize this as a way to add colors to a linux shell, specifically, the color “yellow”. 
We rename the pointer to make it easier for us to reverse the binary. We also apply this to other “color-strings” we find in the binary. 

IDA graph of the Panel function

This function seems to be a simple printf with static values. A printf with static values and no user input doesn’t put the program at risk of exposing any pointers.

The panel used in the challenge

So we move on to the next one. 

The “info” function

The function receives a string as a parameter, and prints it with an “INFO” prefix. It is referenced 3 times in our software. The main function uses this to print “Goodbye” incase you choose to enter the number “3” in the panel.

printing out Goodbye before the program exists

 

The “log_console” function

This function once again contains static prints with colors.

IDA graph of log_console

The output looks like this:

log_console output

Doesn’t look like we’ll have anything useful here.
Or maybe… there is?
It is talking about detecting a buffer overflow that was triggered with an attempt to execute /bin/sh
Then the classic segmentation fault (program termination after detection of issues with memory)

Did you recognize it? The most important part here is that we have a “/bin/sh” substring. Not only that, but its also null terminated! If we actually have a buffer overflow here, we already have one pointer fixed for us for a later function call to execve (More in this in part2)

The “diagnostics” function 

IDA graph of the diagnostics function

Once again we have colored prints, followed by input for either:

  1. Vulnerability Scan
  2. Firmware update
  3. Change grids

We immediately target the firmware update, but that’s just a printout of 
“Firmware update is available, contact the administrator to perform this action.” Firmware update is "available" it seems

 Static text, no additional logic.  We move on to “Change grids“, which is another static printout of text. This time; however, we have some pointers and their relative values. 

change grids leaks some pointers and data

Okay, this could be used to do some address computations and give us an offset we can work with. We’ll get back to that later. 

Finally, we move on to…

The “vuln_scan” function

Starts off with a progress bar for a random duration (imitates an actual scan, but doesn’t interact with a even a single block of memory) 

Fake progress bar loads

 

At the end of the scan it prints out some security information about the process. Looks like quite a few anti-exploitation techniques have been implemented in this binary. This is once again a static printout, probably to assist the exploiters in the CTF. Since this is a static printout, lets confirm with an actual checksec:

checksec output 

Stack canaries seem to exist, but our reverse engineering showed nothing on the main module (0x4000000), we can ignore this if we use functions from this module for our exploit.

SHSTK: Enabled – Shadowstack is enabled.
This is a tough one. With this enabled, we may not be able to use ROP chaining (the RET command will verify stack pointers against a hardware-maintained stack).
There is some hope though, this requires hardware support, perhaps the server executing our code doesn’t support it yet.

IBT: Enabled – Indirect branching 
This means that we can’t simply CALL or JMP to a random address in memory. It must land on a special CPU command “ENDBR32” or “ENDBR64”. This poses an issue for exploitation, but we don’t really know if we even need a random JMP or CALL

Stripped: No – Well… we know this already, we see symbols as we debug.

Finally, the vuln_scan “finds” a potentially vulnerable Buffer and asks you if you want to test it. 
vuln_scan finds a buffer overflow

Okay, might have done a bit of an overkill with the research and reverse engineering. The challenge looks like an exploitation of a buffer overflow with some mitigations in place.

With that, dear reader, we will end part 1.
Part 2 will be coming soon!

Call Now Button