CH 05 코드 보안

김유찬·2023년 6월 18일

정보 보안 개론

목록 보기
3/4
post-thumbnail

■ 시스템 구성과 프로그램 동작

● 프로그램과 코드 보안

  • 하드웨어, 어셈블리어, 소스 코드 중 보안 취약점이 가장 쉽게 발생하는 곳은 소스 코드
  • 요인은 데이터의 형태와 길이에 대한 불명확한 정의

● 시스템 메모리의 구조

  • 프로그램을 동작시키면, 프로그램이 동작하기 위한 가상의 공간이 메모리에 생성

  • 목적에 따라 상위, 하위 메모리

  • 상위 메모리에는 스택(로컬 인자와 프로세스 상태 저장), 하위 메모리에는 힙(동적으로 할당된 데이터 저장) 생성

  • 스택 영역
    -프로그램 로직이 동작하기 위한 인자와 프로세스 상태를 저장하는 데 사용
    -레지스터의 임시 저장, 서브루틴 사용 시 복귀 주소 저장, 서브 루틴에 인자 전달 등에 사용
    -메모리의 상위 주소에서 하위 주소 방향으로 사용, 후입선축(LIFO) 원칙에 따라 나중에 저장된 값을 먼저 사용

  • 힙 영역
    -프로그램이 동적할 때 필요한 데이터 정보를 임시로 저장하는 데 사용
    -가변적인 양의 데이터를 저장하기 위해 프로그앰 프로세스가 사용할 수 있도록 미리 예약된 메인 메모리 영역
    -프로그램에 의해 할당되었다가 회수되는 작용 되풀이
    -힙의 기억 장소는 포인터 변수를 통해 동적으로 할당받고 돌려주며, 연결 목록이나 트리, 그래프 등의 동적인 데이터 구조를 만드는 데 반드시 필요함
    -프로그램 실행 중 해당 힙 영역이 없어지면, 메모리 부족으로 이상 종료

  • 레지스터
    -CPU의 임시 메모리로, CPU 연산과 어셈블리어의 동작에 필요

● 스택과 레지스터의 실제 사용

1. pushl %ebp: 처음 main 함수가 시작되면 main 함수의 EBP 레지스터 값을 스택에 저장

2. movl %esp,%ebp: ESP 레지스터는 항상 현재 스택 영역에서 가장 하위 주소를 저장

3. subl $4, %esp: ESP 값에서 4바이트만큼을 뺀다. 즉, 스택에 4바이트의 용량을 할당한다.
4. pushl $2: 스택에 정수 2를 저장한다.
5. pushl $1: 스택에 정수 1을 저장한다.
6. call function: function 함수 호출
7. pushl %ebp: function 함수의 기준 값으로, 현재 EBP 값을 스택에 저장

8. movl %esp,%ebp: 앞서 언급한 대로 function(1, 2)의 시작에서도 프롤로그(pushl %ebp 명령과
movl%esp,%ebp)가 실행
9. sub $12, %esp: ESP 값에서 12바이트만큼을 뺀다.

10. movl 12(%ebp),%eax: EBP에 12바이트를 더한 주소 값의 내용을 EAX 값에 복사
11. addl %eax,8(%ebp): EBP에 8바이트를 더한 주소 값의 내용에 EAX 값을 더하면 8값은 3이 됨

■ 셸

  • 운영체제를 둘러싸고 있으면서 입력받는 명령어를 실행하는 명령어 해석기로, 조개 껍데기에 비유

● 셸의 역할

  • 자체에 내장된 명령어 제공
  • 입력, 출력, 오류에 대한 리다이렉션 기능 제공
  • 와일드카드 기능 제공
  • 파이프라인 기능 제공
  • 조건부, 무조건부 명령열 작성 기능 제공
  • 서브셸 생성기능 제공
  • 후면 처리 가능
  • 셸 스크립트 (프로그램) 작성 가능

● 셸에서 사용할 수 있는 명령어

  • cd: 디렉토리 변경
  • ls: 디렉토리 내의 파일 목록 표시
  • cat: 파일 내용 표시
  • mkdir: 새로운 디렉토리 생성
  • rm: 파일 또는 디렉토리 삭제
  • cp: 파일 복사
  • mv: 파일 이동 또는 이름 변경
  • ps: 현재 실행 중인 프로세스 목록 표시
  • kill: 프로세스 종료
  • ping: 네트워크 상태 확인
  • ssh: 원격 호스트에 로그인

● 셸의 리다이렉션 기능

  • 입력 또는 출력의 방향을 변경하는 데 사용
  • 명령의 표준 입력, 표준 출력 또는 표준 오류 출력을 변경하는 데 사용
  • 파일로부터 입력을 받을 수 있고, 파일로 출력을 보낼 수도 있음
  • 파일과 명령어를 연결하여 작업을 자동화하거나 명령의 결과를 파일로 저장할 수 있음

● 셸의 와일드카드 기능

  • 파일 및 디렉토리 이름을 패턴 매칭하는 데 사용되며 별표와 물음표와 같은 문자로 구성됨
  • 별표는 모든 문자열을 일치시키는데 사용됨, 예를 들어, “.txt" 패턴은 모든 .txt 확장자를가진 파일들과 일치합니다. 또한, "file" 패턴은 "file1.txt", "file2.txt", "file3.dat"과 같은 파일들과도 일치함
  • 물음표는 하나의 문자를 대체하여 일치시키는 데 사용됨, 예를 들어, "file?.txt" 패턴은
    "file1.txt", "file2.txt"와 같은 파일들과 일치함
  • 대괄호는 일치시키려는 문자의 범위를 나타냄, "[abc]file.txt" 패턴은 "afile.txt", "bfile.txt", "cfile.txt"와 같은 파일들과 일치함
  • 파일 이름을 일괄적으로 변경하거나 검색하는 등 다양한 작업에서 사용됨

● 셸의 파이프라인 기능

  • 여러 개의 명령어를 실행하여 결과를 하나로 연결하는 기능, 파이프(|) 를 사용하여 명령어를 연결하며, 이전 명령어의 출력이 다음 명령어의 입력으로 사용됨

● 셸의 조건부, 무조건부 명령열 작성 기능

  • 조건부 명령어는 일반적으로 if-then-else 구문으로 작성됨
  • 무조건부 명령어는 특정 조건에 관계없이 실행되는 명령어러 echo 명령어 사용

● 셸의 후면 처리

  • 후면처리는 셸에서 실행되는 프로세스를 백그라운드에서 실행시키는 것을 말함
  • 일반적으로 해당 명령어 뒤에 & 기호 추가
  • 실행 중인 후면처리 프로세스의 목록을 확인하기 위해 jobs 명령어 사용, 현재 셸 세션에서 실행 중인 백그라운드 작업 목록 표시
  • 종료하려면 kill 명령어

● 셸

  • 버퍼 오버플로나 포맷 스트링 공격의 목적은 '관리자 권한의 셸'
  • 버퍼 오버플로나 포맷 스트링 공격에서는 /bin/sh를 다음과 같이 기게어 코드로 바꿔 메모리에 올림
  • 셸을 기계어로 바꾸는 이유는 메모리에 원하는 주소 공간을 올리기 위해서임
  • 버퍼 오버플론나 포맷 스트링 공격에서도 이와 같이 셸을 기계어화한 코드를 이용하여 관리자 권한의 셸을 획득함

● 프로세스 권한과 SetUID

  • 유닉스 파일에 rwsr-xr-x로 권한이 설정되어 있는 경우
  • SetUID 파일은 누가 실행하든 상관 없이 해당 파일이 실행될 때 파일 소유자의 권한을 갖는 것이 특징

● SetUID를 이용한 해킹

  • chmod 4755 ./shell 명령어는 ./shell 파일의 권한을 설정하는 명령어
  • ./shell은 현재 디렉토리에 있는 shell 파일을 가리킴
  • 4755setuid 비트가 설정된 실행 파일의 권한임
  • 4: 소유자는 읽기 권한을 가짐
  • 7: 그룹은 읽기, 쓰기, 실행 권한을 가짐
  • 5: 모든 사용자는 읽기 및 실행 권한을 가짐
  • 1: setuid 비트가 설정됨
  • setuid 비트가 설정된 파일은 파일을 실행하는 사용자가 파일의 소유자로 인식됨
  • ./shell 파일을 실행하는 모든 사용자는 파일을 소유한 사용자의 권한을 가질 수 있음
  • 이러한 권한은 특정 시스템 명령어를 실행하는 데 필요한 권한을 가진 사용자가 아닌 다른 사용자도 명령어를실행할 수 있게 해줌
  • , setuid 비트를 설정하는 것은 보안 위험이 따르기 때문에 신중하게 사용해야 함

■ 버퍼 오버플로 공격

■ 버퍼 오버플로 공격의 개념

  • 데이터의 길이에 대한 불명확한 정의를 악용한 덮어쓰기로 발생
  • 경계선 관리가 적절하게 수행되어 덮어쓸 수 없는 부분에 해커가 임의의 코드를 덮어쓰는 것

■ 버퍼 오버플로 공격의 원리


1. int main(int argc, char *argvp[])

  • argc는 휘약한 코드인 bugfile.c가 컴파일되어 실행되는 프로그램의 인수 개수. *argv[]는 포인터 배열로서 인자로 입력되는 값의 번지수를 차례로 저장
  • argv[0]: 실행 파일의 이름
  • argv[1]: 첫 번째 인자의 내용
  1. char buffer[10]
  • 10바이트 크기의 버퍼를 할당
  1. strcpy(buffer, argv[1])
  • 버퍼에 첫 번째 인자(argv[1])를 복사. 즉 abcd 값을 버퍼에 저장
  • 실제 버퍼 오버플로 공격은 이 코드에서 일어남
  1. printf("%s\n", &buffer)
  • 버퍼에 저장된 내용 출력


1. push %ebp
2. mov %esp,%ebp: 스택에 ebp 값을 밀어넣고 현자의 esp 값을 ebp 레지스터에 저장

3. sub $0xc,%esp: main 함수의 char buffer[10]을 실행하는 과정, char 명령어로 메모리에 10바이트를 할당했으나 메모리에서는 모두 4바이트 단위로 할당되어 실제로 할당되는 메모리는 12바이트임
4. <main 6>: mov 0xc(%ebp),%eax: ebp에서 상위 12바이트(0xC) 내용을 eax 레지스터에 저장하면 eax 레지스터는 ret보다 상위 주소의 값을 읽어들임, 여기에는 char argv[]를 가리키고 eax에 argv[]에 대한 포인터 값이 저장

5. add $0x4,%eax: eax값을 4바이트만큼 증가, argv[]에 대한 포인터이므로 argv[1]을 가리킴
6. mov (%eax),%edx: eax 레지스터가 가리키는 주소의 값을 edx 레지스터에 저장, 프로그램을 실행할 때 인수 부분을 가리킴
7. push %edx: 프로그램을 실행할 때 인수에 대한 포인터를 스택에 저장, 인수를 넣지 않고 프로그램을 실행하면 0x0의 값이 스택에 저장

8. lea 0xfffffff4(%ebp),%eax: eax 레지스터에 12(%ebp)의 주소 값을 저장
9. push %eax: 스택에 eax 레지스터 값을 저장
10. call 0x8048340: strcpy(buffer, argv[1])을 실행하기 위해 buffer, argv[1]과 관련된 사항을 스택에 모두 상주시킴, 마지막으로 strcpy 명령을 호출
11. jmp
0x80494c0 버퍼 오버플로 공격은 여기서 일어남

● GDB를 이용한 strcpy가 호출되는 과정

  • strcpy 함수는 입력된 인수의 경계를 체크하지 않으므로 10바이트 길이를 넘지 않아야만 그보다 큰 인수를 받아도 스택에 쓰임
  • 13개 A를 인수로 사용하면 A가 쌓일 것
  • 열여섯 번째 문자에서 세그먼테이션 오류가 발생하는 것을 확인(입력 버퍼 이상의 문자열을 입력할 때 발생하는 세그먼테이션 오류)

● 버퍼 오버플로 공격의 대응책

  • 버퍼 오버플로에 취약한 함수 불사용
    -strcpy(char dest, const char src);
    -strcat(char dest, const char src);
    -getwd(char buf);
    -gets(char
    s);
    -fscanf(FILE stream, const char format, ...);
    -scanf(const char format, ...);
    -realpath(char
    path, char resolved_path[  ]);
    -sprintf(char str, const char format);

  • 최신 운영체제 사용
    -최신 운영체제에는 non-executable stack, 스택 가드, 스택 실드와 같이 운영체제 내에서 해커의 공격 코드가 실행되지 않도록 하는 여러 가지 장치가 있음

■ 포맷 스트링 공격

● 포맷 스트링 공격의 개념

  • 데이터 형태에 대한 불명확한 정의 때문에 발생하는 문제점
  • 위와 같이 포맷 스트링을 작성하는 것은 정상적인 경우로, 포맷 스트링에 의한 최약점이 발생하지 않음
  • 여기서 사용된 %s와 같은 문자열을 포맷 스트링이라고 함

● 포맷 스트링 공격의 원리

  • wishfree라는 문자열에 대한 주소 값을 포인터로 지정
  • 포인터(buffer)가 가리키는 주소에서 %s을 읽어서 출력
  • 취약한 포맷 스트링
    -포맷 스트링 공격은 포맷 스트링인 %s의 값을 바꾸는 것(명확하게 정의되었던 데이터 형태를 바꾸는 것)

● 포맷 스트링 문자를 이용한 메모리 열람

  • char *buffer에 문자열을 입력할 때 %x라는 포맷 스트링 문자를 추가
  • 8048440은 wishfree 문자열이 저장된 다음의 메모리에 존재하는 값으로 0x0848440을 의미함

● 포맷 스트링 문자를 이용한 메모리 변조

■ 메모리 해킹

  • 프로그램의 동작에 관여하지 않고, 프로그램이 실행되는 데 필요한 정보를 저장해둔 메모리를 조작하는 것
profile
eukddan

0개의 댓글