본문 바로가기
SeSAC/어플리케이션 보안 & 취약점 진단

[SeSAC 성동캠퍼스 1기] 어플리케이션 보안 & 취약점 진단 1일차

by zivvon 2023. 11. 15.
목차 접기

어플리케이션 보안 & 취약점 진단

[ CPU Architecture ]

Stored-program concept : 폰 노이만의 프로그램 내장방식, 현대 컴퓨터와 똑같은 개념

- 기억 장치에서 하나의 데이터를 가져와서 해석

- 그에 따른 명령 수행

- 결과를 다시 메모리에 기록

- 무한반복

 

- 설계에 따라 CISC, RISC

        CISC                 RISC        
복잡 명령어 단순 명령어
가변 길이 명령어 고정 길이 명령어
컴파일 과정이 쉽고, 호환성 좋음 호환성이 낮음
속도 느림 속도 빠름
상대적으로 비쌈 상대적으로 저렴
고전력 저전력(모바일)
Intel, AMD ARM, Mips, GPU

 

 

 레지스터 Register : CPU 내부에 존재하는 다목적 저장 공간

1. General Purpose Register : 범용 레지스터
- IA-32에서 32bit로 활용
- EAX : 산술 연산, 함수의 리턴값
- EBX : 간접 주소 연산
- ECX : 반복문 명령어에서 카운트
- EDX : 간접 주소 연산 및 산술 연산의 보조
- ESI, EDI : 연산과 간접 번지 지정에 사용, 문자열 비교 시 주소 지정
- ESP : 스택의 위치 저장, SS와 같이 사용
- EBP : 스택의 바닥 저장, 데이터 액세스

2. Segment Register
- 현재 수행되고 있는 명령어의 위치를 나타내는 값
- 프로그램이 사용하는 데이터가 있는 메모리 값
- 함수 호출 등을 위한 스택의 위치를 나타내는 값(SP)

3. Program Status and Control Register ⭐
- Carry Flag : 덧셈에 의한 자리올림, 뺄셈에 의한 빌림
- Parity Flag : 하위 8비트의 1로 셋팅된 비트가 짝수일 시 세트
- Auxiliary Flag : 연산 결과 하위 4비트에 자리올림 또는 빌림
- Zero Flag : 연산 결과가 0일 시 또는 비교 연산
- Sign Flag : 연산 결과가 1(음수)일 시 세트
- Overflow Flag : 연산 결과에 오버플로우 발생 시, ex) 비트 연산 - 128 ~ + 128

4. Instruction Pointer
- IP Register
- 프로그램의 실행할 코드의 주소를 지정
- IP를 마음대로 변경 => RCE

 

 

[ Memory Architecture ]

Memory : CPU가 작업을 수행하는 공간

- 폰 노이만 아키텍처

- 속도가 디스크에 비해 빠름

- 한정된 리소스

- 과거 Single Tasking의 문제 (하나의 프로그램이 마무리 되어야 다음 프로그램 수행, 프로세서의 자원 낭비 등)

과거의 단점을 극복하고자! 하나의 프로세서에서 각각의 프로그램(프로세스)을 교대(TDM, 스케줄링)로 수행

   ㄴ 멀티태스킹과 유사

 

멀티 태스킹 Multi Tasking ⭐

- 한 개의 CPU에서 특정 순간 한 개의 작업만 가능

- GUI, 다양한 어플리케이션의 독립된 실행 공간이 필요

- 스케쥴링을 통해 사용자에게 병렬 연산이 이루어지는 것과 같은 환경 제공

- 문맥 교환을 통해 새로운 작업 처리

 

▶ MMU(Memory Management Unit)

- CPU가 메모리를 Access 할 때마다 주소를 Virtual Address로 매핑

ㄴ Q. Virtual Address?

     A) 실행 되어 있는 응용 프로그램에게는 물리적인 메모리 감춤

          모든 응용 프로그램이 각각의 독립된 가상주소 0에서 메모리 사용

 

Segment

- Code, Resource, 전역 변수 등과 같은 데이터가 저장되어 있는 요소들을 각각 배치

- 코드부나 리소스부를 참조하는 세그먼트 레지스터들을 통해 오프셋(Offset) 0을 기준으로 데이터에 접근

- 따로 Segment Table을 마련하고 각각의 세그먼트에 속성 지정

 

개발에서 실행까지!

 

Debugger : 다른 프로그램을 테스트 하고 디버깅(s/w 오류를 잡는 행위)하는 프로그램

- GNU Debugger(GDB), Intel Debugger(IDB), Microsoft Visual Studio Debugger, Valgrind...

- WinDBG, OllyDBG, IDA, Immunity Debugger

- 프로세스를 trace, Dynamic Analysis

- 소프트웨어 취약점에 접근하고자 할 때 유용하게 사용할 수 있는 기능 제공

 

- Break Point : 실행 중인 디버깅 대상 프로세스르 멈추게 함

~> 프로세스가 일시 중지되면 중지된 시점의 변수나 메모리 값들을 확인 가능

~> SW Break Point, HW Break Point, Memory Break Point 

 

 Assembly ⭐

- CPU는 기계어만 해석

- 코드는 기계어로 해석되기 전 Assembly 중간언어로 변환

- CISC와 RISC의 중간언어는 많은 차이가 있음

- OpCode와 Operand로 구성

OpCode : 명령어 Operand : 파라미터 (없을 수도 있음)
ex) mov eax ecs ex) return

 

- 자주 접하는 명령어 ⭐

명령어 설명
PUSHAD 8개의 범용 레지스터의 값을 스택에 저장
POPAD PUSHAD 명령에 의해서 스택에 저장된 값들을 다시 레지스터에 입력
PUSH A A 값을 스택에 넣음
POP Register 스택에서 값을 꺼내 레지스터에 넣음
INC A A 값을 1 증가시킴
DEC A A 값을 1 감소시킴
ADD A B A 값과 B 값을 더해서 그 결과를 A에 저장
SUB A B A 값에서 B 값을 빼고 그 결과를 A에 저장
IML A B A 값과 B 값을 곱하고 그 결과를 A에 저장
LEA A B B 값을 A 값으로 옮김
MOV A B
OR A B  A 값과 B 값을 OR 연산
XOR A B A 값과 B 값을 XOR 연산
AND A B A 값과 B 값을 AND 연산
TEST A B A 값과 B 값을 AND 연산 (함수 호출 리턴 값을 확인하는 용도로 많이 사용)
연산 결과 값이 A에 저장되지 않지만 ZF 플래그 설정에 영향
연산 결과가 0이면 ZF가 1이 되고 연산 결과가 0이 아니면 ZF는 0이 됨
CMF A B 비교 구문으로 A와 B가 같은지 판단
JMF Address 해당 주소로 무조건 이동
JZ(Jump if Zero) Address 연산 결과가 0이면(ZF=1) 이동하고, 아니면(ZF=0) 다음 명령어 실행
JE(Jump if Equal) Address
JNZ(Jump if Not Zero) Address 연산 결과가 0이 아니면(ZF=0) 이동하고, 0이면(ZF=1) 다음 명령어 실행
JNE(Jump if Not Equal) Address
MOVE DWORD PTR DS:[Address] EAX Address부터 4Byte 값을 EAX로 복사
CALL Address Address 호출
RET 해당 함수를 종료하고 스택이 지시하는 함수로 리턴

 

PE Header

- Dos Header : Dos와 호환성 위해 만듦, 파일의 처음 위치, 0x40 크기

 

- Dos Stub

~> PE 파일이 MS-Dos에서 실행될 경우, 출력될 메시지와 코드 기록

~> Dos Stub은 옵션이기 때문에 파일 실행에 영향이 없음

~> 크기 일정하지 않고 없어도 됨

 

- NT Header

~> 파일 실행에 필요한 전반적인 정보를 가지고 있음, 0xF8 크기

~> Image Optional Header 중요

 

- Section Header : 각 섹션의 속성 정보

 

- Image Optional Header

 

- IAT(Import Address Table)

~> EXE에 주로 존재

~> DLL이 제공하는 함수들 중에서 사용하는 것들에 대한 정보 기술

 

- EAT(Export Address Table)

~> DLL에 주로 존재

~> DLL 자신이 서비스 하는 함수에 대한 정보를 기술

 


 

💡실습!

zip 파일에 암호 걸기!
1. 1111.txt 파일과 1111.zip 파일을 준비한다.

2. HxD로 zip 파일의 기계어를 수정해준다.
50 4B 01 02 14 00 14 00 다음을 '01'로 수정​
하단 화면 참고!
⚠️ 텍스트 파일 내용이 다르면 위치가 다를 수 있음!

3. 수정한 파일을 저장하고 zip파일 압축을 풀어본다.
이 때 정상적으로 암호가 걸린 것을 확인할 수 있다 :) 
결과화면은 하단 참고!

수정 화면
결과 화면


 

✏️ 공부하면서 몰랐던 것들 혼자 정리해보는 시간!

 

Q1. 올리 디버거 OllyDBG?

A1. 리버싱을 하려면 디스 어셈블리 툴과 디버그 툴이 필요한데, 올리 디버거는 두 가지 모두 가능한 툴!

ㄴ Q1-1. 리버싱이란?

ㄴ A1-1) Reverse Engineering의 약자로 역공학이라는 의미를 가짐. 일반적인 의미에서 리버스 엔지니어링이라고 하면 물건이나 기계장치 혹은 시스템의 구조, 기능, 동작 등을 분석하여 그 원리를 이해하며 단점 보완하고 새로운 아이디어 추가하는 일련의 작업, 즉! 이미 만들어진 시스템이나 장치에 대한 해체나 분석을 거쳐 그 대상 물체의 구조와 기능, 디자인 등을 알아내는 일련의 과정

= ' 완성품의 설계도 없이 구조와 동작 과정을 알아내는 모든 단계 '

 

ㄴ Q1-2. 리버싱 방법?

ㄴ A1-2) 프로그램을 실행시키지 않고 분석하는 정적 분석과 프로그램을 실행시켜서 입출력과 내부 동작 단게를 살피며 분석하는 동적 분석 

 

Q2. PE? ⭐

: PE 포맷이란 윈도우 운영체제에서 사용되는 실행파일, DLL Object 코드, FON 폰트파일 등을 위한 파일 형식, OE 파일은 윈도우 로더가 실행 가능한 코드를 관리하는데 필요한 정보를 캡슐화한 데이터 구조체

= PE를 풀어쓰자면 ' Portable Excutable ', 어디서든 실행되는 파일

ㄴ Q2-1. 왜 PE파일 포맷을 해야 되는지?

ㄴ A2-1) PE 구조는 파일이 실행되기 위한 모든 정보를 다 볼 수 있기 때문, 프로그램이 사용하는 API나 어느 메모리 주소에 파일이 로딩되는지 알 수 있음!

 

- PE 파일의 종류

~> 실행 계열 : EXE, SCR

~> 드라이버 계열 : SYS, VXD

~> 라이브러리 계열 : DLL, OCX, CPL, DRV

~> 오브젝트 계열 : OBJ

 

- PE Header

: PE 헤더는 구조체로 이루어져 있으며, 영역은 DOS Header ~ Section Header

 

- DOS Heaer

: Microsoft는 PE파일 포맷을 만들 때 DOS 파일에 대한 하위 호환성을 고려했기 때문에, 그 결과로 PE 헤더 파일 제일 앞 부분에는 기존 DOS EXE Header를 확장시킨 IMAGE_DOS_HEADER 구조체가 존재. 즉, 모든 PE 파일은 시작부분(e_magic)의 DOS signature(MZ)가 존재하고 e_lfanew값이 가리키는 위치에 NT header 구조체가 존재해야 하며, 그 구조체의 이름이 IMAGE_NT_HEADERS! 

= 모든 PE 파일 시작 부분에는 e_magic이 존재! 

 

- DOS Stub

: DOS Header 밑에 존재, DOS Stub는 옵션에 의해 존재여부를 결정하며 크기도 일정하지 않음

⚠️ DOS Stub이 없어도 파일 실행에는 문제 x

 

- NT Header 구조체 : Signature, IMAGE_FILE_HEADER, IMAGE_OPTIONAL_HEADER32

 

~> DOS Signature : NT Header 구조체의 시작을 알리며 ASCII 값이 PE로 시작

~> IMAGE_FILE_HEADER 

Machine : CPU별로 고유한 값을 가지면서 IA-32 호환 CPU 14ch의 값을 IA-64호환 CPU는 200h의 값을 가짐
NumberOfSections : 다음에 나오는 Section들의 갯수이며 최소 1개 이상이어야 함
SizeOfOptionalHeader : 이 값은 IMAGE_NT_HEADERS 구조체의 마지막 구조체 IMAGE_OPTIONAL_HEADER 32의 구조체 크기를 나타냄
Characteristics : 이 값은 파일 속성에 대한 부분

 

~> IMAGE_OPTIONAL_HEADER  ⭐

  • Address of Entry Point : 파일의 코드 시작 지점에 대한 RVA(Related Virtual Address) 값을 가짐
  • Image Base : 파일 데이터가 메모리에 올라갈 때, 기준이 되는 주소 값 가짐
  • Size of Images : 메모리에 올라간 파일 데이터의 크기 값을 나타냄
  • Data Directory : PE 파일의 내부 데이터를 가리키는 포인터 포함, 여러 개의 Entry로 구성되어 있으며, 각 엔트리는 하나의 Data Directory를 가리키는 포인터와 포인터에 위치한 데이터의 크기 기술

 

오늘의 후기!

: 어플리케이션 보안 수업에 들어오자마자 벙-찌게 된다 내 전공이 맞나 의심스러울 정도로 다 처음 해보는 것들이라 머리 아픔 ㅎㅎ... 물론 학교 이론 수업이나 정처기 준비하면서 봤던 개념들도 있지만 다시 접하니까 또 새로 배우는 것 같다 특히 PE 파일 아직도 이해를 못 했는데 많은 노력이 필요할 것 같다. C++이 고급언어라는 걸 갑자기 체감 중 ㅎ... 어셈블리어랑 기계어에 적응할 시간이 필요할 듯 싶다. 얼른 헥스레이를 보는 눈을 가지고 싶다 ^^....!!