
버퍼 오버플로우를 이용해서 저 Return address를 변조하면 현재 실행되는 함수 다음으로 무슨 함수를 실행할지를 결정할 수 있다.
이때 궁금증 두가지가 생겼다.
1. 매개변수를 받는 함수일경우 어떻게 전달해줄까?
2. 함수를 두 개 이상 실행하고 싶다면 어떻게 해야할까?
1. 매개변수 전달하기
ret 명령어와 스택의 변화를 알아보면서 이해할 수 있었다.
데이터가 이렇게 있다고 가정해보면

함수가 종료될때쯤

rsp는 saved ebp를 가리키고 있을 것이다.
예전에 알아보았던것처럼 함수의 끝부분에는
pop ebp; ret; 이렇게 이루어지는데
이렇게되면 ret 직전에 스택의 모습은

이렇게 되어있다. 만약 return address에 새로운 함수의 시작 주소가 들어있으면 어떻게 될까?
일단 ret 명령에서는는 pop을 한번 수행하기 때문에 ret 직후 스택의 모습은 다음과 같다.

함수의 시작에서는 push ebp; mov ebp esp;로 스택 프레임을 형성하기 때문에 함수의 본격적인 시작에 앞서 스택의 모습은 이렇게 생겼다.

이때 정상적인 경우와 비교해보면, 원래 ebp의 한칸 아래는 return address가 저장되어있고, 2칸 뒤부터 매개변수들이 저장된다. 따라서 원래 data1이 있던곳은 새로운 return address 영역으로 인식하는곳이고, data2 부분은 1번 매개변수로, 그 아랫부분은 2번 매개변수로 ... 이런식으로 이루어지는 것이다.
이를 system("/bin/bash")로 적용시켜본다면

이런식으로 된다. return address 뒤에 한칸을 비우고 필요한 매개변수들을 순서대로 나열해준다고 생각하면 편하다.
2. 함수의 연속 실행은 어떻게할까?
처음에는 단순 나열만 하면 될줄 알았다. Hello World를 출력하고 /bin/bash를 실행한다고 가정해서 스택의 모양이 이렇게 되도록 설계하면 어떻게될까?

nop에서는 아무 작업도 이루어지지 않는다고 가정한다.

stack frame을 해체하기 전의 모습이다. 여기에서 pop ebp; 수행 후 ret 직전에서의 모습은 이럴것이다.

이제 ret가 수행되어야 하는데 아무 작업도 안한다고 했으므로, ret 안에 포함되어있는 pop이 수행되어야한다.
그런데 문제가 있어보인다.

esp의 위치가 다음 실행될 함수와 printf()의 매개변수의 개수만큼 차이가 발생한다.
ret가 실행되기전 esp가 매개변수 개수만큼 내려거나, 혹은 매개변수 개수만큼 pop이 수행되었으면 좋았을 거라는 생각이 든다. 따라서 두 번째로 불러와지는 return address에는

이렇게 pop; ret; 명령어가 적혀있는 주소를 적는것이다.
이렇게되면 총 pop은 2번(이후 esp가 system address를 가리킴), ret는 마지막에 한번 실행되어 결국 두 번째 함수인 system을 가리키게 된다.
이런식으로 스택을 구상하게 되면 3개든 4개든 라이브러리에 있는 함수들을 "원하는대로" 연속으로 실행시킬 수 있다.
역시 이해가 안될때는 "어라? 왜 이렇게 하면 안되는거지?" 이걸 먼저 알아보는게 이해에 매우 큰 도움이 되는것같다.
'정보보안' 카테고리의 다른 글
| [문제해결] HackCTF RTL_World 해결과정 (0) | 2022.01.22 |
|---|---|
| [문제해결] HackCTF yes or no 해결과정 (0) | 2022.01.21 |
| [문제해결] BOF_PIE 해결과정 (0) | 2022.01.18 |
| [문제해결] Offset 해결과정 (0) | 2022.01.18 |
| [정보보안] Simple_Overflow_ver_2 해결과정 (0) | 2022.01.16 |