Load bf
with IDA:
main:
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax@4
int v4; // edx@4
size_t i; // [sp+28h] [bp-40Ch]@1
int v6; // [sp+2Ch] [bp-408h]@1
int v7; // [sp+42Ch] [bp-8h]@1
v7 = *MK_FP(__GS__, 20);
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 1, 0);
p = (int)&tape;
puts("welcome to brainfuck testing system!!");
puts("type some brainfuck instructions except [ ]");
memset(&v6, 0, 1024u);
fgets((char *)&v6, 1024, stdin);
for ( i = 0; i < strlen((const char *)&v6); ++i )
do_brainfuck(*((_BYTE *)&v6 + i));
result = 0;
v4 = *MK_FP(__GS__, 20) ^ v7;
return result;
}
do_brainfuck:
int __cdecl do_brainfuck(char a1)
{
int result; // eax@1
int v2; // ebx@7
result = a1;
switch ( a1 )
{
case '>':
result = p++ + 1;
break;
case '<':
result = p-- - 1;
break;
case '+':
result = p;
++*(_BYTE *)p;
break;
case '-':
result = p;
--*(_BYTE *)p;
break;
case '.':
result = putchar(*(_BYTE *)p);
break;
case ',':
v2 = p;
result = getchar();
*(_BYTE *)v2 = result;
break;
case '[':
result = puts("[ and ] not supported.");
break;
default:
return result;
}
return result;
}
checksec using checksec --file bf
:
RELRO STACK CANARY NX PIE RPATH RUNPATH FORTIFY FORTIFIED FORTIFY-able FILE
Partial RELRO Canary found NX enabled No PIE No RPATH No RUNPATH Yes 0 4 bf
We can move a pointer and write value at that address using ,
, also, we can use .
to read data from it. So we can leak libc
address, we can replace given function with the function in libc
.
Since we cannot change the string "[ and ] not supported."
in .rodata
, so it may be not easy to modify puts
's got table to system
. The function putchar
is not suitable either, because the parameter is a char instead of pointer.
Here I modify putchar
's got table to let it jump to _start
, and let memset
be gets
, fgets
be system
.
➜ ctf python bf.py
[+] Opening connection to pwnable.kr on port 9001: Done
[*] Switching to interactive mode
welcome to brainfuck testing system!!
type some brainfuck instructions except [ ]
$ cat flag
BrainFuck? what a weird language..
$ id
uid=1008(bf) gid=1008(bf) groups=1008(bf)
Just in case you can't get the shell because of *** stack smashing detected ***:
One may also need to overwrite the address of __stack_chk_fail@plt with some other address (ex. the address of the next instruction after it).
If you overwrite the "putchar" with some other address in main, you will likely end up with an untidy stack frame (because you will not let the do_brainfuck() function to perform the return and cleanup {popping stuff out of the stack}).
With this untidy stack, the SSP will not find the correct "CANARY" in the stack and will raise the ABORT signal which causes the process to exit and so no interactive session would stay alive.
Therefore, by also overwriting the address of __stack_chk_fail@plt to something benign, you will get the shell.