저번 TIL에서 동작원리만 한글로 조금 적어놨던 기법들을 예시로 만들고 직접 컴파일하고 디버깅하여 분석을 해보았다.
그전에 알아야 할 Return to Shell이라는 간단한 공격기법이 있다.
방법은 어떠한 버퍼에 system("/bin/sh") 같이 해당 운영체제의 권한을 탈취하는 코드의 opcode를 넣고 오버플로우를 통해 Return Address를 다시 해당 버퍼의 주소로 덮는 것이다. 그렇게 되면 해당 함수나 분기가 끝나고 돌아가려는 주소가 버퍼로 가게 되어 opcode가 실행되며 권한을 탈취할 수 있게 된다. 과정을 그림으로 도식화하면 밑의 그림과 같다.
하지만 이런 Return to Shell 공격도 무작정 할 수 있는 것이 아니라 조건이 두 가지 있다.
1. Return 시킬 버퍼의 주소를 아는가?
2. 이를 실행시킬 수 있는 환경인가?
1번의 조건을 만족시키지 못하게 하기 위해 ASLR이라는 보호기법이 생겨났고,
2번의 조건을 만족시키지 못하게 하기 위해 NX라는 기법이 생겨났다.
Address Space Layout Randomization
직역하면 주소공간 난독화이다.
직역을 한 의미처럼 프로그램이 실행될 때마다 스택, 힙, 공유 라이브러리가 할당되는 주소들을 마구마구 바꿔버린다.
이것이 실제로 실행되는지 보기 위해 Dreamhack의 코드에 내가 몇 가지 추가하고 컴파일하여 그 결과를 보았다. 코드는 다음과 같다.
(ref : https://learn.dreamhack.io/85#4)
이런식으로 메모리의 세그먼트에 할당되도록 하는 몇 가지의 주소지를 찍어보니 이런식으로 나왔다.
위에 4개는 실행때마다 바뀌고 밑에 3개는 실행을 해도 바뀌지 않는 것을 볼 수 있는데 여기서 세가지를 알 수 있다고 한다.
코드 세그먼트에 있는 것들은 바뀌지 않는다. (main함수의 주소가 바뀌지 않는 것을 통해 알 수 있음.)
데이터 세그먼트에 있는 것들은 바뀌지 않는다. (전역변수들의 주소도 바뀌지 않음.)
사실 이건 나중에 팩트체크를 더 해봐야한다. 그렇게되면 전역변수에 버퍼를 선언해버린 프로그램에서는 Return to Shell이 통해야하니 교차검증을 더 해봐야하므로 이건 무시해주세요.
여기서는 직접 보이지 않았지만 라이브러리의 시작주소와 특정 함수사이의 거리(차이)는 늘 똑같다. (도서관에 책이 어디에 끼어있든 시작페이지와 특정 내용까지의 페이지 차이는 같듯이)
하지만 보통 버퍼는 스택영역안에 할당될 것이고 실행때마다 그 위치가 바뀌어버리니 Return to Shell 공격의 첫번째 조건을 없애버린다.
No-Executable
직역하면 "응~안해~"이다.
각 메모리 세그먼트에서 필요없는 권한을 빼는 것이라고 한다.
EX) 코드영역에서 쓰기권한 삭제 -> 공격자가 이상한 코드 넣는 것을 방지
EX) 스택영역에서 실행권한 삭제 -> 아까봤던 R2S 방지
어차피 각 영역마다 실행권한만 보면 되므로 정말 아무 코드나 짜고 디버깅을 해보았다.
컴파일은 저런식으로 -z execstack을 추가해서 하면 되고 보호기법에 NX disabled가 있는 것을 보니 성공적으로 해제되었고 해당 프로그램을 디버깅해보면 제일 밑에 스택영역에 여전히 rwxp로 실행권한이 있는 것을 볼 수 있다.
이번엔 위의 조건을 없애 그냥 컴파일하였고 보호기법에 NX Enabled가 있는 것을 확인하고 디버깅해보면 아까와달리 rwxp가 아니라 rw-p가 되면서 실행권한이 빠진 것을 볼 수 있다.
엥? 코드 영역(빨간 글씨)에는 애초에 w가 없는데요?
=> 어.. 나도 모르겠다 애초에 없어야 했을 권한이니 처음부터 없었으면 머 딱히 달라질게 없다.