HTB: Safe

Target Experience:

My observations while working this target:

· Enumeration: CTF-like

· Vulnerabilities: CTF-like

· Exploitation: CTF-like/ Life-like

· Difficulty: Medium/Hard

· Community Notes: CTF-like


The recommended tools for this lab were:

· Nmap

· Browser

· Python

· gdb w/peda

· gdb server

· radar2

· ROPgadget

· pwntools

· keepass2john

· Hashcat or John

· KeePassXc


The following vulnerabilities were found:

· Buffer Overflow

Information Gathering:

First things first, I used Nmap to perform a scan for service version detection, OS detection, script scanning, and traceroute.

Nmap Scan

After identifying TCP Port 80 as being open, I used Nikto for a base scan of the web site.

Nikto Scan

Web Enumeration:

With the initial scans completed, I decided to open a web browser to further investigate the web site. Nothing interesting other than a default Apach2 page.

After some review of the /manual directory, I returned to the default Apache2 to review the source. To my surprise, I found a comment about TCP Port 1337 and a hidden binary that could be downloaded.

Page Source
Binary Download

Note: I ran another Nmap scan with the following flags and discovered the TCP port (-sn -sSVC -p-).

Buffer Overflow:

Testing for Buffer Overflow:

This was the toughest part of the entire challenge for me. I have had very little knowledge with registers and how things work. I had to watch many…many…many videos and read lots…lots…lots of articles to get the basics; which I barely comprehend.

So, I am going to go at this from a no nothing point of view. For those that a wiz’s, please don’t laugh, much.

After downloading the myapp, I launched the binary to see what it did.


Next, I decided to use Python to create 200 A’s and used those to create a buffer overflow.

Python with Print

With the A’s generated, I relaunched myapp and input the 200 A’s.

myapp with a Buffer Overflow

Obtaining the Offset:

I decided to launch gdb with the peda extension pack. Before continuing any further insvestigation, I needed to understand the security implemented on the binary. So, I issued the checksec command within gdb.

gdb: checksec

With NX (no execute) bit enabled, this makes this portion of the memory read-only. The processor will refuse to run code within this memory area; which helps prevent certain types of malicious code from running.

With regards to RELRO, data sections are reordered so that they can come after the ELF internal data sections; thus, making exploitation possible.

Knowing my options, I would have to use a ROP chain to be able bypass the NX and inject a shell into the buffer overflow.

Obtaining the Offset:

Continuing with gdb, I added the set follow-fork-mode parent so that the debugger would continue to debug the parent process if a fork occurred within the binary.


I then issued the r command to run the binary and then I entered in the 200 A’s to overflow the buffer.

Buffer Overflow

Reviewing the buffer overflow, I could see the 200 A’s within the stack. In addition, I could see that the RSP register had the A’s repeated 80 times when the overflow occurred.

Doing a quick calculation of the comment for RSP, the offset should be 120. However, I wanted to get an accurate calculation by displaying the 64bit memory address of the RSP register.

To do that, I needed a cyclic pattern to rerun the binary and overflow it with that pattern.

Cyclic Pattern

Using the newly created cyclic pattern, I ran the binary and then entered the pattern after the question.

Buffer Overflow: Cyclic

Note: when entering the cyclic pattern after the questions, do not include the single quotes. If they are included, the offset may not calculate correctly.

At this point, I needed the memory address for the RSP register. So, I issued the x/xg $rsp command to retrieve the memory location.

RSP Memory

With that memory address, I then used the pattern offset with the memory location found for the RSP register to obtain the required offset to be used.

Pattern Offset

Next, I needed help to understand what was going on. So, I separated the contents returned from the segmentation fault.

Binary Execution and Fault

Reviewing the registers, it was worth noting that the cyclic entry could be viewed in the RSP register; which was the current stack pointer during the crash.

Binary: Registers
Binary: Code

Reviewing the stack, RSP being the current pointer, the cyclic entry was within the memory addresses. In addition, the fault happened within the main function.

Binary: Stack and Stopped Reason

Code Review:

Next, I wanted to review the binary code to gather more information. So, I launched radare2 with the aaaa command, followed by the afl command to analyse the flags, files, and directories.

Analyze Binary Functions

Reviewing the main function, I determined that the lea rdi, qword was utilizing /usr/bin/uptime (to display the uptime and connection to the console) and then made a call to system. Another lea rdi, qword was utilized to as the question (\nWhat do you want me to echo back? “), followed by a mov eax, 0 and the a call to printf.

Main Function

At first, reviewing the test function was not all that exciting to me. It added data to the stack, preformed a few register moves and then jumped to register 13. However, reviewing the top half of the main function, there were similar routines that were occurring. So, maybe I could use the test function as a gadget as part of the buffer overflow to inject a /bin/sh command?

Test Function

To get a complete view of the test function, I returned to gdb and issued the disassemble command. I then took note of the nop, pop, and ret commands.

Test Function: gdb

ROP Chain:

In order to determine if I could use the test function as a ROP gadget, I needed to use ROPgadget to review the binary for listed mov, pop, and ret entries.


Reviewing the results of ROPgadget, it would appear that I could use the pop, pop, pop, ret for registers 13, 14, and 15. However, I did not have any data to place into registers 14 and 15.

After a little research and a few discussions, I learned that I could use a null string to enter data into those registers. So, I gathered the following information:

ROP Chain Entry

This left the need to find an entry for register 13. Since the goal was to execute /bin/sh, I would need the system function for the register. So, I returned to radar2 and issued the pdf @ sym.imp.system command to review the memory. An alternative method in with gdb was to issue the info functions command. But, that has more information than required. Another alternative was to use objdump -D myapp | grep system.

radar2: system
ROP Chain Entry

RBP Offset:

At this point, I tried to build and test my exploit script, but a segmentation fault was still occurring. After inspecting the main function, a little closer, I noticed that rsp had a sub instruction of 0x70. So, this needed to be calculated as part of the offset.

main Disassembled

Reviewing the registers again in gdb, I found the entries within the RBP and RSP registers.


Next, I issued the command to display the 64bit memory address of the RSP register. With that memory address, I then used the pattern offset with the string found within the RBP register to obtain the required offset to be used.

Calculated Offset
ROP Chain Entry

Final Local Exploit:

Since I had a local copy of the binary, I decided to build my exploit to test against it. So, I gathered all of the data needed to build the exploit.

Final Exploit Data

After some testing and tweaking, I came up with my final code.

Final Local Exploit
Local Connectivity

Final Remote Exploit:

With the local exploit complete, I modified it and connected to the remote target.

Final Remote Exploit
Remote Connectivity

User Flag:

With connectivity established, I was able to locate the user flag within the /home/user directory.


Root Flag:

I tried the standard methods to exfiltrating the KeePass file found within the /home/user directory, but nothing was working. So, I converted the file to Base64 and then copied the text to my attacker system.

Base64 Encode

On my attacker system, I then converted the Base64 file back to the original .kdbx file.

Base64 Decode

I was looking to do the same procedure for the found JPG files. However, once encoded, it took a little bit of effort to copy all of the contents to my attacker system.

So, I decided to create a public and private key to enable the ability to scp files to my system without the user’s password. With that, I used ssh-keygen to create the keys in a file other than /root/etc/ssh.

With the keys created, I copied the contents of the file and then pasted it to the target user’s ~/.ssh/authorized_keys directory.
Target: Authorized_keys

With the keys created and the public key copied to the target, I launched scp with the identity_file flag (for the private key location) followed by the target user and then the JPG files.

SCP w/Identity Flag

After downloading and review the options for keepass2john, I treated each one of the JPG files as a key file for the KeePass database. So, I ran keepass2john against the MyPasswords.kdbx and each one of the JPG files to produce a hash.


With the hashes created, I used my cracking rig to run Hashcat against the hashes. I read an article that the database name needed to be removed from the hash prior to cracking. In addition, I noticed that Hashcat would only crack one hashed entry from the input file.

Cracked Password

Since I already had a copy of KeyPassXC on my OSX system, I used it to open the database and entered the cracked password. I then selected the IMG_0547.JPG file as the Key File.

MyPasswords.kdbx Authentication

Once in the database, the first entry present was Root pass for root.

Root Credentials

Next, I used ssh to try to connect with root. However, I was not able to establish the connection. So, I used ssh with the identity_file flag to connect to the target as the user. I then issued a switch to root and logged in with the credentials from the KeePass database.

SSH w/Identity Flag

All that was left was to find the Root Flag.




This article is made available for educational purposes only!!! In addition, this article provides general information on cyber security topics used for “Ethical Hacking”.

Persons accessing this information assume full responsibility for the use and agree to not use this content for any illegal purpose. Furthermore, the author is not liable for any direct or indirect damages or expense incurred which may result from the use of the information covered within this article.

Information within this article is “as is”, without warranty of any sort.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store