main() 함수를 보면 welcome() 함수와 login()함수를 차례로 호출한다.
welcome() 함수에서 100byte 배열을 선언하고 최대 100byte 문자열을 입력 받아 배열에 저장, 출력한다.
login() 함수가 중요한데, scanf() 로 passcode1, passcode2를 입력 받고 각각의 key값과 대조해 flag를 출력한다.
그런데 표시한 부분을 보면 scanf() 함수의 전달 인자로 포인터를 전달하지 않고 그냥 변수명을 넣었다.
현재 passcode1과 passcode2는 초기화 되기 전이므로 쓰레기 값이 들어있을 것이고 그 쓰레기 값을 주소로 삼아 해당 지점에 정수를 입력하려 할 것이다.
확인을 해보자. 위와 같이 코드를 작성하고 컴파일 한 뒤(컴파일 경고가 뜨긴한다.) 정수를 입력하면 segmentation fault가 뜬다. 예상대로다.ㅋ gdb로 분석해보자.
main() 함수를 보면 스택에 16byte를 할당하고 welcome() 함수와 login() 함수를 각각 호출한다.
welcome() 함수에서는 스택에 136byte를 할당하고 EBP-112byte 에 있는 name 배열에 EBP-12byte 까지 최대 100byte를 입력받는다.
"A"*100을 name 배열에 입력하고 스택을 보면 0x41이 100번 삽입된 것을 확인할 수 있다. 표시한 부분은 각각 welcome() 함수의 SFP, RET이고, welcome함수가 종료되고 나면 해당 스택 프레임이 소멸되고 login() 함수가 호출되면서 다시 RET, SFP, STACK 순으로 스택 프레임이 생성될 것이다.
login() 함수를 보면 스택에 40byte를 할당하고 scanf() 함수의 두 번째 인자로 EBP-16byte의 값을 전달하는데, 이곳이 passcode1 변수임을 알 수 있다. &를 이용해 포인터로 전달하지 않았기 때문에 passcode1의 초기화되지 않은 쓰레기 값이 바로 인자로 들어갈 것이다.
login() 함수의 스택을 살펴보면 SFP, RET(표시한 부분)이 확인되고 이전에 welcome() 함수를 통해 입력했던 name 배열의 값("0x41"*100)도 보인다.
그런데 EBP-16byte의 위치의 passcode1 변수의 값에 welcome() 함수에서 입력했던 "AAAA(0x41414141)"의 값이 들어있다. name 배열의 마지막 4byte가 passcode1의 위치와 겹친다! 즉, name 배열의 마지막 4byte를 주소로 삼아 scanf() 함수가 호출되며 공격자가 원하는 주소값에 원하는 값을 4byte만큼 입력시킬 수 있다.
따라서 특정 함수의 got를 overwrite해서 system 함수의 코드 주소로 뛰도록 실행흐름을 조작해 조건문을 우회하자.
scanf() 함수가 종료된 직후 호출되는 fflush() 함수의 got는 0x0804A004이다.
system("/bin/cat flag") 코드 영역 주소는 0x080485E3이다. 익스 ㄱㄱ
96byte dummy와 fflush() 함수의 got를 name 배열에 전달하고 마지막 fflush() 함수의 got를 overwrite하자.
flag를 출력해준다.
'Wargame > Pwnable.kr' 카테고리의 다른 글
Pwnable.kr shellshock-1pt (0) | 2017.04.17 |
---|---|
Pwnable.kr lotto-2pt (0) | 2017.04.17 |
Pwnable.kr blackjack-1pt (0) | 2017.04.15 |
Pwnable.kr mistake-1pt (0) | 2017.04.13 |
Pwnable.kr random-1pt (0) | 2017.04.13 |