Return oriented programming

Return oriented programming 들어보셨나요? 아마 최근 아이폰 SMS DB 해킹기법이 Return oriented programming의 잘된 예라고 했던 듯 합니다. (기사가 기억이 잘..)

일단 이것인가 아시는 분들을 읽을 필요없는 글이고, 이것이 무엇인지 전혀 모르는 분을 위한 초간단 개요를 하나 적을까 합니다.

일단 Return oriented programming을 알려면 return to libc를 아는 것이 필요합니다. return to libc란 해킹 테크닉중의 하나로 library로 리턴하는 방법을 말하며, 상세한 내용은 pharack, smashing the stack for fun and profit이란 글에 자세히 나와 있습니다. 하지만 여기서는 간단하게만 알아보겠습니다.

다음과 같은 잘못된 코드가 있다고 해보죠.

int main(int argc, char** argv) {
  char buf[255];
  strcpy(buf, argv[1]);
}

이 코드가 잘못된 이유는 사용자의 입력을 지나치게 신뢰한나머지 buffer overflow가 가능하다는 점입니다. 그냥 buffer overflow만 되면 모르겠는데, 만약 이 코드를 root사용자의 권한으로 실행할 수 있도록 setuid 가 되어있다고 하면, 공격자 X는 다음과 같이 이 코드를 공격할 수 있습니다.

1. 일단 “/bin/sh”를 실행하는 C코드를 하나 짭니다. (system 함수 호출)
2. 걔를 disassemble합니다. 그럼 16진수 코드가 나오죠.
3. 위 프로그램의 인자로 약간의 패딩(최소한 오버플로우시키고 싶으니까 255글자 이상이겠죠)과 함께 아까 disassemble한 16진수 코드를 넣습니다.
4. 그러면 위 프로그램은 root의 권한으로 돌다가 /bin/sh를 실행.
5. 결국 공격자는 쉘을 따내게 됩니다.

이게 가능한 이유는 buf라는 데이터가 저장되는 주소에서 계속 오버플로우해서 가다 보면 main이라는 함수가 종료되는 스택 반환 주소가 나오기 때문입니다. 다시 말해, 공격자는 이렇게 메모리 레이아웃을 고칩니다.

buf[255] | /bin/sh/ | system 주소

그러면 프로그램은 종료하려고 하다가 system 주소로 RET하는데, 이 때 인자로 /bin/sh를 넘기게 됩니다. (아시다시피 function call의 인자는 스택을 통해 넘깁니다.) 결국 root권한으로 쉘을 내주게 되는 것이죠.

그러나 이것이 최근에는 다양한 방법으로 막히게 되는데, 그 중 하나는 변수의 전달을 어렵게 하는 보호 방법입니다. 앞서 보시면 system에 제가 ‘/bin/sh’를 넘겨야하는데, 이처럼 넘겨주는 변수가 메모리에 써있으면 안되고 레지스터에 들어있어야 하도록 강제하는 것입니다.

두번째는 데이터 영역과 코드 영역을 명확히 구분해버리는 것입니다. 기존에는 메모리를 overflow하면서 쓰고(write), 그 영역이 동시에 실행(execute)될 수 있었습니다만, 이제는 쓸수도 있으면서 실행도 가능한 메모리를 없애버린것입니다.

세번째는 코드 사이닝으로, 못믿을 놈이 넣은 코드는 실행안한다는 것입니다.

그외에도 여러가지 방어 기법이 있습니다. 예를들어 스택의 반환 주소를 랜덤화한다던가, 내가 호출할 system이란 펑션을 아예 라이브러리에서 지워버린다던가, 아니면 system이란 함수의 라이브러리내 위치 주소를 랜덤화한다던가, 스택을 overwrite하게 되면 곧바로 프로그램이 죽어버리게 막아놓는다던가.

Return oriented programming은 공격자가 인자와 함수를 정해서 호출하는 것이 아니라, 그냥 시스템에 존재하는, 이미 코드 사이닝이 된 코드를 호출해버리겠다는 것입니다. 예를들어 가상의 시스템내 라이브러리가 이렇게 이미 생겨있다고 해보겠습니다.

funcA()
….
copy ‘/bin/sh’ to argument. // (1)
RET

funcB()
copy ‘ls’ to argument.
system 호출 // (2)
RET

그럼 공격자는 funcA()와 funcB()를 조합합니다. 그래서 앞에서처럼 직접적으로 system을 호출하지 않고 코드를 1로 점프시킵니다. 그게 반환되어 오겠죠? 이미 copy다음엔 RET가 있으니까. 그러면 곧바로 2를 호출합니다. 이렇게 되면 결국 쉘을 따냅니다.

물론 시스템 라이브러리에서 이렇게 필요한 코드를 찾는다는 것은 고역이 아닐 수 없겠죠. 그래서 연구자들은 아예 라이브러리에서 유용한 code fragment를 뽑아내서 또다시 2차 라이브러리화하고 있습니다.

Similar Posts:

Comments 5

  1. 0000 wrote:

    간단한설명 감사합니다.

    윈도우 리눅스 모두 Remote rop가 가능한가요?

    우선 local에서 주소를 찾은후 참조해서 remote rop exploit를 코딩하는건가요?
    주소가 다 다를텐데..

    Posted 17 Aug 2012 at 3:16 am
  2. Minkoo wrote:

    네 주소가 다 다릅니다. 라이브러리 위치도 요즘엔 일부러 찾기 어렵게하죠. Remote로 될런지는 이부분에 대한 제 공부가 부족해 잘 모르겠네요.

    Posted 22 Aug 2012 at 3:37 am
  3. 0000 wrote:

    Linux 환경에서 ROP를 성공한후
    윈도우에 갑자기 관심이 생겨서 ROP문서를 찾아보고있습니다.
    보호기법은 DEP / aslr 이렇게 2개인데
    제가 생각한 방법이
    aslr이적용되지않은 모듈을 찾은후
    그 모듈안에서 ROP에 공격에 필요한 가젯들을 찾는겁니다!! (이렇게 생각한이유가.. 우선 aslr이 적용되어있지않으니깐 가젯을 찾아도 주소가일정하지않을까아?~해서…)
    그리고 그 찾은 가젯들로 exploit! 해야하는데 ROP에대한 지식이 부족해서 지금 이상태에서 몇일동안 제자리걸음입니다…..ㅜㅜㅜㅜ
    윈도우 ROP꼭 성공하고싶은데 문서를 찾을수가없네요 ( 하나 찾긴 찾았지만 제가 머리가안좋아서 이해하기가 너무어렵습니다.ㅜㅜ)
    좋은 자료있으면 알려주시면감사하겠습니다!

    Posted 13 Sep 2012 at 11:44 pm
  4. mkseo wrote:

    답이 무척 늦었습니다… 죄송합니다. 저도 ROP는 이 이상 아는 내용은 없습니다. 죄송스럽게도요. 대신 http://securityproof.net 같은 보안 커뮤니티를 추천드립니다.

    Posted 09 Oct 2012 at 10:44 pm
  5. pokemon wrote:

    그 모듈안에서 ROP에 공격에 필요한 가젯들을 찾는겁니다!! (이렇게 생각한이유가.. 우선http://allpokemoncardslist.blogspot.com

    Posted 04 Feb 2013 at 8:07 am

Post a Comment

Your email is never published nor shared.