Anti-Flag Write-Up | HackTheBox

Matthew OBrien
5 min readDec 18, 2022

--

Let’s get started with the fifth challenge in the HTB reversing track.

Challenge Info:

· Type: Reverse Engineering

· Difficulty: Easy

· Retired: Yes

Initial Checks

We begin by running file on the executable “anti_flag”:

We can see that its a 64 bit ELF that is dynamically linked and stripped. It is in little endian format and has PIE enabled. Next, let’s run checksec:

This tells us that the stack is non-executable and that a stack canary is present, as well as full RELRO being enabled. Check out my first write-up of BabyRE for descriptions of each of these fields. After that, let’s try strings:

Not too much of value here either. Let’s see what we get when we can trying running the program:

Unfortunately, no flag for us. Adding some command line arguments doesn’t help either. Interestingly, running ltrace returns a different message.

Exploitation

Let’s open up the program in Ghidra:

Since it is stripped, it won’t have a main function. But, we can check out the entry function and we what is passed to that. In this case, “FUN_00101486”. Double clicking that will give us the code we want.

The important thing we see here is a call to ptrace. This will allow the program detect if another process like a debugger is monitoring it and attempting to control its execution. If so, it prints “Well done!!” like we saw when we ran ltrace. If not, it says “No flag for you :(“. There is something odd in the assembly though:

The first instruction we see is checking whether or not the value returned by ptrace is -1. If so, it prints the “Well done!!” message and then exits. If not, it jumps to “LAB_00101509” and we can see the call to print “No flag for you :(“ and then exit. But before that, there is a comparison between the 4 byte value at the address calculated by adding the contents of RBP to the value within “local_24” (which has been stored on the stack) and comparing it with the hex value 0x539, which is 1337 in decimal. If they match, it jumps to “LAB_00101525”. That code is essentially unreachable though, as is indicated by the warning on line 2 of the decompiled code. We can make that code viewable by going to Edit->Tool Options->Decompiler->Analysis and unchecking the “Eliminate unreachable code block”.

Now the code looks a bit different:

Now there is a new section which could potentially print out our flag. The problem is that the program will never enter that flow of execution since the conditional is “else if (false)” which will always be false. We can get around this by explicitly jumping to the code we want using pwndbg.

We can’t set up a breakpoint at the address for the function we want because of PIE, but we do have the offset in memory the function is from the PIE base address. We can run “starti” which will have the program break on the first instruction, and then run “piebase” to get the base address:

The offset we need is 1525 since that is where “LAB_00101525” starts:

We can add this to the PIE base. This is the address of the function we want to jump to to get the flag. Now we need a breakpoint so we can jump to it. We can se it up where the program checks if ptrace returned -1:

The offset for that instruction is 14f4. Let’s set up the breakpoint with “breakrva”;

Next we enter “c” to continue. This will put the program at the point where it is about to check whether ptrace returned -1. Because we have a debugger attached, it will and we will never get to the code that prints the flag. So we just have to jump to the address of that code which we’ve already calculated (0x555555555525). So we run “jump *0x555555555525” (the asterisk denotes its an address) and that should print the flag:

Takeaways

There are a lot of takeaways from this challenge. Some are little tricks like adding a few characters or numbers as command line options to see if that affects the behavior of the binary. Others are more substantial, like seeing how ptrace is used to thwart us, or recognizing the unreachable code that would lead to the flag. It was nice to learn how to use pwndbg more as well. All of these are just more tools to add to the toolkit.

Lastly, I would again like to give credit to CryptoCat and his video walk through in helping me solve this challenge. I recommend watching it if you need a more detailed explanation. He also provides a few other ways to solve the challenge by patching the binary using both Ghidra and pwntools. I had to lean a lot on his walk throughs as I am definitely still learning.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Matthew OBrien
Matthew OBrien

Written by Matthew OBrien

My personal site for security research, write-ups, and projects

Responses (1)

Write a response