[EVI$ION 7기] 6주차 System Hacking

김예원·2024년 11월 21일

포너블

시스템 관리자 권한을 탈취(==쉘 획득)하여 정보를 획득하는 것.

사용자와 커널 간의 인터페이스. 명령어 해석기
유저 - 쉘 - 커널

공격자가 쉘을 탈취하면 노출 시 위험한, 중요한 정보가 담긴 파일을 볼 수 있음.
ex) /etc/passwd : 사용자 정보가 저장된 파일(root만 권한)
/etc/shadow : 사용자의 pw 해시값이 저장된 파일

아키텍처

아키텍처마다 CPU가 한번에 처리할 수 있는 데이터의 크기가 달라짐
ex) 32bit 구조(x86), 64bit 구조(x86-64, x64)

x86-64 vs x64 Architecture

주소 체계의 크기, 레지스터가 저장할 수 있는 데이터의 크기가 다름

범용 레지스터

rax: 함수 반환 값
rbx: x64에서는 주된 용도 x
rcx: 반복문에서 반복횟수(counter), 연산 시행 횟수 등
rdx: 함수의 인자를 담는 레지스터
rsi: 함수의 인자를 담는 레지스터
rdi: 함수의 인자를 담는 레지스터
rsp: 스택 위치를 가리키는 포인터
rbp: 스택 바닥을 가리키는 포인터

rip: 현재 코드가 실행되는 위치 저장

메모리 구조

유저 영역에 실행되는 프로세스 A, B, C...가 쌓임.


^ 각 프로세스 메모리 구조

  • 위로 갈수록 높은 주소, 아래로 갈수록 낮은 주소
    1) 코드 세그먼트(텍스트 세그먼트)
    코드를 저장
    2) 데이터 세그먼트(data, rodata)
    상수, 전역 변수를 저장
    3) BSS 세그먼트
    초기화되지 않은 변수를 저장(처음에 다 0으로 초기화됨)
    4) 힙 세그먼트
    malloc 등으로 동적 할당한 메모리
    5) 스택 세그먼트
    지역변수, 레지스터, 환경변수 정보 등을 저장

스택 프레임

함수가 호출될 때, 해당 함수만의 스택 공간을 구분하기 위해서 생기는 공간

cdecl

x86(32bit 아키텍처)에서 사용하는 함수 호출 규약

함수 호출 처리 순서

ex)

void caller(){
	callee(1, 2);
}

1) caller가 전달할 argument를 stack에 push
2) callee prolog
3) callee epilog
4) caller가 call과정에서 사용한 stack 정리
-> callee가 아닌 caller가 ‘인자’를 정리
ex) add esp, n (여기서 n값은 esp가 증가한 byte만큼)
5) 함수 반환 값은 eax로 전달


^ 스택 구조

sysv

x64(64bit 아키텍처)에서 사용하는 함수 호출 규약

함수 호출 처리 순서

1) 6개의 인자를 RDI, RSI, RDX, RCX, R8, R9에 순서대로 저장하여 전달(더 많은 인자를 사용해야 할 때는 스택을 추가로 이용함)
2) callee prolog
3) callee epilog
4) caller에서 인자 전달에 사용된 스택 정리
5) 함수 반환 값은 rax로 전달

스택 프레임 변화 과정

1) 함수 호출

call func

push rip -> rip: 함수 실행 위치
jmp func

2) 함수 프롤로그
push rbp
mov rbp, rsp -> 스택 바닥을 가리키는 포인터인 rbp를 func 함수 실행 위치로 옮김
sub rsp, .. -> callee 스택에 callee의 각종 지역변수가 쌓이고 rsp가 그 맨 위를 가리킴

3) 함수 에필로그
leave
== mov rsp, rbp -> rsp는 rbp 위치(calle의 시작 위치)로 내림
pop rbp

ret
== pop rip

GDB

ELF(Executable and Linkable Format)

  • 리눅스 실행파일 형식
  • 헤더와 여러 섹션들로 구성
    • 헤더: 실행에 필요한 정보들
    • 섹션: 컴파일된 기계어 코드, 프로그램 문자열 등의 여러 데이터

구조

1) REGISTERS
레지스터의 상태를 보여줌
2) STACK
rsp부터 여러 줄에 걸쳐 스택의 값들을 보여줌
3) DISASM
rip부터 여러 줄에 걸쳐 디스어셈블된 결과 보여줌
4) BACKTRACE
현재 rip에 도달할 때까지 어떤 함수들이 중첩되어 호출됐는지 보여줌

GDB 사용법

프로그램 컴파일 후 gdb [프로그램명]으로 디버깅 시작

명령어

1) 파일 정보 출력(아키텍쳐, 동적/정적 링크 여부, 로더 정보 등)
file [파일 이름]
2) 보안 기법 출력
checksec --file=[파일이름]
3) 특정 주소에 중단점(breakpoint) 설정
break [주소]
4) 중단된 프로그램을 이어서 실행
continue
5) 단순히 실행
run 또는 r
-> bp 설정 안 되어있으면 프로그램이 끝까지 멈추지 않고 실행
6) 해당 함수가 반환될 때까지 기계어를 전부 디스어셈블하여 보여줌
disassemble [함수 이름] 또는 disass [함수 이름]
7) 메모리가 참조하고 있는 주소를 재귀적으로 탐색하여 값을 보여줌
tele
8) 분석할 함수의 중단점에 도달했으면, 그 지점부터 명령어를 한 줄씩 자세히 분석
navigate
-ni: 서브루틴의 내부로 들어가지 않음(next instruction)
-si: 서브루틴의 내부로 들어감(step into)
9) 특정 주소에서 원하는 길이만큼의 데이터를 원하는 형식으로 인코딩하여 보여줌
examine x
ex1) rsp부터 80바이트를 8바이트씩 hex형식으로 출력
x/10gx $rsp
ex2) rip부터 5줄의 어셈블리 명령어 출력
x/5i $rip
ex3) 특정 주소의 문자열 출력
x/s [주소]
10) 데이터의 위치 찾기
find
-> string, 주소값 등..
11) 프로세스 아이디 확인
pidof
12) 레지스터 정보 확인
i r
13) 세그먼트별 권한 확인
vmmap

0개의 댓글