My Study/Exploit2010. 3. 19. 16:05
저도 BOF공부를 하면서 처음으로 만든 쉘코드를 만들어보는 것으로 해보겠습니다. 

execve 함수는 첫번째 인자로 실행시킬 파일 명
두번째 인자로는 전달될 인자입니다. ( argv[0], argv[1] 이라고 생각하면 됩니다. )

뭐 아무것도 없는 소스코드 입니다. 단순히 쉘을 떨치는 프로그램 입니다.
컴파일 하고 실행시켜보겠습니다.

위에 static 옵션을 준 것은 나중에 어셈코드로 볼 것인데 각 함수들이 내부적으로 어떤일을 하는지도 보기위해 옵션을 준 것입니다.

이제 해당 프로그램을 objdump로 봐보겠습니다.

gdb로 하지 않고 objdump를 사용한 이유는 헥사덤프값을 보기 위함 입니다. 쉘코드 만들때 필요하기 때문입니다.
아래쪽을 보니 <__execve>라는 함수를 호출하고 있는 것을 볼 수 있습니다.
<__execve>함수 내부를 보도록 하겠습니다.

<__execve>함수 내부 입니다. 빨간색 네모친 부분만 보시면 될것입니다.

mov 0x8(%ebp),%edi
mov 0xc(%ebp),%ecx
mov 0x10(%ebp),%edx
mov %edi,%ebx
mov $0xb,%eax
int $0x80

인터럽트 0x80을 하고 있습니다. 위에를 보면 eax에 0xb를 넣고 있군요.

인터럽트 0x80은 시스템콜 함수이므로 시스템 콜 값을 지정해 줘야되는데 0xb 시스템 콜을 하고 있네요.
<__execve>함수를 호출합니다.

그리고 위쪽 소스를 보면
ebx에 첫번째 인자
ecx에 두번째 인자
edx에 세번째 인자
를 넣고 있습니다.

첫번째 인자는 "/bin/sh"
두번째 인자는 shell
세번째 인자는 0

이거였습니다.
지금 까진 본 것을 토대로 <__execve>를 호출하는 과정을 어셈블리언어로 나타내보겠습니다.
이것을 소스코드로 인라인 어셈블리 할 것입니다.

push $0x0068732F      //  /sh\0
push $0x6E69622F     //  /bin
mov %esp,%ebx       //  /bin/sh의 주소를 ebx에 넣음
push $0x0               //  shell[1]
push %ebx              //  shell[0]
mov %esp,%ecx       //  shell을 ecx에 넣음
mov $0x0,%edx        //   0을 edx에 넣음
mov $0xb,%eax
int $0x80                //  시스템 콜

위 소스코드를 인라인 어셈으로 짜겠습니다.

__volatile__를 붙힌 이유는 예전에 윈도우에서 쓰레드 동기화 함수 공부하면서 나왔던 키워드 입니다.
그때 정리했던 내용을 잠시 써보겠습니다.

volatile 의미(키워드) - 2가지 기능
C, C++언어의 ANSI표준 키워드
1. 최적화를 수행하지 마라.
예를 들면 
int a = 10;
a = 30;
printf(a);
에서 첫번째 문장은 필요가 없다. 그래서
컴파일러는 보통 
int a = 30;
printf(a);
로 바꿔버림
이런게 최적화지만 최적화가 필요하지 않을 때도 있기 때문에..

int volatile a = 10; 
이렇게 하면 된다.

2. 메모리에 직접 연산하라!
성능 향상을 위해 요새는 캐쉬메모리라는 것을 사용한다.
하지만 캐쉬메모리에 저장이 되면 우리가 원하는 시점에 그것을 사용할 수 없다.
그래서 절대로 그 데이터가 캐쉬메모리에 저장되지 않게하는 기능

여기선 첫번째 기능 때문에 쓴 것입니다. 저희가 썼던 어셈언어가 최적화가 되지 않고 그대로 나오게 하기 위함입니다.
컴파일을 하고 실행을 시키면 쉘이 떨어지는 것을 볼 수 있습니다.

이제 저 소스코드에서 헥사값을 추출하기 위해 objdump로 열어보았습니다.

우리가 썼던 코드가 그대로 있습니다. 부가적으로 붙은 것은 함수 프롤로그 에필로그? 인데 컴파일에서 알아서 붙혀줍니다.
빨간색 네모친 부분의 헥사값을 그대로 가져다 쓸려고 했지만 도중 도중 " 00 " 이라고 되서 널 문자가 보입니다.
코드 실행 중 널 문자가 있으면 끝인줄 알고 멈춰버리기 때문에 " 00 "이라고 된 부분을 전부 없애주어야 합니다.
다시 어셈 코드를 수정 하도록 하겠습니다.

어디가 바뀌었는지 비교해보시길 바랍니다.

위 코드를 다시 컴파일하고 헥사값을 봐보겠습니다.
" 00 " 널은 전부 없앴습니다.
저기서 옆에 있는 헥사값만 빼오면 쉘코드 완성입니다.

쉘코드
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53
\x89\xe1\x89\xc2\xb0\x0b\xcd\x80

한줄로 써주셔도 됩니다.
( 저는 쉘코드를 만드는 것에만 중점을 두고 만들었습니다만.. 최대한 쉘코드는 짧게 만들면 만들수록 좋습니다. 우리가 공격해야할 버퍼의 크기가 작을 경우도 대비를 해야되니 말이죠.. )

쉘코드 만드는 것까지 끝났지만 쉘코드가 정상적으로 작동하는지 알아봐야겠죠??
테스트를 해보겠습니다. 쉘 코드를 실행시키기 위해서는 아래와 같은 소스코드를 만들어서 실험해봐야합니다.

메인 함수가 끝나면서 스택에 있는 리턴 주소를 제가 만든 쉘코드가 있는 곳으로 돌려준 것입니다.
컴파일 시키고 실행시켜보겠습니다.

정상적으로 쉘이 떨어진 것을 볼 수 있습니다.

그리고 쉘코드를 만들 때 도중에 " 00 " 이라는 널이 들어가면 안되지만 또 " ff "도 들어가서는 안됩니다.
이 내용에 대해서는 다음에 올리겠습니다.

'My Study > Exploit' 카테고리의 다른 글

Hackerschool level15  (0) 2010.03.23
Hackerschool level14  (0) 2010.03.22
Hackerschool level13  (0) 2010.03.22
Hackerschool level12  (3) 2010.03.22
shell 코드 만들어 보기  (14) 2010.03.19
BOF의 개념 ( Hackerschool level11 )  (7) 2010.03.19
Posted by sharememory

댓글을 달아 주세요

  1. 비밀댓글입니다

    2010.06.13 03:46 [ ADDR : EDIT/ DEL : REPLY ]
  2. 왕초보

    안녕하세요 ^^;
    블로그 보면서 열심히 공부중인 초보입니다.

    다름이 아니라..
    push $0x0068732F // /sh\0
    push $0x6E69622F // /bin
    이 코드가 어떻게 나오게 되었는지 궁금합니다..
    /bin/sh 문자열을 나타낸건지.. 아니면 절대적인 수치인지..
    눈을 씻고 찾아봐도 이 코드의 출처를 알 수가 없네요.. 검색을 해도 모르겠구요..

    도움을 부탁드립니다.. 감사합니다!!

    2012.11.13 09:35 [ ADDR : EDIT/ DEL : REPLY ]
    • 시스템콜 첫번째 인자를 셋팅하기 위함인데요.
      push $0x0068732F
      push $0x6E69622F
      위 두 명령어를 실행하면 스택에
      "/bin/sh\0" 이 들어가게됩니다.
      저런방법으로 다른 문자열도 스택에 넣을 수 있는것이지요.

      2012.11.13 15:39 신고 [ ADDR : EDIT/ DEL ]
  3. 왕초보

    아 그렇다면.. $0x0068732F 자체가 "/sh\0"을 나타내는 값이라는 말씀이신가요?
    그렇다면 혹시 제가 원하는 문자열을 저런 식으로 값을 넣는건 어떻게 할수 있을까요?
    이를테면 'abc' 라는 문자열을 스택에 넣고 싶다면 어떻게 코드를 생성할 수 있을까요..

    다른건 어찌어찌 이해하겠는데 역시 어셈블리는 많이 어렵네요.. 따라갈 수 있을지 ^^;;

    2012.11.14 10:25 [ ADDR : EDIT/ DEL : REPLY ]
    • 저 숫자 값이 메모리에 들어갈 땐 리틀 엔디언 방식을 적용해

      0x0068732F => 0x2F 0x73 0x68 0x00

      순으로 들어가게 됩니다.

      "abc" 라는 문자열은 각각을 아스키값으로 표현하면
      0x61 0x62 0x63 이므로 마지막 NULL을 포함해 스택에 넣는다면
      0x00636261 값이 되겠습니다.

      2012.11.14 12:34 신고 [ ADDR : EDIT/ DEL ]
  4. 왕초보

    아! 그래서 문자열이 '/bin/sh'에서 h부터 역순으로 들어간다는 말씀이시군요
    실제로 2자리씩 끊어서 아스키값으로 바꾸면 저런 문자열이 나오니까
    4자리씩 끊어서 스택에 넣을 수 있다는거 맞죠?? 이제야 이해가 됩니다.
    덕분에 많은 것들 배워가고 있습니다. 어떻게 하다 보니까 어셈블리도 배우게 되어서
    주인장님 블로그에서 열심히 공부해야 겠습니다.. 정말 감사합니다!

    2012.11.14 13:33 [ ADDR : EDIT/ DEL : REPLY ]
  5. mm

    아 근데 질문이 있습니다~ esp레지스터는 스택의 가장 최근에 있는 데이터를 가리키는데, 그렇다면 "/bin" 문자열만 가리켜야 하는거 아닌가요?
    어떻게 "/bin/sh"를 통틀어서 가리키게 되는 거죠???

    2014.02.21 10:43 [ ADDR : EDIT/ DEL : REPLY ]
    • 스택도 메모리의 한 부분입니다.

      0x00000000 | 44 43 42 41 | ABCD <- ESP
      0x00000004 | 00 47 46 45 | EFG..

      이런식으로 있을 때 이걸 쭉 늘여서 쓰면
      0x00000000 | 41 42 43 44 45 46 47 00
      이 됩니다.

      당연히 문자열은 NULL까지 이므로 /bin/sh를 전부 가리킨다고 볼 수 있죠...

      2014.02.23 18:58 신고 [ ADDR : EDIT/ DEL ]
  6. mm

    안녕하세요. 쉘코드 공부 하면서 막혔던 부분이었는데 정말 감사합니다. ^^

    2014.02.21 10:44 [ ADDR : EDIT/ DEL : REPLY ]
  7. 안녕하세요. 정말 도움이 많이 되었습니다. 감사합니다 ^^
    그런데, 궁금한점이 있어서 여쭙습니다.
    중간에 인라인 어셈으로 짠 소스코드에서 NULL을 없애기 위해
    0x0068732f 부분을 0x68732f2f로 변경하여 push 하였는데
    그러면 /bin//sh가 되는것이 아닌가요?

    NULL을 없애기 위해 왜 2F가 한 번 더 들어갔는지 궁금합니다.

    2014.06.16 01:50 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 뒤에 null이 있어서 없애주려고 그냥 슬레쉬 한번 더 쓴것 뿐입니다.
      한번쓰나 두번쓰나 똑같기 때문에요 ㅋ 아니면 NULL을 없애는데 딱히 다른거 쓸 문자가 있을까요? ㅎ

      2014.06.17 22:30 신고 [ ADDR : EDIT/ DEL ]
  8. Favicon of https://snmn0827.tistory.com LF0827

    관리자의 승인을 기다리고 있는 댓글입니다

    2014.06.18 04:09 [ ADDR : EDIT/ DEL : REPLY ]