Return to Shellcode
- Return to Shellcode 란 , 이름 그대로 프레임의 Return address 영역을 Shellcode가 위치한 주소로 변경시켜
프로그램의 흐름을 의도적으로 조작하여 shellcode를 호출하는 방식이다.
Return to Shellcode 이해하기
- Return to Shellcode를 이해하기 위해서는 Assembly Instruction 중 CALL 과 RET에 대한 이해가 요구된다.
CALL Instruction : Return Address ( CALL 명령어 다음으로 실행할 명령어의 위치 ( 주소 ) ) 를 Stack에 저장후 , 피연산자의 주소로 이동
RET Instruction : POP Instruction을 통하여 ESP 레지스터가 가리키는 Stack 영역에 저장된 값을 EIP에 저장후 , 해당 주소로 이동한다.
즉 , Stack 영역에 저장된 Return address 값을 변경할 수 있다면 , 우리는 프로그램의 흐름을 변경할 수 있다.
CALL & RET 명령어 이해하기.
- 다음의 예시와 같은 코드를 통하여 CALL , RET 명령어에 대한 이해를 돕자.
main() 에서 vuln() 을 호출하는 단순 코드이며 , vuln()은 아무 역할도 하지 않는다.
해당 소스를 위의 적어놓은 컴파일 옵션을 통하여 컴파일 후 ,
위와 같이 BreakPoint를 설정한다.
위의 Call Instruction의 흐름은 아래의 사진을 보며 이해해보자.
Call Instruction
Call Instruction의 동작.
- vuln() 함수 호출전 , ESP(RSP) Register가 가리키는 Stack의 위치는 0x7fffffffddb0 이며 ,
해당 영역에 저장되어 있는 값은 0x0000555555554620 이다.
- vuln() 함수 호출 후 , ESP(RSP) Register가 가리키는 Stack의 위치는 0x7fffffffdda8 이며 ,
해당 영역에 저장되어 있는 값은 0x000055555555460f 이다.
- 즉 , CALL 명령어에 의해 Stack에 호출된 함수가 종료된 후에 이동할 주소 (Return address ) 값을 저장함을 확인 할 수 있다.
RET instruction
RET instruction의 동작.
위와 같은 개념을 이용하여 레지스터의 흐름을 살펴보면 RET의 동작의 흐름을 이해할 수 있다.
이제 해당 기법을 이용하여 직접 문제에 적용시켜 보자.
compile option : gcc -z execstack -fno-stack-protector -o test test.c
예제 소스이다.
소스를 분석해보자.
- main함수는 vuln함수를 호출한다.
- vuln함수에는 길이 50의 buf가 있으며 , read 함수를 통하여 buf에 100byte 길이까지 입력을 받는다.
여기 취약점이 존재한다.
buf의 크기는 50byte인데 , 우리가 입력할 수 있는 길이는 100byte로 Stack Overflow가 발생한다.
그럼 이제 Exploit 위해 필요한 정보들을 긁어모으자!
Stack Overflow의 흐름을 정확히 파악하기 위해 다음과 같이 BreakPoint를 설정한다.
vuln+0 : vuln()의 첫번째 명령어
vuln+49 : vuln()내에서 read()함수 호출부분
vuln+56 : vuln()의 ret 명령어
이제 Return address를 확인하여 보자.
위와 같이 gdb를 통하여 Return address를 확인 할 수 있다.
Return address는 함수를 호출 후 돌아갈 주소가 저장되어 있음을 기억하자.
RSP 레지스터가 가지고 있는 stack 최상위 메모리는 0x7fffffffdda8 이며 , 해당 메모리에 vuln() 함수 종료 후
돌아갈 코드영역의 주소값 0x5555555546d1이 저장되어 있다.
Return address의 주소는 구하였으니 이제 취약점을 공략하기 위한 요소인 buf의 시작주소를 구하자.
이번 예제에서는 본문 소스에서 %p , buf 를 통하여 프로그램 구동시 buf의 시작주소를 프린트하도록 설계해놓았다.
이렇게 Exploit을 위한 준비요소는 모두 준비되었다.
Return address : 0x7ffffffffdda8
buffer의 시작 주소 : 0x7ffffffffdd60
이 둘 사이의 위치를 구하여 보면 10진수 값으로 72byte임을 확인할 수 있다.
위 정보의 의미는 , 사용자 입력값으로 문자를 72개 이상 입력하면 , Return address를 덮어쓸 수 있다는 의미이다.
이 정보들을 토대로 Exploit code를 작성한다.
그리고 해당 코드를 실행시키면 쉘을 획득할 수 있다.
'Hacking & Security > Exploit' 카테고리의 다른 글
diff 32bit vs 64bit (0) | 2019.11.20 |
---|---|
Return To Libc ( RTL ) (0) | 2018.12.29 |
Basic of pwnable (0) | 2018.12.27 |
BOF 기초문서 (0) | 2018.11.03 |