[정보보안개론] 05주차. 코드 보안

Sujung Shin·2023년 4월 24일
0

01 프로그램과 코드 보안

EXE, COM, DLL 등과 같은 실행 파일의 형태로 작동하는 프로그램의 코드 보안
하드웨어, 어셈블리어, 코드 중 가장 취약한 곳 = 소스 코드
'데이터 길이와 형태에 대한 불명확한 정의'
보통 C/C++ 등과 같은 low-level language에서 많이 발생한다.
동적 prototyping 필요

시스템 메모리의 구조

1 스택(stack)영역과 힙(heap 영역)

레지스터


레지스터는 CPU의 임시 메모리
CPU연산과 어셈블리어 동작에 필요하다.
인텔의 80x86 CPU기준으로 다음과 같은 레지스터를 사용한다.

프로그램 실행 구조

셸(=cmd)

본 셸(bourne shell), 콘 셸(korn shell), C 셸(C shell)
본 셸은 유닉스 시스템에서 사용하는 기본 셸

  • 자체에 내장된 명령어 제공
  • 입/출력, 오류에 대한 리다이렉션 기능 제공
  • 와일드카드 기능 제공
  • 파이프라인 기능 제공
  • 조건부, 무조건부 명령열 작성 기능 제공
  • 서브셸 생성 기능 제공
  • 후면 처리 기능
  • 셸 스크립트 프로그램 작성 가능
    관리자 권한의 셸 = 버퍼 오버플로/포맷 스트링 공격을 통해 얻고자 하는 것
    획득한 관리자 권한을 이용한 셸이 필요
    /bin/sh명령으로 셸 실행, exit명령으로 셸 빠져나오기


프로세스 권한과 SetUID

SetUID = 유닉스 시스템을 해킹하는 데 매우 중요한 요소
유닉스 파일에 rws r-x r-x로 권한이 설정된 경우(사용자 권한에서 x가 아닌 s가 설정되어있다)
SetUID 파일은 누가 실행하든 상관없이 해당 파일이 실행될 때 파일 소유자의 권한을 가짐
test 파일이 root 소유이고, SetUID 비트가 설정되어 있다면 다음과 같이 실행된다.


03 버퍼 오버플로 공격

  • 데이터 '길이'에 대한 불명확한 정의
int main(int argc, char *argv[]) {
// argv[0]: 실행 파일의 이름, argv[1]: 첫번째 인자, argv[2]: 두번째 인자
	char buffer[10]; // 10바이트 크기의 버퍼 할당(12byte의 주소할당)
    strcpy(buffer, argv[1]); // 버퍼 오버플로는 여기서 발생
    printf("%s\n", &buffer); // 버퍼에 저장된 내용 출력
}

10바이트 길이를 넘지 않아야 하는데,(실제 메모리는 12byte만 할당받긴 함) strcpy는 입력받은 인수의 경계를 체크하지 않아 10바이트보다 큰 인수를 받아도 스택에 쌓인다.(세그멘테이션 오류 발생)
즉, 기존의 EBP 값을 지나 변조된 RET값을 참조할 수 있다.

대응책

버퍼 오버플로에 취약한 함수 사용하지 않기

  • strcpy(char *dest, const char *src);
    strcpy_s(), strncpy() 함수 사용(인수 경계 체크하는 함수)
  • strcat(char *dest, const char *src);
  • getwd(char *buf);
  • gets(char *s); //사용자가 입력받는 문자열 그대로 입력받기
    fgets()함수 사용
  • fscanf(FILE *stream, const char *format, ...);
  • scanf(const char *format, ...);
  • realpath(char *path, char resloved_path[]);
  • sprintf(char *str, const char *format);

최신 운영체제 사용

non-executable stack, 스택 가드, 스택 실드와 같이 운영체제 내에서 공격 코드가 실행되지 않도록 하는 여러 장치가 존재한다.

04 포맷 스트링 공격

포맷 스트링 공격의 개념


  • 데이터 '형태'에 대한 불명확한 정의
#include <stdio.h>

main() {
	char *buffer="wishfree";
    printf("%s\n", buffer); //'%s'는 문자열 포맷 스트링 문자
}

포맷 스트링 공격의 원리


데이터의 포맷 스트링이 명확하게 정해져 있으면 포맷 스트링 공격이 적용되지 않는다.

  • 포맷 스트링 문자의 종류

취약한 포맷 스트링


#include <stdio.h>

main() {
	char *buffer="wishfree";
    printf(buffer); // 포맷 스트링 공격이 일어날 수 있는 곳
}

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


#include <stdio.h>

main() {
	char *buffer="wishfree\n%x";
    // %x는 양의 정수(16진수), 메모리값 참조 가능
    printf(buffer); // 포맷 스트링 공격이 일어날 수 있는 곳
}

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


#include <stdio.h>

main() {
	long i = 0x00000064, j = 1;
    printf("i의 주소 : %x\n", &i);
    printf("i의 값: %x\n", i);
    
    printf("%64d%n\n", j, &i); //포맷 스트링 문제
    //%64d 부분에 공격 셸(egg shell)의 주소 값을 계산하여 넣는다.
    printf("변경된 i의 값 : %x\n", i); 
}

05 메모리 해킹


메모리 해킹의 개념

  • 프로그램의 동작에 관여하지 않고, 프로그램이 실행되는 데 필요한 정보를 저장해둔 메모리를 조작하는 것 (게임 머니, 아이템을 조작하는 등)
    메모리 해킹이 발생하면 사용자가 인지하지 못하는 경우가 多
    메모리 주소에 저장된 값을 암호화 하여야 한다.
    즉, End-to-End(종단 간) 암호화, 가변으로 메모리 참조 변숫값을 돌리는 등의 암호화 과정을 거쳐야 한다.
    해킹 툴로는 MHS(Memory Hacking Software)을 이용한다.
profile
백문이불여일타

0개의 댓글

관련 채용 정보