Story of CowHacker

Pwnable_Passcode 본문

공부/Pwnable

Pwnable_Passcode

Cow_Hacker 2019. 12. 16. 12:00
728x90

포너블 5번 문제를 풀어 볼것이다.

5번 문제 사진이다.

ssh 로 접속 주소가 있었다.

 

 

 

 

ssh 주소로 접속후 파일 확인 사진이다.

ls 해본 결과 플래그 passcode, passxode.c 가 있었다.

 

 

 

 

c파일 확인 사진이다.

passcode.c 파일을 cat으로 보았다.

크게 두개의 함수와 그리고 main 함수가 있었다.

먼저 main 함수를 보면 프린트문을 출력하고 welcome함수로 넘어 갔다.

그리고 나서 login함수로 넘어가고 나서 두번째 프린트 문을 출력했다.

 

welcome함수를 보았다.

char name[100]을 보아 name 이라는 변수에 버퍼 100을 준것이였다.

그리고 scanf로 값을 받아 name에 넣고 프린트 문을 출력할려는 모습이였다.

 

login함수를 보았다.

int passcode1

int passcode2

두개의 passcode변수를 선언하고 passcode1을 입력하라는 프린터문을 출력한후

scanf로 값을 받은뒤 passcode1에 넣으려는 모습이였다.

그리고 쭉쭉 내려와 보니 passcode1 == 338150 && passcode2 == 13371337 이 되면 플래그 값을 얻을수 있게 되어있었다.

 

 

 

 

 

a 값을 넣은 사진이다.

일단 a를 넣어 봤다.

login 함수의 else에 있는 프린트 구문이 출력됬다.

 

 

 

 

 

33850값을 넣은 사진이다.

이번에는 if문을 실행하기 위해 passcode1에 33850을 넣어 봤더니, Segmentation fault ( core dumped ) 가 떳다.

구글링을 해본 결과 저 이유는 바로 scanf를 쓸때 &를 넣지 않고 써서 그렇다는 거였다.

 

 

 

 

 

login 함수의 scanf 확인사진이다.
welcome 함수의 scanf 사진이다.

 

 

 

 

즉 &이놈을 쓰지 않으면 passcode1에 내가 입력한 값을 저장하는것이 아니라 passcode1의 주소에 내가 입력한 값을 저장하게 된다.

 

ex)

passcode1 의 주소가 0x11111111이라고 쳤을때

1. scanf ( " %d " , &passcode1 ); -> 내가 입력한 값을 passcode1에 저장한다.

2. scanf ( " %d " , passcode1 ); -> 내가 입력한 값을 passcode1 의 주소값인 0x11111111에 저장한다.

* 여기서 문제점은 지금 두 개의 변수 passcode1 과 passcode1가 초기화가 되지 않았기 때문에 주소 값에는 더미값이

들어 가 있을것이다. 그런데 지금 값을 저장할려고 하니까 오류가 나는 거다.

 

 

 

 

 

 

login 함수를 disassemble 로 본 사진이다.

첫 번째로 login 함수를 disassemble 해보았다.

0x10(%ebp),%edx가 passcode1의 값을 받는 구간 즉 scanf의 부분인걸 알수 있었다.

 

 

 

 

 

 

welcom을 disassemble 해본 사진이다.

두 번째로 welcome을 disassemble 해보았다.

여기에서는 0x70(%ebp),%edx가 name에 값을 받는 즉, scanf의 부분인걸 알수 있었다.

 

 

 

 

 

main 함수를 disassemble 한 사진이다.

세 번째는 main함수를 disassemble 해보았다.

0x8048609 가 welcome 함수로 가는 거고 0x8048609가 login 함수로 가는 걸 알수 있었다.

 

 

 

 

 

 

 

welcome 구문의 사진이다.

다시 첫번째로 호출 하는 welcome 함수로 가보았다.

name에 100이라는 버퍼를 주고 그값을 입력 받은후 출력하는 저 구문... 저기 까지는 정상적으로 출력이 되고 그다음 login함수에서 if문 즉 입력 받은 값을 비교할때 오류가 나는걸 알수 있었다. 그럼 name을 출력할때 까진 정상 작동한다는 거였다.

 

그럼 또 name의 버퍼를 사용해 login의 영역에 영향을 줄수 있진 않을까 생각했다.

 

 

 

 

 

name의 주소값을 표시한 사진이다.

name의 주소값을 확인했다.

name의 주소값은 0x70이였다. 즉 젤 처음 scanf를 받는 구간이였다.

 

 

 

 

 

 

passcode1의 주소값을 표시한 사진이다.

이번에는 passcode1의 주소값을 확인했다.

passcode1의 주소값은 0x10이였다.

 

젤 처음 scanf를 받는 부분과 그리고 바로 다음 scanf를 받는 그 구간 값을 빼면 name의 버퍼 다음 주소 영역을 알수 있지 않을까 생각했다.

 

 

 

 

 

 

 

break 로 welcome의 +68 즉, welcome의 마지막 부분을 걸어논 상태다.

일단 정상 작동하는 그 부분을 보기위해 welcome의 마지막 프린트 구문까지 break를 걸어 봤다.

 

 

 

 

a를 100 개 넣어본 사진이다.

이제 run을 한뒤,

a를 name의 버퍼 크기 만큼 100개를 넣어 봤다.

 

 

 

 

 

a의 주소값이 들어간 걸 확인하는 사진이다.

a값이 100개 들어 간걸 알수 있엇다.

 

 

 

 

a값을 96개 넣는 사진이다.

이제는 a값을 96개 넣어 봤다.

 

 

 

 

 

a값이 들어간걸 확인하는 사진이다.

x/40wx $esp를 해서 a값이 96개 들어간걸 볼수있다.

 

 

 

 

 

 

여기서 우리는 PLT 와 GOT의 개념에 대해 알아야 한다.

내가 구글링 해본결과로 이 두 개념을 통해서 이문제를 푸는것이 이 문제의 포인트 겠구나 생각했다.

 

PLT : 실제 호출코드를 담고 있는 테이블이다.

GOT : PLT가 참조하는 테이블이다.

 

EX) print 함수를 호출시

1. PLT로 이동

2. GOT 참조

3. 다시 PLT로 이동

4. dl_runtime_rresolve ( print 주소를 PLT가 GOT에 저장하는 과정이다. )

5. 두번째 호출시 PLT가 GOT한테 print어디에 있나 묻고 GOT가 여기 있다라고 준다. 

 

자 이것이 하나의 함수가 호출 될때 이루어지는 과정이다.

쉽게 말하면 저기 scanf 함수가 실행 되는 과정을 설명 해보면

 

1. c파일에서 scanf함수가 코딩 되있으면 일단 scaff함수가 PLT로 이동한다 ( 1번 과정 ) . 그리고 GOT 함수로 그 scanf 함수를 저장하기 위해 PLT가 GOT 를 참조 한다. ( 2번 과정 ) GOT는 저장하는 주소를 다시 PLT한테 알려준다. ( 3번 과정 )  그리고 이제 또다시 PLT는 GOT한테 받은 주소값으로 scanf함수를 저장한다. ( 4번 과정 ) 이제 scanf 함수가 저장된 상태다 scanf 함수가 이제 실행이 될꺼다 ( 내가 값을 입력을 할때 ) 근데 여기서 PLT가 GOT 한테 scnaf함수 어딧냐 할때

GOT가 다른 값을 줘버리면 다른 명령어를 실행 할수 있다. 우린 그걸 이용해 이 문제를 풀것이다.

 

 

 

 

 

a값을 100 개 넣은 사진 ( 왼쪽 ) a값을 96개 넣은 사진을 비교 한 사진이다.

a값을 100개 넣은거 빼기 96개 넣은걸 하면 차이나는 주소값을 알수있다.

정말 그런지 계산기로 확인 해봤다.

 

 

 

 

 

 

 

 

name값의 주소값 사진이다.

name값의 주소값은 -0x70이다.

 

 

 

 

다음 scanf 주소값 사진이다.

다음 login에 있는 scanf가 처음 scanf가 나온후 처음 나오는거라 두번째 scanf값을 확인했다.

여기서 scanf 주소값은 0x10이다.

 

 

 

 

0x70을 그대로 계산기에 붙여넣기한 사진이다.

처음 scanf 값은 112이다.

 

 

 

 

두번째 scanf 값이다.

두번째 scanf값은 10 16이다.

 

 

 

 

첮번째 와 두번째를 빼기한 결과사진이다.

여기서 결과가 96이다 그래서 아까 a값을 100개 넝고 96개 넣고 비교한것이 증명 되었다.

 

 

 

 

fflush가 참조하는 값이다.

이제 위에서 설명한 PLT와 GOT의 과정을 써볼거다.

일단, fflush가 GOT에 참조하는 부분을 찾는다 위 사진을 보면 x/i 0x8048430명령어를 통해 봤다.

0x804a004라고 떳다. 이 값이 바로 GOT로 fflush가 참조하는 값이다.

여기에 이제 우리의 목적이 있는 값인 system호출이 일어나는 값을 넣어줄거다.

 

 

 

 

systemp호출의 주소값이다.

여기서 왜 system호출 주소값을 넣어주냐면 이 코딩은 애초에 &를 쓰지 않은 scanf를 써서 if문을 건너뛰고 바로 system을 실행해 flag값을 얻으려는 것이다.

위에 system호출 값을 확인한다.

 

 

 

 

 

 

 

 

10진수로 주소값을 바꿔준다.

여기서 값을 10진수로 바꿔준다. 이유는 값을 넣을때는 정수를 넣어 줘야하기 때문이다.

 

 

 

 

 

마지막으로 fllush호출 값과 system호출 값을 넣은 사진다. 그리고 flag가 뜬 사진이다.

위에서 구한 두개의 값을 페이로드에 넣어 flag 값을 얻었다.

 

 

728x90

'공부 > Pwnable' 카테고리의 다른 글

Pwnable_input  (0) 2020.08.13
Pwnable_Random  (2) 2020.07.24
Pwnable_Flag  (0) 2019.11.30
Pwnable_Bof  (0) 2019.11.29
Pwnable_collision  (0) 2019.11.24
Comments