[LOB 페도라 FC3] gate -> iron_golem

2014.08.30 04:22

지금까지는 온실속의 화초처럼 redhat 6.2, 9에서 bof를 했다가 한 단계 상위 버전인 fedora core 3에서 bof를 적용해보게 되었다.


일단, bof 방어 기법들이 생겼는데, 검색 해보고 다음과 같이 요약해 보았다.


[환경 요약]

Stack Dummy : O       스택 사이에 더미를 넣음

Down privileage of bash : O   ??? 배쉬의 권한이 다운 됨??

Random Stack : O      랜덤 스택

Random Library : X    공유 라이브러리가 위치한 메모리 주소가 랜덤

Random Program Binary Mapped : X

ASCII Armor : O                공유 라이브러리 주소에서 최상위 바이트가 0x00(ex 0x008962fc)인 메모리 영역을 ASCII Armor라고 함

      그래서, redhat 9에서는 연속적인 함수 호출이 가능하지만 FC에서는 딱 한번만 호출 할 수 있음

Non-Executable Stack : O       스택에 있는 코드실행 불가

Non-Executable Heap : O        힙에 있는 코드 실행 불가

Stack Carany : X               스택 ret 앞에 canary 값이 추가됨

Stack Smashing Protector : X   ???





현재 FC3에 적용된 방어 기법을 정리하면 다음과 같다.

Stack Dummy : O                   스택 사이에 더미를 넣음

Down privileage of bash : O    ??? bash의 권한이 다운 됨??

Random Stack : O                  랜덤 스택

ASCII Armor : O 

Non-Executable Stack : O       스택에 있는 코드실행 불가

Non-Executable Heap : O        힙에 있는 코드 실행 불가




이전 레드햇 버전들과 비교할 때 랜덤 스택과 스택 더미를 제외하면 새로 추가된 것들이 몇개 보인다.

일단, 검색해본 결과 NX-bit 때문에 쉘코드를 직접 올려서 하는 공격은 불가능 할 것 같고, ASCII Armor가 걸려있으면 주소에 0x00이 포함되어 있어서 스택에서 함수 chain을 만들지 못하고 딱 한 번만 함수를 호출 할 수 있다고 한다. (ex "\xfc\x62\x89" <-마지막은 0x00이므로 더 이상 읽어들이지 않음)


아래 사이트를 많이 참고하였는데, 여기서 알려주는 fake ebp 방법(execl() 이용)으로 이번 문제를 풀이해보도록 한다. 

http://blog.naver.com/PostView.nhn?blogId=noish&logNo=100050649974&parentCategoryNo=94&categoryNo=&viewDate=&isShowPopularPosts=false&from=postView




먼저, 목표파일의 소스는 다음과 같다.

int main (int argc, char *argv[])

{

char buffer[256];


if(argc < 2) {

printf("argv error\n");

}


strcpy(buffer, argv[1]);

printf("%s\n", buffer);

}


gdb를 켜서 얼만큼의 공간을 할당하고 있는지 확인해 보자.

위 사진을 보면 10진수로 264바이트를 할당하고 있는데, 이는 8바이트의 dummy가 있음을 예측해 볼 수 있다.


실제 스택의 구조를 보기위해 다음과 같이 strcpy 다음에 브레이크포인트를 걸고 확인해 본다.



(gdb) b *main+86

(gdb) r AAAA




위 사진을 보면 1번은 buffer, 2번은 sfp, 3번은 ret 이다. 

스택 구조를 그려보면 다음과 같다.


low address ... | buffer[256](0x41414141......) | dummy[8] | sfp(0xfeecb568) | ret(0x00730e33) | ...     high address

      

이제 ret위치에 공유 라이브러리의 execl 함수 주소를 써주고 sfp 위치에 execl의 매개변수들이 위치한 주소값을 써주면 된다.

다음 url을 참고하여 alt+f2를 눌러주고 got 주소를 찾아 보았다.

http://bbolmin.tistory.com/33




plt의 주소를 확인 해보면 맨 처음에 jmp 하는 곳이 got의 주소라고 한다. 


그렇다면 해당 주소를 확인해 보도록 한다



여기까지는 잘 되고 있는 것 같다. 한 가지 다른점은 execl의 두번째 인자로 들어가는 부분이 0x0으로 되어있다는 점이다.


execl의 첫 번째 인자는 파일명인데 현재 첫번째 인자가 들어가는 값이 1이므로 파일명이 1인 파일이 있다면 execl이 실행되고 해당 파일을 실행시킬 것이다.







이제 설명대로 shell.c라는 소스를 작성해 setuid와 system("/bin/sh")를 해주고 이 파일에 심볼릭 링크로 파일명이 1인 파일을 생성한다.

나는 아직 기초가 부족한지 이 부분이 좀 햇갈린다 ㅠㅠ



이제 공격 코드는 다음과 같이 작성해본다.


low address ... | buf(256) | dummy(8) | sfp (0x8049610) | ret (0x7a5723) | ... high address


위에서 알아본 got 주소는 0x8049618인데 여기에 -8을 더해준 이유는 스택 구조에서 sfp를 기준으로 매개변수의 위치는 -8에 위치하기 때문이고,

 execl의 주소는 위에 캡처가 안되어있는데 0x7a5720이고, 여기에 +3을 더해준 이유는 함수의 프롤로그를 건너뛰기 위해서라고 한다.

(이런건 도대체 어떻게 생각해내는지.....)



이제 공격 코드를 작성해 본다.

./iron_golem `perl -e 'print "A"x264, "\x10\x96\x04\x08", "\x23\x57\x7a"'`



random libc가 없어서 한 번에 쉘이 떨어지긴 했지만 실패한 것 같다. 


shell.c 소스에서 setuid(501); 부분을 setreuid함수로 변경하여 setreuid(501, 501);로 다시 컴파일 하니 성공!








위와 동일한 공격 방법에서 몇가지 다른 exec* 함수를 이용하여 풀어 보았다.


먼저 got을 보면 위 풀이 방법의 execl 함수의 첫 번째 인자로 들어가는 0x0804954c가 보이고 그 뒤로 0x007194f8, 0x0070e9e0이 있다. 



두 번째 인자로 들어가는 0x007194f8이 가진 값을 보면 0x00이고, 0x0070e9e0 이 가진 값은 0x8b525150이다. 


이 환경에서 execv(const char *path, char *const argv[]); 함수 같은 경우엔 첫 번째 인자와 두번째 인자의 조건을 잘 가지고 있으므로 당연히 공격이 성공하고 쉘이 떨어질 것이다. 


그리고, execve(const char *filename, char *const argv[], char *const envp[]); 함수 같은 경우엔 세 번째 인자의 조건이 맞지 않아서 쉘이 안떨어질 것으로 예상된다. 


execv함수와 execve함수의 주소는 아래와 같다.




마지막으로 결과는 다음과 같다.




다른 write-up을 보니 ret sleding을 사용해서 execve함수로 풀이한 걸 봤는데, execve의 인자에 어떤 값이 들어가야 제대로 동작하는지 이해를 못하겠다...

여러 값을 직접 넣어보며 연구해봤음에도 이해불가... 아시는분은 댓글좀 부탁드립니다 ...

또, 내가 쓴 위 풀이에서 execve의 인자로 사용될 다른 ebp 주소를 적어주면 될것 같지만 아직 execve 함수에 대한 이해가 완벽하지 않아서 다른 풀이는 추후에 찾는걸로...




참고

http://blog.naver.com/PostView.nhn?blogId=noish&logNo=100050649974&parentCategoryNo=94&categoryNo=&viewDate=&isShowPopularPosts=false&from=postView

http://bbolmin.tistory.com/64

http://bbolmin.tistory.com/33

smleenull WARGAME/hackerschool ftz,lob

  1. Sfp 와 ret의 주소가 거긴지 어떻게아나요?

    ----- high
    ret
    -----
    sfp
    -----
    Buf
    ---- low
    이런구조인데 어떻게 바로 저게 ret이랑 sfp인지 정확하게 알수있는건가요?

  2. 바로 안 것은 아니고 사전에 여러 정보(버퍼크기, 스택 더미 유무, canary 값의 유무 등)를 가지고 대충 추측할 수 있구요, 정확한 정보는 gdb로 열어보면 알 수 있습니다.

    위 소스에서 지역변수는 char buffer[256] 하나 뿐입니다.
    그렇다는 것은 main 함수가 실행될 때 먼저 ret, sfp 순으로 스택에 푸쉬되고, 다음으로 지역변수를 위한 공간을 마련하게 되는데 위 디버깅 화면을 보시면 sub $0x108, %esp라고 되어있습니다.

    0x108은 10진수로 264 으로 지역변수의 크기는 256 바이트인데 스택에 264 바이트의 공간을 할당한 것으로 보아 264-256 = 8 바이트의 dummy값이 있음을 알 수 있습니다.

    그러면 머릿속에 스택 구조를 그릴 수 있겠죠

    low... | buffer(256) | dummy(8) | sfp | ret | ...high

    위 스택구조에서 buffer의 시작하는 부분만 알면 그 위치에서 264바이트를 더해주면 그 위치가 sfp가 되겠고, sfp에서 4를 더한 위치가 ret이 되겠습니다.

    저도 첨공부할때 많이 햇갈렷던 부분인데, 함수 호출 규약에 대해 공부하시면 좀 더 많은 정보를 얻으실 수 있을겁니다.

  3. execve함수로 실행시킬때, 세번째 인자가 안된다는 뜻은 세번째 인자가 들어가게 될 영역이 _dl_runtime_resolve 영역이라서 그런건가요?
    그리고 왜 굳이 exec*계열 함수로 페이로드를 짜야 하나요?? system함수로 동일하게 페이로드를 짜봤는데 안되던데.. system함수는 내부에 /bin/sh라는 문자열만 있으면 될텐데 왜 안되고 exec*계열을 써야 하나요..? 간단하게라도 알려주시면 감사하겠습니다..

  4. 감사합니다.

  5. 하... 오랜만에 다시 해봤는데 어렵네요 ㅋㅋㅋ
    자세한 답변은 내일이나 해드릴 수 있을 것 같고,
    일단은 아래 url 참고하시면 간단한 답변은 되실겁니다!
    http://sosal.kr/37
    http://bbolmin.tistory.com/35
    http://sanguine.leaveret.kr/3

  6. Blog Icon
    qwer

    와... 공부 시작한지 얼마 안됬는데 감탄밖에 안나오네요 대체 이런 생각을 어떻게 하는걸까요..

티스토리 툴바