320x100

리눅스의 주요 역할

  1. 응용 프로그램 관리 (App Management)
    • 리눅스는 다양한 응용 프로그램을 실행하고 관리하는 역할을 합니다. 프로세스의 생성, 스케줄링, 종료 등을 통해 여러 응용 프로그램이 효율적으로 자원을 사용할 수 있도록 합니다.
  2. 하드웨어 관리 (Hardware Management)
    • CPU, RAM, 디스크, 네트워크 장치 등 하드웨어 리소스를 관리합니다. 이를 통해 시스템 자원의 효율적인 사용과 안정성을 보장합니다.

리눅스의 물리적 실체

  • 리눅스 커널은 C 코드로 작성되어 있으며, 컴파일을 통해 vmlinux라는 실행 파일로 변환됩니다. 이 커널은 약 10만 개의 함수로 구성되어 있으며, 그 중 300~400개는 사용자 호출이 가능한 시스템 콜로 제공됩니다. 예를 들어, open, read, write 등의 시스템 콜이 있습니다.

바이너리 실행 파일 및 ABI

  • 리눅스에서 실행되는 바이너리 파일은 ELF(Executable and Linkable Format) 형식을 따릅니다. ABI(Application Binary Interface)는 운영체제, CPU, 컴파일러 간의 규칙과 규약을 정의합니다. ABI를 준수하면, 소스 코드를 한 번만 컴파일하더라도 여러 시스템에서 재컴파일 없이 실행할 수 있습니다.

.

ABI는 소프트웨어와 하드웨어 간의 상호작용을 정의하는 중요한 규칙 세트로, ELF 파일 형식, 시스템 호출 번호, 호출 규약, 가상 메모리 매커니즘 등을 포함하여 다양한 컴포넌트를 통해 운영체제와 응용 프로그램 간의 호환성을 보장합니다. 이를 통해 개발자는 다양한 환경에서 소프트웨어를 효과적으로 개발하고 배포할 수 있습니다.

메모리 관리

  • 소스 코드는 물리적 메모리 주소 기반으로 컴파일되지만, 실제 실행 시에는 가상 주소(VA)가 사용됩니다. 이때, OS와 CPU는 VA를 물리적 주소(PA)로 변환하여 메모리를 관리합니다.
  • OS는 프로세스를 실행할 때 task_struct와 mm_struct를 사용하여 각 프로세스의 가상 주소 공간을 기록합니다. 이 구조체는 가상 메모리 영역(VMA)을 관리합니다.

페이지 테이블 및 MMU

  • CPU 내부의 MMU(Memory Management Unit)는 가상 주소를 물리적 주소로 변환하는 역할을 합니다. 만약 현재 프로세스의 페이지 테이블에 해당 VA가 존재하지 않는 경우, 페이지 폴트(page fault) 예외가 발생합니다. 이는 필요한 페이지를 메모리에서 로드하거나, 다른 처리를 통해 해결해야 함을 의미합니다.
  • 리눅스는 후매핑 방식을 사용하여 필요한 페이지가 실제로 사용될 때까지 물리 메모리에 로드하지 않습니다. 즉, 프로세스가 특정 메모리 페이지에 접근하려 할 때, 해당 페이지가 메모리에 존재하지 않으면 페이지 폴트가 발생합니다.

pagefault는 프로세스가 접근하려는 가상 주소가 물리 메모리에 존재하지 않을 때 발생합니다. 이 경우, OS는 해당 VA가 유효하지 않음을 확인하고 페이지를 디스크에서 로드하여 페이지 테이블을 업데이트합니다. 페이지 크기는 일반적으로 4KB이며, 페이지 테이블은 VA와 PA 간의 연결을 관리하여 메모리 접근을 효율적으로 수행합니다. 이 모든 과정은 가상 메모리 시스템의 핵심적인 부분으로, 프로세스가 메모리를 안전하고 효율적으로 사용할 수 있도록 돕습니다.

*페이지 크기: 4KB,4096,0x1000, 12bit, 2^12

 

 

1. CPU와 MMU의 상호작용

  • CPU는 실행 중인 프로그램의 명령어를 처리하며, 메모리에 접근할 때 가상 주소(VA)를 사용합니다.
  • **MMU (Memory Management Unit)**는 CPU가 요청한 가상 주소를 물리 주소(PA)로 변환하는 역할을 합니다. MMU는 페이지 테이블을 참조하여 VA의 유효성을 검사하고, 해당하는 PA를 획득합니다.

2. 메모리 접근 과정

  • CPU가 메모리에 접근할 때, 다음 과정이 일어납니다:
    1. CPU가 MMU에 가상 주소를 전달합니다.
    2. MMU는 페이지 테이블을 조회하여 VA에 해당하는 PA를 찾습니다.
    3. PA가 결정되면, MMU는 이 주소를 CPU에 반환합니다.

3. 캐시 계층

  • PA가 획득되면, 다음 단계는 캐시 메모리입니다:
    1. 캐시 컨트롤러는 PA를 기반으로 캐시 메모리(SRAM L1, L2, L3)에 접근합니다.
    2. 만약 요청한 데이터가 캐시에 없다면, "cache miss"가 발생합니다.
    3. 이 경우, **메모리 컨트롤러(MC)**는 DRAM에서 데이터를 가져와야 합니다.

4. Huge Page

  • Huge Page는 메모리 관리에서 더 큰 페이지 크기를 사용하는 방식입니다. 예를 들어, 4KB 페이지를 512개 사용하여 2MB의 메모리를 할당할 수 있습니다. Huge Page는 페이지 테이블의 크기를 줄이고 TLB(Translation Lookaside Buffer)의 효율성을 높여 성능을 개선합니다.

5. 프로세스 및 쓰레드 구조

  • 프로세스가 생성될 때, test_struct와 같은 구조체가 만들어집니다. 이 구조체는 프로세스의 정보와 상태를 담고 있습니다.
  • 각 쓰레드는 task_struct를 사용하여 관리됩니다. 이 구조체는 쓰레드의 실행 정보 및 상태를 포함합니다.
  • 하지만 여러 쓰레드가 동일한 프로세스 내에서 실행될 때, 메모리 관리 구조체인 mm_struct를 공유합니다. 이는 모든 쓰레드가 동일한 가상 메모리 공간을 사용하게 함으로써 효율적인 메모리 관리를 가능하게 합니다.

*쓰레드(Thread)는 프로세스 내에서 실행되는 가장 작은 단위로, 프로세스가 수행하는 작업의 흐름을 나타냅니다. 쓰레드는 프로세스의 자원을 공유하며 독립적으로 실행될 수 있습니다. 여러 쓰레드가 동시에 실행됨으로써 멀티태스킹을 구현할 수 있으며, 이를 통해 프로그램의 성능을 향상시킬 수 있습니다.

 

 

  1.  

1. 프로세스 관리 (PM)

  • 프로세스 관리는 운영체제가 프로세스의 생성, 스케줄링, 종료 등을 관리하는 기능입니다.
  • task_struct: 각 프로세스에 대한 정보를 담고 있는 구조체로, 프로세스 ID, 상태, 우선순위, 스케줄링 정보 등을 포함합니다.
  • CFS (Completely Fair Scheduler): Linux의 기본 스케줄러로, 프로세스의 CPU 시간을 공정하게 분배하는 알고리즘입니다. 각 프로세스의 가상 실행 시간을 기반으로 스케줄링을 수행합니다.

2. 메모리 관리 (MM)

  • 가상 메모리 관리: 프로세스가 사용하는 가상 주소 공간을 관리합니다. mm_struct는 가상 메모리 영역(VMA)을 정의하며, 여기에는 스택, 힙, 텍스트 영역이 포함됩니다.
    • Stack VMA: 함수 호출 시 사용하는 스택 메모리 영역.
    • Heap VMA: 동적 메모리 할당을 위한 힙 메모리 영역.
    • Text VMA: 실행 코드가 위치하는 영역.
  • VA-PA 매핑 테이블: 가상 주소를 물리 주소로 변환하기 위한 페이지 테이블을 포함합니다.
  • 물리 메모리 관리:
    • 버디 시스템: 메모리 할당을 효율적으로 관리하는 방법으로, 메모리를 2의 거듭제곱 크기로 분할하여 관리합니다.
    • 페이지 조각 관리: 4KB 크기의 페이지를 기본 단위로 하여 메모리를 관리합니다.

3. 시스템 이벤트

  • 인터럽트: 하드웨어나 소프트웨어가 CPU의 작업을 중단하고 이벤트를 처리하도록 하는 신호입니다.
    • 타이머 인터럽트: 주기적으로 발생하여 프로세스 스케줄링 등을 수행합니다.
    • 네트워크 인터럽트: 네트워크 패킷 수신 시 발생합니다.
  • 예외: 특정 이벤트가 발생했을 때 처리하는 메커니즘입니다.
    • 시스템 호출 (syscall): 사용자 공간에서 커널 공간으로 요청을 전달하는 방법입니다.
    • 페이지 폴트 (page fault): 요청된 페이지가 메모리에 존재하지 않을 때 발생하며, 페이지를 메모리에 로드하는 과정이 필요합니다.

4. I/O 관리

  • 네트워크:
    • L4 (TCP): 전송 계층 프로토콜로 데이터 전송을 담당합니다.
    • L3 (IP): 네트워크 계층 프로토콜로 패킷의 라우팅을 담당합니다.
    • Netfilter (iptables): 패킷 필터링 및 네트워크 주소 변환(NAT)을 위한 프레임워크입니다.
    • L2 (MAC): 데이터 링크 계층에서의 주소 지정 및 프레임 전송을 관리합니다.
  • 디스크:
    • VFS (Virtual File System): 다양한 파일 시스템을 추상화하여 일관된 인터페이스를 제공하는 계층입니다.
    • FS (File System): 파일 시스템의 구현으로, submit bio를 통해 블록 장치에 대한 읽기/쓰기 요청을 처리합니다.
    • 블록 파일 시스템: 물리 디스크 블록을 읽고 쓸 방식을 정의합니다. 예: ext4, xfs, btrfs, f2fs 등.
  • 디바이스 드라이버:
    • 다양한 하드웨어 장치를 운영체제가 사용할 수 있도록 해주는 소프트웨어입니다. 예를 들어, 네트워크 카드, 블루투스 장치, PCI-e 장치 등이 있습니다.

기타: 보안, 도구, 사운드


권한 확인

getfacl hello.txt

 

 

소유자에게는 읽기, 쓰기(6) 권한을 주고, 그룹과 기타 사용자에게는 읽기(4) 권한만 부여

chmod 644 hello.txt

 

 

chmod g-r hello.txt

그룹(g) 권한의 읽기(r) 권한을 제거(-)

 

 

/usr/bin 폴더안에 있는 파일들이 진짜 바이너리파일들만 있을까?

/usr/bin 폴더안에 있는 파일들 중에서 스크립트 파일만 추려내려면?

 

  • LIST=$(ls /usr/bin)
  • echo $LIST
  • for name in $LIST
  • do
  • file $name
  • done
  • for name in $LIST; do file $name; done | grep -v ELF

제시하신 명령어는 LIST 변수에 저장된 파일 목록을 순회하면서 각 파일의 타입을 file 명령어로 확인하고, 그 결과 중에서 ELF 파일을 제외하는 작업을 수행합니다.

  • echo “hello” : 터미널 stdout 출력화면 print
  • cat hello.txt : 파일을 read 해서 stdout 출력
  • awk: column 추출
  • grep: 가로추출: 라인 by 라인 필터링
  • sort: 정렬 → 알파벳, 숫자(-n), KGM -h

패키지

아이폰 → 앱스토어 →앱설치, 삭제, 업데이트

리눅스

  • 패키지관리자 (apt, dnf, yum)을 통해 패키지 설치, 삭제, 업데이트를 할 수있다.
  • 오픈소스라서 자유도가 높다 (기업활용, 지속적발전)

패키지 관리자

  1. High-Level 패키지 관리자:
    • apt, yum, dnf는 고수준 패키지 관리 도구로, 사용자 친화적인 인터페이스를 제공하고, 패키지의 설치, 삭제, 업데이트 등을 쉽게 수행할 수 있도록 도와줍니다.
    • 이 도구들은 내부적으로 저수준 패키지 관리자(rpm, dpkg)를 호출하여 실제 패키지 파일을 처리합니다.
  2. Low-Level 패키지 관리자:
    • rpm(Red Hat Package Manager)과 dpkg(Debian Package)는 저수준 패키지 관리 도구로, 패키지 파일을 직접 설치하거나 관리합니다.
    • 이들은 패키지의 세부 정보를 직접 처리하며, 패키지 정보(이름, 버전 등)를 기반으로 패키지 리스트를 생성합니다.
  3. 패키지 파일:
    • .rpm  .deb 파일은 각각 Red Hat 계열과 Debian 계열의 패키지 형식으로, 윈도우의 설치 파일과 유사합니다.
    • 이 파일들은 패키지 설치 시 사용됩니다.

프로세스와 커널

  1. 프로세스 실행:
    • OS에서 실행 중인 프로세스의 수를 확인하려면 다음 명령어를 사용할 수 있습니다:

      bash

      ps -ef | wc -l
      
  2. 유저 프로세스 vs 커널 프로세스:
    • 유저 프로세스는 사용자 애플리케이션(예: Nginx, MySQL, Tomcat, PostgreSQL)으로, 실제로 사용자가 상호작용하는 프로그램입니다.
    • 커널 프로세스는 시스템 자원을 관리하고, 하드웨어와 상호작용하는 데 필요한 작업을 수행합니다.
  3. 커널 프로세스의 필요성:
    • 커널은 하드웨어와 소프트웨어 간의 인터페이스 역할을 하며, 시스템의 안정성과 보안을 보장합니다.
    • 커널 프로세스는 이벤트 핸들러와 같은 역할을 하여, 시스템 자원을 효율적으로 관리합니다.

인터럽트 처리

  1. 하드 인터럽트(Top-half):
    • 하드웨어 인터럽트가 발생했을 때 즉시 처리되는 부분으로, 빠른 응답이 필요한 작업입니다.
  2. 소프트 인터럽트(Bottom-half):
    • 하드 인터럽트가 발생한 후, 이후에 처리해도 되는 작업을 지연시켜 처리하는 부분입니다.
    • 주로 workqueue, softirq, tasklet을 통해 구현됩니다.

1. mm_struct

  • 목적: 각 프로세스에 대한 메모리 관리 정보를 저장합니다. 커널은 이 구조체를 통해 프로세스의 가상 메모리 공간을 관리합니다.
  • 구성 요소:
    • vma (Virtual Memory Area): 프로세스의 가상 메모리 영역을 나타내는 구조체의 리스트입니다. 각 vma는 특정 메모리 영역(예: 텍스트, 힙, 스택 등)에 대한 정보를 포함합니다.
    • 페이지 테이블: 가상 주소와 물리 주소 간의 매핑 정보를 저장하는 테이블입니다.
    • 메모리 관리 상태: 페이지 폴트 처리 및 메모리 할당 상태를 관리합니다.

2. vm_area_struct

  • 목적: 각 가상 메모리 영역에 대한 정보를 저장하는 자료구조로, 프로세스의 메모리 공간을 세부적으로 관리합니다.
  • 구성 요소:
    • 시작 주소와 끝 주소: 해당 영역의 가상 메모리 주소 범위를 지정합니다.
    • 메모리 접근 권한: 읽기, 쓰기, 실행 권한을 설정합니다.
    • 백킹 저장소: 해당 영역에 대한 데이터가 어떻게 저장되는지를 나타냅니다(예: 파일 매핑, 익명 메모리 등).

메모리 관리 및 페이지 설정

  • 페이지 테이블: 가상 주소(VA)와 물리 주소(PA) 간의 매핑을 관리합니다. 페이지 테이블은 일반적으로 4KB 크기의 페이지 단위로 할당되며, 이로 인해 메모리 사용의 효율성을 높입니다.
  • Huge Page: 큰 페이지를 사용하여 메모리 할당의 오버헤드를 줄입니다. 예를 들어, 2MB 또는 1GB의 큰 페이지를 사용하면, 많은 수의 작은 페이지를 관리하는 것보다 효율적입니다.

메모리 할당과 해제

  • malloc 및 free: 메모리 할당 요청(malloc)이 발생하면 mm_struct에 해당 정보를 기록합니다. 해제 요청(free)이 없으면, 가상 메모리 사용량(vsz)은 계속 증가하게 됩니다.
  • 가상 주소와 물리 주소 연결: 현재는 가상 메모리 주소이지만, VA-PA 연결이 이루어진 후에는 실제로 존재하는 가상 주소로 변환되어 사용됩니다.
  • dnf 란 ? “Dandified YUM” yum (Yellowdog Updater, Modified)의 후속 버전으로, 더 향상된 의존성 해결 알고리즘과 성능 최적화를 제공하고 자동화된 문제 해결기능, 유저 친화적인 기능 등으로 발전된 소프트웨어 패키지 관리자 이다.

패키지 관리 및 의존성

  1. 패키지 저장소 서버 URL 설정
    • 패키지 저장소의 URL은 /etc/ 디렉토리에 설정됩니다. 이곳에서 패키지 관리 도구가 사용할 저장소의 위치를 지정합니다.
  2. 패키지 정보 및 파일
    • 패키지 정보와 관련된 파일은 /var/cache 디렉토리에 저장됩니다. 이곳은 패키지 관리 도구가 다운로드한 패키지 파일의 캐시를 보관하는 위치입니다.
  3. 캐시
    • 캐시는 미리 읽어놓은 데이터로, 패키지 관리 도구가 더 빠르게 작업을 수행할 수 있도록 도와줍니다.
  4. 의존성 패키지
    • apt, yum, dnf와 같은 패키지 관리 도구는 소프트웨어 설치 시 필요한 의존성 패키지를 자동으로 관리합니다.
  5. 패키지 삭제 시 의존성 관리
    • 예를 들어, httpd 패키지를 삭제할 경우, 해당 패키지에 의존하는 C, D 패키지는 자동으로 삭제되지 않습니다. 이는 의존성 패키지가 다른 소프트웨어에서 사용될 수 있기 때문입니다.
    • 그러나 apt autoremove 명령어를 사용하면 더 이상 사용되지 않는 의존성 패키지를 정리할 수 있습니다. 이 명령은 시스템에서 필요 없는 패키지를 자동으로 찾아 삭제합니다.
  6. 패키지 설치 예시
    • nginx 설치 시 A, B, C, D 의존성 패키지가 설치됩니다.
    • nodejs 설치 시 C, D 의존성 패키지가 설치됩니다.
    • httpd 설치 시 F, G, C, D 의존성 패키지가 설치됩니다.

내가 설치한것중에 mariadb 관련 뭐가 있지?

패키지정보(이름, 버전)만 가져오는 것 : yum check-update / apt update

패키지 버전 업그레이드 : yum update / apt upgrade

→ 백그라운드 업그레이드가 진행될 수 있다.

ls /boot

grep -v “#”

**`lsb_release -a` 명령어는 리눅스 시스템에서 설치된 배포판의 버전 정보를 출력하는 데 사용됩니다.**

패키지 저장소 서버 URL 설정파일

  • /etc/apt/sources.list
  • /etc/yum.repo.d/*.repo

패키지 정보(이름, 버전), 파일(.rpm, .deb)

  • /var/cache /yum

APT 패키지 관리 시스템

  1. APT 내부 구성
    • apt는 apt-get과 apt-cache를 내부적으로 사용하여 패키지를 관리합니다. apt-get은 패키지 설치, 제거 등의 작업을 수행하며, apt-cache는 패키지 정보 조회를 담당합니다.
  2. 패키지 정보 저장
    • 패키지 정보는 /var/lib/apt/lists/ 디렉토리에 저장됩니다. 이 폴더가 비어 있으면 현재 리눅스 시스템에서 패키지 정보(이름, 버전)가 없으므로 apt search 명령어를 사용할 수 없습니다.
    • 그러나 이미 설치된 패키지에 대한 정보는 여전히 존재하므로, 설치된 패키지에 대한 정보는 조회할 수 있습니다.
  3. 패키지 저장소와 정보
    • 패키지 정보는 패키지 저장소(repo) 서버로부터 수집됩니다. 이 정보에는 패키지의 이름, 버전 등이 포함됩니다.
  4. 패키지 조회 과정
    • 사용자가 apt search 명령어를 입력하면, APT는 저장소에서 패키지 정보를 조회하여 사용자가 요청한 패키지를 검색합니다.
  5. 패키지 파일 다운로드
    • 패키지 파일(.deb)은 임시로 /var/cache/apt/archives/에 다운로드됩니다.
    • 이 위치에 저장된 .deb 파일은 설치가 완료된 후 dpkg를 통해 처리됩니다.
  6. 패키지 설치 후 처리
    • 패키지가 성공적으로 설치되면, APT는 /var/cache/apt/archives/에 저장된 .deb 파일들을 제거하여 공간을 절약합니다.

정리

패키지 설치 실패 원인

  1. 외부망 및 DNS 설정 문제
    • 외부망 연결 문제: 폐쇄망 환경에서 외부망에 연결되지 않으면 패키지 공식 서버로부터 데이터를 다운로드할 수 없습니다.
    • DNS 설정 문제: DNS 설정이 잘못되면 도메인 이름을 IP 주소로 변환할 수 없어 패키지 저장소에 접근하지 못합니다. 예를 들어, ping 8.8.8.8은 성공하지만 ping www.google.com이 실패하는 경우 DNS 설정이 잘못된 것입니다.
  2. 패키지 저장소 URL 설정 문제
    • 패키지 저장소의 URL 설정에 문제가 있을 수 있습니다. URL이 만료되었거나 수정된 경우에도 패키지 정보를 가져올 수 없습니다.
    • 패키지 저장소의 설정 파일은 /etc/apt/sources.list (APT) 또는 /etc/yum/repo.d/*.repo (YUM)에서 확인할 수 있습니다.
  3. 패키지 정보 저장 경로
    • 패키지 정보는 패키지 저장소 서버로부터 가져와 /var/cache 또는 /var/lib/lists에 저장됩니다. 이 정보가 없으면 패키지 조회 및 다운로드가 불가능합니다.
  4. 패키지 조회 및 다운로드 과정
    • 패키지 조회(apt search 또는 yum search)를 통해 패키지 정보를 확인합니다. 이 과정에서 문제가 발생하면 패키지를 찾을 수 없습니다.
    • 패키지 파일은 .rpm (YUM) 또는 .deb (APT) 형식으로 다운로드됩니다.
  5. 패키지 설치 과정
    • 다운로드된 패키지 파일은 rpm 또는 dpkg를 통해 설치됩니다. 이 과정에서 오류가 발생할 수 있으며, 패키지 설치 후 임시로 저장된 패키지 파일들은 기본적으로 삭제됩니다.

 

리눅스 문제해결 접근방법과 전략

 

에러 메시지 처리 및 문제 해결 프로세스

  1. 에러 메시지
    • 예시: No such file or directory
    • 이 메시지는 시스템이 요청한 파일이나 디렉토리를 찾을 수 없음을 의미합니다.
  2. 문제 정의
    • 문제는 목표와 현재 상태 간의 차이(Gap)입니다. 예를 들어, 특정 파일에 접근해야 하는데 그 파일이 없어서 작업이 중단되는 상황입니다.
  3. 원인 분석
    • 동작 과정이나 절차를 나열하고 관찰하여 문제의 근본 원인(root cause)을 찾습니다.
    • 예를 들어, 우분투 버전을 업그레이드한 후 리드 성능이 30% 느려졌다면, 다음과 같은 과정을 통해 진단할 수 있습니다:
      • 원래 리드 성능이 어떻게 이루어지는지 분석합니다.
      • 시스템 아키텍처를 고려하여 유저 → 커널(VFS → syscall → FS → submit_bio → Block) 경로를 추적합니다.
      • smartctl 등을 사용하여 디스크 상태를 점검합니다.
      • 펌웨어나 드라이버가 이전보다 성능이 떨어질 수 있으므로, 이를 확인하고 필요 시 펌웨어를 업그레이드해야 할 수 있습니다.
  4. 성능 관련 고려 사항
    • 유저가 10바이트를 리드 요청했더라도 디스크가 느릴 경우, 예상되는 블록을 미리 읽어오는 방식(read-ahead)이 적용될 수 있습니다.
    • 미리 읽기 사이즈가 크면 성능이 좋아질 수 있습니다. 예를 들어, 넷플릭스와 같은 영상 스트리밍 서비스에서는 큰 데이터 블록을 미리 읽어와 버퍼링을 줄이는 방법이 효과적입니다.
  5. 해결책 적용
    • 다양한 해결 방식을 적용하여 문제를 해결합니다.
    • 해결 과정에 대한 기록과 메모를 남기는 것이 중요합니다.
    • 적용한 해결 방식의 평가를 통해 임시방편적인지, 근본적인 해결 방법인지 분석합니다.
    • 예를 들어, 펌웨어 업데이트가 효과적이었다면, 이는 근본적인 해결책으로 평가할 수 있습니다. 반면, 임시 방편적인 조치일 경우 추가적인 조치가 필요할 수 있습니다.

리눅스 명령어 및 파일 관련 오류

쉘(sh, bash, zsh, …) → 명령어에 반응하는 프로그램

사용자 → 명령어를 입력 → bash → PATH 변수를 확인 → 여러개의 폴더 경로정보를 알 수 있다. → 폴더들을 전부 순회하면서 해당 명령어의 문자열이 일치하는 바이너리 실행파일을 찾는다. → 실행한다.

PATH=

PATH 경로 관련

주석을 바꾸면 file hello 에서 형식이 구분이 된다.

~/.bashrc 파일의마지막 라인에 PATH=$PATH:/home/realinux 를 추가하면 새롭게 열린 bash/shell 에서도 PATH 정보를 확인해서 home/realinux 를 찾을 수있다.

터미널생성 → bash 새롭게 ㅣㄹ행 → 최초실행시 ~/.bashrc 를 세팅한다.

기존 터미널에서 ~/.bashrc 를 수정했다면 source ~/.bashrc 명령어를 하면 새로운 터미널을 안켜도 현재 터미널에서 설정이 적용된다.

~/.bashrc 파일 마지막 라인에 아래 라인을 적고

alias test_ls=’ls -l —color=auto’

저장후에 source ~/.bashrc 설정 적용 하고 alias 명령어를 통해서 설정적용결과 확인하고 test_ls 명령어 입력해보기

아래의 명령어 맨 밑에 사진과 같이 입력을 하면 새로운 터미널을 켰을떄도 인석을 함

nano ~/.bashrc

alias grep=” 를 적고 저장후에

source ~/.bashrc 설정 적용하고

ps -ef | grep kwroker 가 정상동작 안되는 상황을 만들어보자

bash 쉘에서 명령어를 입력했을떄 처리되는 과정:

  1. alias 별칭인지?
  2. bash 쉘 내장명령어 인지? → compgen -b (내장명령어만 입력할 수 있다)
  3. bash 쉘이 아닌 외부명령어를 찾자 → PATH 변수를 참조해서 폴더를 순회하고 없으면 command not found 나옴
300x250
320x100

서버엔지니어(주로 리눅스.bash, python ⇒ 세팅,운영,문제해결,관리) vs 서버 개발자(주로 Java, Python 코딩)

리눅스에서 익혀야할 기초

  1. 기본 명령어 → 파일, 폴더, 편집, 다운로드, 설치 …
    1. 제어 명령어 → nginx, tomcat, mysql, postgresql, docker, …
    2. 조회 명령어 → 모니터링, 추적, 상태 확인
  2. 리눅스 구조 → cpu, ram, disk, net 관리 매커니즘
    1. 장기적으로 공부해야함 → 문제해결능력 기르는게 핵심
    2. Depth 단계별 학습해야함. 내 레벨은 1인데 레벨 10 지식은 혼란만 줌
  3. 리눅스 역할 → App 관리 / HW 관리(CPU, RAM, DISK, NET)
  4. 리눅스 란 ? → 시스템 이벤트 핸들러 이다!!
  5. mysql (유저) → 디스크 쓸거야!! → 어덯게 리눅스에게 요청 ?
    1. 시스템 콜(open, read, write)
  6. Core:
    1. PM : 프로세스 관리
    2. MM : 메모리 관리 → 가상메모리 매커니즘을 사용
    3. 시스템이벤트(인터럽트 예외) → 핸들링 !!
      1. Entry 진입점 : 커널함수가 호출되는 지점
  7. I/O :
    1. 네트워크 : L4 : TCP / L3 : IP / L2 : MAC
      1. nmap : 특정 서버를 조회하여 포트 등을 확인할 수 있음
    2. 디스크 : VFS(virtual file sys) / FS ⇒ submit_bio ⇒ Block
    3. 디바이스 드라이버
  8. 파일시스템 이란 ?
    1. 물리 디스크 블록을 어떻게 read/write할지 전략, 규칙
    2. ext4, xfs, btrfs, f2fs, …
    3. 디바이스 드라이버: 네트워크, PCI-e, 블루투스
  9. 기타 :
    1. 보안, 도구, 사운드 …
  10. 리눅스의 실체
    1. C코드 → 10만개 함수
    2. 300~400개 함수 → 유저호출가능 → 시스템콜함수(open, read, write)
    3. 컴파일결과 → vmlinux (virtual memory) → vmlinuz

GUI (Graphic User Interface)

  • 장점: 초보 유저가 사용하기 쉽다.
  • 단점: 느리다, 자원소모가 크다, 자동화가 불편하다(작업능률)

CLI (Command Line Interface)

  • 장점: 빠르다, 자원소모가 적다,자동화가 좋다(세부적이고 다양한 기능활용가능)
  • 단점: 명령어 숙지가 필요, 사용초기 진입장벽

리눅스 실습 기초 명령어

whatis cp 한줄로 명령이 뭔지 알래

man cp cp에 대해 알아보고 싶어

/r 내가 찾고 싶은 단어를 검색

n 스크롤 아래로

shift + n 스크롤 위로

파일의 메타정보 → inode 아이노드

물리 디스크 블록 → 슈퍼블록, 아이노드블록, 데이터블록

Access: 2024-08-22 04:26:35.685876192 +0000 (read 했을때) Modify: 2024-08-22 04:26:13.831633909 +0000 (내용이 변경되었을때) Change: 2024-08-22 04:26:46.810999529 +0000 (권한만 변경됌)

어떤 특정 실행파일이 어떤 라이브러리를 사용하는지 알아내는 명령어

ldd /bin/ls

stmbolic 링크를 사용하면 원본파일만 교체를 하면 편하다.

프로세스가 오픈 할 수 있는 파일의 개수

task_struct

→ fd [0] = stdin → tty →터미널,콘소리 입출력환경

[1]  = stdout → tty

[2] = stderr → tty

read(0,….) → scanf

write(1, …) → printf

write(2, …) → 에러메시지 출력시

2>/dev/null

find / -name "aaa” 입력

에러가 송출됌

find / -name "aaa" 2>/dev/null 입력

[2] = stderr → tty /dev/null (갈아끼워져서 에러가 생략)

그냥 묶기만 함 tar

압축함 - gz

/ 폴더가 최상위 폴더이고 run 폴더는 / 폴더의 자식폴더인데

자식폴더인 var 폴더나 usr 폴더는 /dev/vda1 디스크에 귀속되는데 왜 자식 폴더인 run은 ramdisk 에만 적용되는가?

캐시 : 미리 읽어 놓은 데이터 - 지워도 문제가없다

/usr → apt,dnf,yum 패키지 관리자 → 설치 기본경로

/etc → 설정파일

/run → 램디스크에 위치 → runtime 임시적으로 저장하는 파일 (mysql.sock, docker.sock)

No such file or directory : mysqld.sock → 껏다 키면 재생성됌

/mnt

/media → 새로운 디스크 장착(mount) 전용 폴더

/proc

/sys

/dev → 특수폴더이다 → 물리적으로 커널 메모리(변수,함수)에 장착된다.

VFS

/usr/bin 패키지관리자가 직접 관리 (배포판에 따라 달라질 수 있는 곳)

/usr/sbin

/usr/local → 소스코드 받아서 컴파일 해서 설치할때 쓰는 경로

/usr/local/sbin

/bin → 기초 명령어 ls, mv

/sbin

df -h / → disk 용량 확

ps -ef | wc -l 명령은 리눅스 또는 유닉스 시스템에서 현재 실행 중인 프로세스의 수를 계산

/usr/bin 폴더랑 /bin 폴더안에있는 모든 바이너리파일을 찾아서 ldd 명령어를 입력하면 설치된 모든 실행파일들이 사용하는 라이브러리 목록이 나온다. 중복되는걸 카운트해서 랭킹을 세우고 가장많이 쓰는 라이브러리 top 10을 찾을 수 있다.

root 계정에서 빠져나오기

sudo yum install -y vim

vim hello.txt

I —— insert

ESC —— 삽입 모드에서 나감

:q! —- 밖으로 나감

ctrl + z ——- stop

jobs —- 내가 한짓 확인

fg —— 다시 복구

내가 사용하고 있는 쉘

ps -ef | grep $$

“>” 덮어쓰기

“>>” 엎어 올리기

반복문으로 ls 불러오기

touch new.txt 임의의 텍스트파일 생성

locate new.txt (new.txt가 어디있는지 확인)

updatedb 를 해야 위치를 찾을 수 있다.

find ./ -name test.txt → find 명령어로는 바로 찾는다.

type d와 type f는 리눅스 또는 유닉스 시스템에서 파일 또는 디렉토리의 유형을 확인하는 명령어

대문자와 소문자 구분을 하기 때문에 구분안하고 모든 것을 뽑고 싶으면 -i 추가

-r = recursive

그냥 error 적는 것 보다 err 적으면 범위가 더 넓게 다 나옴

err = Errror + error

sudo yum install the_silver_searcher

cd /var/log

sudo ag err

ag err는 "The Silver Searcher"라는 텍스트 검색 도구를 사용하여 "err"라는 문자열을 포함하는 파일을 검색하는 명령입니다.

현재 리눅스에서 몇개의 프로세스가 구동중인지

ps -ef | wc -l

ps -ef: 현재 시스템에서 실행 중인 모든 프로세스를 나열합니다. -e: 모든 프로세스를 표시합니다. -f: 프로세스의 전체 형식을 보여줍니다.

ps -ef | head -5 —— 출력결과의 최상단부터 5라인을 필터링해 본다.

ps -ef | tail -5 —— 마지막 5라인 확인

 


터미널1 : sudo tail -f /var/log/yum.log

터미널2: sudo yum install -y httpd

이렇게 돌릴 경우 터미널1에서 이벤트가 나오는가 ?

터미널1 업데이트가 되는 것을 확인할 수 있음

 


ls -l / | awk -F " " '{print $2}’

세로줄 두번쨰칸을 뽑겠다.

root 가 구분자 역할을 해서 기준으로 3

sort — 문자열로 구분

sort -n (number) 숫자로 구분

sort -r (reverse) 거꾸로

du 를 통해서

human readable 하게


권한

읽기 (r: read)

쓰기(w: write)

실행(x: execute)

  1. 내 계정확인 whoami
  2. 파일의 권한 → owner 인 경우 / group / other 중 내가 어디에 속해 있는지 찾는다.

getfacl /var/log/messages

messages의 권한 설정을 확인하고 내 계정과 비교

sudo chmod o+r /var/log/messages

getfacl /var/log/messages

cat /var/log/messages

300x250
320x100

Pwntools

Pwntools는 파이썬으로 작성된 CTF(해킹 대회)와 익스플로잇 개발을 위한 도구 모음입니다. 이 라이브러리는 다양한 익스플로잇 작업을 쉽게 수행할 수 있도록 돕는 여러 기능을 제공합니다.

 

Stack 

스택은 거꾸로 자란다.

힙(Heap)은 컴퓨터 과학에서 동적 메모리 할당을 위한 데이터 구조 및 메모리 영역을 의미합니다.

buffer

 

기본 세팅 

 

 

Lucky draw 정적 분석 실습

Stack over flow

"Stack Overflow"는 일반적으로 프로그램이 스택 메모리를 초과하여 발생하는 오류입니다

 

  • $ wget {binary address}
  • # 바이너리에 실행 권한 부여
  • $ chmod +x lucky_draw
  • $ ./lucky_draw

IDA를 사용하여 lucky_draw 실행 후 바이너리 정적 분석

 

바이너리 파일을 실행시켜 문제가 어떻게 돌아가는지 점검을 해보니 문자를 넣을 수 있는 구간은 1번 add 기능과 3번 winner기능인 것으로 확인되었다.

IDA에서 add 함수부터 확인 시작

버퍼의 크기는 40 

read 크기는 0x860 (2144 size) 를 받는다

-> stack over flow 상황

 

1번 기능에 아무문자나 40개보다 많이  stack over flow 가 발생하는지 확인 -> 에러 발생

 

두번째 문자를 넣을 수 있는 곳 winner 기능 확인

버퍼의 크기는 24

read 크기는 0x98 를 받는다

-> stack over flow 상황

 

3번 기능에 아무문자나 24개보다 많이 넣어서 stack over flow 가 발생하는지 확인 -> 1번 기능과 동일하게 에러 발생

 

stack over flow 는 이런 상황에서 발생

 

 


 

Canary ( = 같은 기능을 수행 NX,malloc)

 

 

  • 스택 오버플로우 보호 완화 기법(mitigation)
  • 함수 호출 시 카나리 값을 스택 프레임의 최상단에 저장, 함수 종료 시 스택 오버플로우를 검사

 

Master Canary

  • 로컬 카나리는 함수 종료 시 검사를 위해 마스터 카나리와 비교 -> 값이 다르면 스택오버플로우가 발생했다고 판단하고 프로그램을 비정상 종료시킴 (stack smashing detected error 발생)
  • 일반적으로 마스터 카나리는 전역 공간에 저장되나 쓰레드에서는 마스터 카나리가 스택 영역에 저장

 

그렇다면 카나리를 우회하는 법이 있을까?

만약 카나리의 값과 마스터카나리값을 동일한 문자로 덮어버린다면 우회할 수 있다.

 

 

 

buffer size 0x28 보다 큰 임의의 값을 넣어준다 -> 0x100

 

 

앞에 p. 는 Pwntools로 분석을 쉽게 하기 위한 매크로를 만들고 있다고 생각하면 됌

sendlineafter설명

 

코드를 작성한 이후 테스트를 하고 싶으면 vscode와 연결되어 있는 터미널에

python3 {file name}  이런식으로 스크립트를 실행해주면 자동으로 넘어가서 테스트를 쉽게 할 수 있다.

버퍼오버플로우가 발생하고 카나리가 프로그램을 자동으로 종료시켜주는 것을 확인 할 수 있다.

 

로컬 카나리까지만 덮으면 전역카나리와 비교 후 값이 달라서 에러가 나는 것 확인

 

GDB를 통한 디버깅

  • tmux
  • python3 {file name} GDB

*GDB: 리눅스(C, C++. 바이너리) 디버거

 

break point 를 걸고 버퍼를 확인하는 작업을 GDB 에서 할 수 있다.

 

GDB에서 확인해야할 사항: 로컬 카나리 (stack frame 에 있는 것) ,마스터 카나리 (실제 원본 카나리)

 

x/gx $rbp-8 명령어를 통해서 로컬 카나리 확인이 가능하다.

 

stack frame point 에 rbp 가 위치하는데 그곳에서 8만큼 떨어진 위치에 로컬 카나리가 위치한다. 

그렇기 떄문에 rbp-8 을 하는 것

 

로컬카나리 - rsi 를 해서 rsi의 랭스가 0x28인것을 확인

다시말해 rsi 는 buffer에 위치해서 0x28만큼 떨어져있다.

 

 

마스터카나리는 fs_base에 저장이 되어있다.아래와같이 얼만큼 떨어져있는지 확인가능

Buffer ~ Master Canary 오프셋 확인

 

 

 

 

 

 

 

 

로컬카나리와 전역카나리 모두를 같은 문자로 덮어서 우회 시도

마스터카나리까지 덮으려면 얼마나 문자를 적어야할지 계산을 해야함

Buffer ~ Master Canary 오프셋 848이니까 그것보다 큰 850을 넣어서 테스트 

테스트 continue 하면

첫번째 break point에서 죽음 

 

왜냐면, 그 사이에 덮어서는 안되는 어떠한 주소를 임의의 문자로 같이 덮어버림 -> 그래서 비교하는 로직까지도 도착하지 못하고 그냥 죽어버림

그래서 위치까지 파악하면서 계산을 하고 발생한 크러쉬를 우회해서 접근해야함

memo()

Another bof function

리턴 주소를 조작하여 반복해서 buffer overflow를 유발할 수 있음

 

Shellcode는 일반적으로 버퍼 오버플로우와 같은 취약점을 이용하여 원격 코드 실행을 목표로 하는 작은 코드 조각을 의미합니다. 이 코드는 주로 쉘을 실행하기 위해 설계되며, 공격자가 시스템에서 명령을 실행할 수 있도록 해줍니다.

 

최근에는 카나리와 비슷한 동작을 하는 NX가 Shellcode 공격을 다 막는다.

그렇기 때문에 나온 기법이 ROP 이다.

 

 

ROP (Return Oriented Programming)

  • ROP는 주로 실행 방지 메커니즘(NX 비트 등)을 우회하기 위해 사용됩니다. 이 기술은 악의적인 코드를 직접 삽입하는 대신, 기존의 실행 가능한 코드 조각(“gadget”)을 사용하여 원하는 동작을 수행합니다.
  • 스택 주소는 실행 할 수가 없는데 코드영역은 CPU가 실행시켜야 할 코드가 들어가있으니 리턴할떄 쉘코드를 스택에 쓰고 스택으로가는게 아니라 코드영역으로 가면 어떨까 하는것
  • Idea: 바이너리에 존재하는 코드를 재활용
  • “Gadget”: pop rdi ; pop rsi ; ret
  • 스택을 공격자가 조작한 입력으로 overwrite
  • “gadget”을 연결해 프로그램 실행 흐름 조작

 

 

STAGE2

 

기존에 데이터 영역에 있던 got 이라는 섹션에서 특정 라이브러리 함수에 있는 주소를 하나 유추하고 싶음

ASLR 이 작동되고있기 때문에 정확한 위치 파악을 위해 임의의 주소를 하나 빼오는 것 스크립트에서는 read 오프셋을 빼오려고 시도 이러한 방식을 leak 이라고 한다.

 

***ASLR (Address Space Layout Randomization)**는 시스템의 메모리 주소 공간의 배치를 무작위로 변경하여 보안을 강화하는 기법입니다. 주로 버퍼 오버플로우와 같은 공격을 방어하기 위해 사용됩니다

 

다시말해, 정상적 메모리 값 하나 빼와서 거기서 실제 주소를 계산해서 라이브러리 베이스의 주소를 찾는다.

-> 어느 위치에 메모리가 어디에 올라가 있는지를 파악할 수 있다.

 

STAGE3

ROP call 을 진행

bin/shell 과 특정프로세스를 만들어주는 execve 을 call 해서 빈쉘을 열어준다

스텍 포인터를 맞춰주고 rop를 돌려보면 결론적으로 실행되는 내용은 쉘이 떨어진다.

 

*** execve는 Unix 및 Unix 계열 운영 체제에서 사용되는 시스템 호출로, 새로운 프로세스를 실행하는 데 사용됩니다. 이 시스템 호출은 주어진 프로그램을 현재 프로세스의 메모리 공간에서 실행하기 위해 사용되며, 기존 프로세스의 내용을 대체합니다.


NOTE

Use After Free

댕글링 포인터 (Dangling pointer) 

  • 해제된 영역의 포인터를 가리키고 있는 포인터

 

note.c 파일분석

 

 

excercise 4.1

 

아래와 같이 4가지 기능을 구현할 수 있다.

 

설명예시

    def write(self, idx: int, script: bytes, emoj: int):
        self._menu(1)
        self.conn.sendlineafter(b"index(1 ~ 16): ", str(idx).encode())  // index(1~16) 입력받는 출력이 나오면 입력값 idx 를 받는다
        self.conn.sendlineafter(b"script: ", script)  // script 입력받는 출력이 나오면 시크립트를 작성한다.
        self.conn.sendlineafter(b">>> ", str(emoj).encode())  // >>> 입력받는 출력이 나오면 앞에 이모지를 선택한다.

 

DEBUG 옵션을 추가하여 분석을 하면 무엇을 주고 받는지 확인할 수 있다.

 

 

취약점이 어디서 발생하는지 파악단계

  • 1번에 happy를 write 1번을 read했는데 happy가 잘 나옴
  • erase 로 1번 happy를 지웠다. (1번은 free가 되서 다시 할당할 수 있도록 운영체제에 돌아가야함)
  • 2번에 sad를 write read 하서 1번을 read했는데 sad가 나옴 (1번은 다 지워져있어야 정상아닌가?) 

댕글링포인터와 관련이 있다.

 

이미 해제된 포인터인데 그 값을 계속해서 가지고 있기 때문에 1번으로 다시 읽어도 읽을 수 있는데 심지어 1번에 새드가 저장되어있고 2번해도 새드가 잘 나온다.

 

이것이 USE AFTER FREE 취약점 

 

 

 

 

  • tmux
  • python3 example_04_b.py GDB
  • script 의 break point 를 만들어놈
  • c 할때마다 write, read, 순으로 걸림
  • write A 를 8개, Happy 
  • vis (vis는 Vi 모드에서 작동하는 텍스트 편집기로 힙의 구조를 확인, 분석한다)

"vis" command in gdb at each breakpoint to visualize the heap layout.

 

 

코드 분석

위의 USE AFTER FREE 취약점  스택구조 참고


Shellcoding Test

 

  • $ wget {binary address}
  • # 바이너리에 실행 권한 부여
  • $ chmod +x shellcoding_test
  • $ ./shellcoding_test

Seccomp

  • 리눅스 커널 샌드박스 보안 기능
  • 프로그램을 보호된 영역에서 동작해 시스템이 조작되는 것을 방지
  • 프로세스가 사용할 수 있는 시스템 콜을 제한

seccomp tools로 seccomp 정책 확인 가능

  • $ sudo apt install gcc ruby-dev gem
  • $ sudo gem install seccomp-tools
  • $ seccomp-tools dump ./shellcoding_test

 

0x40000000 이하는 모두 kill 한다.

 

x86_64 Assembly

 

Timing based side channel

 

 

 

정답

아래와 같은 shellcode를 통해서 한 문자열씩 비교해가면서 flag 를 추출할 수 있다.

 

 


시험

PPT 강조표시되어있는 내용

stack over flow

  • Canary

스택 오버플로우 보호 완화기법

  • ROP 는 어떨때 사용가능?

nx가 걸려잇어서 쉘코드를 실행하지 못하게 . 그래서 사용하는 기법

Note

heap → danglin pointer 를 통해서 발생하는 취약점

  • Use After Free
  • Seccomp

프로세스가 사용할 수 있는 시스템 콜을 제한하는 샌드박스 보안 기능

(메모리보호기능은 아니고 샌드박스 보안기능임)

  • Timing-based Side channel

실행시간을 비교한다

정상적일떄는

같은값이면 계속 본다.

정상작동하는지 시간을 비교한다.

 

 

300x250
320x100

멀웨어 분석 실습

 

base64

  • base64는 이진 데이터를 ASCII 문자로 인코딩하는 방법

 

인코딩 vs 암호화 차이점

  • (인코딩은 쉽게 여러 웹사이트에 있는 디코딩을 통해서 복원이 가능하지만, 암호화는 복원을 위한 암호화 키가 필요)
  • 인코딩은 데이터의 형식을 변경하여 저장하거나 전송하기 쉽게 만드는 것이며, 쉽게 복원할 수 있습니다. 보안 목적이 아닙니다.
  • 암호화는 데이터를 보호하기 위한 방법으로, 권한이 없는 사용자가 읽지 못하도록 변환하며, 복원하려면 암호화 키가 필요합니다. 보안 목적이 있습니다.

eml_analysis 분석 실습

 

파일을 열면 아래와 같이 알수없는 글씨가 나오는 것을 확인할 수 있습니다.

 

 

CyberChef는 데이터 변환 및 조작을 위한 웹 기반 도구로, 다양한 인코딩, 디코딩, 암호화, 해시 생성, 포맷 변환 등의 기능을 제공

https://gchq.github.io/CyberChef/  

 

위의 사이트를 이용해서 암호화되어 있는 텍스트를 붙여넣기 + From Base64 클릭

아래와 같이 복원된 텍스트를 확인 할 수 있다.

 

Output을 보기 쉽게 텍스트 파일에 옮기고 확인한 결과 

첨부파일이 존재한다는 것을 식별하였다.

 

 

onlineform.html 파일이 첨부가 되어 있는 것을 아래와 같이 식별

 

이메일의 아랫 부분 암호화된 파일도 똑같은 과정을 통해 복호화(디코딩) 진행

 

아래와 같이 스크립트가 출력이 되는 것을 확인

 

숫자 중간 중간 %는 스페이스의 역할을 하는 것으로 추정된다.

메모장에 옮긴 파일의 %를 스페이스로 모두 대체한다.

 

그 이후, Hxd 를 통해 분석 시작

*HxD는 이진 파일 편집기이자 헥스 에디터로, 파일의 내용을 헥사(16진수) 형식으로 보고 편집할 수 있는 소프트웨어입니다. 주로 데이터 복구, 바이너리 파일 분석, 포렌식, 프로그래밍 및 디버깅 등의 작업에 사용됩니다.

 

 

이와같은 방식으로 이메일속 멀웨어를 분석할 수있음.

 

 

참고자료

  • CVE or 한글 CVE (이글루나 안랩에 올라와 있는 공통 취약점을 파악 할 수있음)
  • PostScript는 주로 프린터와 그래픽 디스플레이 용도로 사용되는 페이지 설명 언어입니다. 이 기술은 그래픽과 텍스트의 출력 형식을 정의하는 데 사용되지만, 악성코드가 PostScript를 통해 구현될 수 있는 가능성도 있습니다.
  • 한글 파일 내에서 임의의 코드를 실행할 수 있는 스크립트는 일반적으로 매크로 또는 스크립트 언어를 사용하여 작성됩니다. 예를 들어, 한글 프로그램에서는 HWP 파일 내에 매크로를 삽입하여 특정 작업을 자동화하거나 사용자 정의 기능을 추가할 수 있습니다.
  • OLE 파일은 다양한 데이터를 하나의 파일 내에 효과적으로 포함하고 연결할 수 있는 유용한 방식입니다. 이 기술을 활용하면 문서의 가독성과 기능성을 높일 수 있습니다.

 


hwp_analysis 분석 실습

 

주어진 파일의 압축을 푼다.

'코로나바이러스 대응 긴급 조회' 파일을 연결프로그램으로 반디집을 클릭해서 열게 되면 아래와 같은 창을 볼 수 있다.

 

*반디집은 다양한 파일 압축 및 해제 기능을 지원하는 프로그램으로, 여러 가지 파일 형식을 처리할 수 있습니다

 

의심스러운 파일을 찾아서 매모장으로 열음

 

HxD에 붙여넣기

 

오른쪽 디코드 된 부분을 메모장으로 가져와서 분석한다.

 

이와같은 방법을 통해 hwp 파일을 분석할 수 있다.

 

발전한 해킹기법

  • 요즘 해커들은 사용자의 의심에서 벗어나기 위하여 일정기간동안 바이러스 파일이 실행되지 않게 실행을 잠깐 멈춰놓고 사용자가 의심하지 않을때쯤 프로세스를 실행시켜 공격한다. 
  • 해커는 사용자의 설정 영역 일부를 읽어 현재 가상환경인지 local환경에서 프로그램이 실행되는지 확인을 하고 실행여부를 조정할 수 있다.

분석실습 (실행환경 Ubuntu 22.4 )

 

GDB

GDB는 GNU Debugger의 약자로, 프로그램의 디버깅을 위해 사용되는 강력한 도구입니다. 주로 C, C++, Fortran 등의 언어로 작성된 프로그램을 디버깅하는 데 사용됩니다.

 

초기환경 세팅

 

  • sudo apt update  // 이 명령어는 패키지 목록을 업데이트합니다. 즉, 시스템이 사용하고 있는 소프트웨어 저장소에서 최신 패키지 정보를 가져옵니다.
  • sudo apt install gdb  // GDB를 시스템에 설치합니다. apt는 패키지 관리 도구로, install 옵션은 지정한 패키지를 설치하는 기능을 수행합니다.
  • 주어진 파일 다운
  • sudo apt install unzip  // unzip 명령어는 Linux 시스템에서 unzip 패키지를 설치하기 위한 명령어입니다. 각 부분에 대한 설명은 다음과 같습니다.
  • unzip Handson_dist.zip
  • shell chmod 755 ./handson5 // handson5 파일의 권한을 소유자에게 읽기, 쓰기, 실행 권한을 부여하고, 그룹 및 다른 사용자에게는 읽기 및 실행 권한을 부여합니다.
  • gdb -q handson5  // GDB를 조용한 모드로 실행하여 handson5 프로그램을 디버깅합니다.
  • set disassembly-flavor intel  // GDB에서 어셈블리 코드를 Intel 구문으로 출력하도록 설정합니다.
  • info func  // 현재 디버깅 중인 프로그램 내의 함수 목록을 표시합니다.(우리가 분석해야할 대상확인)

 

  • disassemble main

 

  • run

 

  • x/4gx $rdi // 핵스로 나타내라

 

x/s $rdi // 문자로 나타내라 (내가 사전에 입력한 숫자가 나오는 것을 확인할 수 있다.)

 

n or s 동작이 동일하다.

이 다음의 코드가 실행이 된다.

n : next step 다음에 있는 줄을 실행해라 라는 의미 ( 어느 주소로 뛰든 예를 들어 call 안에 함수들을 한줄로 보고 한줄로 실행을 시키고 다음으로 넘어감)

s : step into ( 예를 들어 call 이 함수의 주소 1080 주소 안으로 한바퀴가 들어가게 된다.)

 

 

Breakpoint 설정하는법 (예시) - 1, 2, 3 이런식으로 순서대로 설정이 된다.

b *main+118

Breakpoint 를 지우는 법

delete 1 or 2 or 3

내가 설정한 포인트를 하나씩 지울 수 있음

info breakpoints 를 통해서 내가 가지고 있는 브레이크포인트를 확인할 수 있음.

 

기드라에서 코드 분석한 내용을 바탕으로

r 1000 982 를 각 인자에 임의로 집어넣어서 Done 표시를 나타낸다 (전날 자료 참고)

 

 

결론, breakpoint를 활용하여 코드를 쪼개보며 분석을 한다.

 


IDA Freeware

  • 바이너리를 역으로 분석해주는 툴 / 프리웨어 버젼으로 다운

SSH

  • 윈도우 상에서 shell 을 연결할 수 있게 해서 가상환경에서 명령어를 동작할 수 있게 한 명령어

$ ssh-keygen

  • Enter 키를 세 번 눌러 기본 설정을 사용합니다. 이렇게 하면 ssh 키 쌍이 생성됩니다

curl

  • 데이터 전송을 위한 명령줄 도구로, 다양한 프로토콜(HTTP, HTTPS, FTP, FTPS, SCP, SFTP 등)을 사용하여 데이터를 전송할 수 있습니다.

 

  • curl {address} > install.sh
  • sudo sh install.sh

가상환경 코드를 Window 화면에서 동작시키기

Window PowerShell 에서 ssh-keygen 입력

 

scp .ssh/id_rsa.pub ubuntu@192.168.1.71:~/.ssh/authorized_keys

 

1. VScode -> extension -> Remote - SSH 설치

2. Ctrl + Shirt + P  누른 후 ssh config 

 

IdentiyFile 라인 추가해서 로컬 경로 설정

HostName :  내가 remote 할 가상환경(Ubuntu) IP 주소

Hose, User 이름 설정 

 

Ctrl + Shirt + P  누른 후 remote ssh connect

-> ubuntu 클릭

 

새로운 VSCode가 열린다면 성공

-> Linux 클릭 -> 터미널 열기

 


System Security - Strange Upgrade 문제

 

문제에 적혀져 있는 주소 그대로 복사하여 vscode terminal 에 붙여넣기 

 

아래와 같은 문제가 나옴

IDA tool을 이용해서 파일을 분석해야함

 

IDA 기본 단축키

  • F5/Tab : Decompile/Change View : 바이너리보다 더 편하게 볼 수 있다.
  • N: Rename : 함수 또는 변수의 이름을 바꾼다.
  • Double Clike: Enter : 해당 함수에 들어갈 수 있다.
  • ESC : 뒤로가기
  • TAB : 코드와 테이블 전환 가능(코드 보는 방식을 바꿀 수 있음) 

 

 

IDA 실행 -> open -> 파일열기 -> OK -> 테이블 형식으로 보여지는데 TAB 버튼을 통해 코드로 확인 

 

 

코드분석을 위해 main함수 더블클릭 

 

단축기 N (rename) 을 이용해 하나씩 변수가 어떤 역할을 하는지 확인하고 이름을 보기 좋게 바꾼다.

첫번째 함수

 

두번째 함수

 

세번째 함수

 

네번째 함수

 

최종 rename된 코드

Command injection

리눅스에서는 명령어를 연결해서 사용할 수 있는데 그러기 위한 특수문자들이 존재한다.

;(세미콜론) 여러 명령어를 순차적으로 실행

&&(AND) 첫 번째 명령어가 성공적으로 실행될 경우(종료 상태가 0인 경우)에만 두번째 명령어를 실행

|| (OR) …. 등등

기본 명령어에 특수문자를 맨앞에 집어넣으면 다른 명령어를 연결해서 인젝션 공격을 할 수 있다. 이것을 커멘드 인젝션 공격이라고 함

ex)

; cat

 

 

아래와 같이 커멘드 인젝션 공격을 통해서 빈 공간에 ls 를 치고 flag 를 cat flag 를 통해 가져올 수 있게 한다.

 

 

* vi 를 사용해서도 같은 결과를 도출해 낼 수 있다.

 


 

System Security - SigMe 문제

 

문제 확인

신호 핸들러(signal handler)는 운영 체제에서 특정 신호를 수신했을 때 실행되는 사용자 정의 함수입니다. 신호는 프로세스 간의 비동기적 통신 방법으로, 특정 이벤트가 발생했을 때 프로세스에 알림을 보내는 역할을 합니다. 예를 들어, 사용자가 프로그램을 종료하려고 할 때 발생하는 SIGINT 신호가 있습니다.

 

IDA를 통해 파일을 열고 main 함수 확인

 

Signal

  • 프로세스 외부에서 발생한 이벤트를 프로세스에게 알려주는 인터럽트
  • 프로세스 외부에서 발생한 이벤트를 알려주는 것 (ex 컴퓨터가 꺼졌으면 컴퓨터 동작이 안되기 떄문에 시그널을 통해 알려줘야함)
  • 시그널 처리: 시그널을 무시하거나 종료하거나 획득
  • Signal Handler: 시그널 처리를 위한 함수 지정

Signal 함수의 3가지 동작

  • 시그널을 무시
  • 시그널에 기본 동작
  • 시그널 수신 시 handler 호출

아래와 같은 방법으로 Strings 으로 분석할 수도 있음

 

아래의 창에서 의심스러워보이는 String을 찾음 (flag)

 

x 버튼을 통해서 의심스러운 라인이 어디에 있는 건지 filename을 확인할 수 있다.

OK 버튼 클릭

 

TAB 버튼을 누르면 아래와 같은 코드로 확인가능

 

추적결과 flag 는 1번 SET Signal 안에 있는 것으로 확인

flag 를 호출하려면 알람기능을 사용해야한다.

 

아래의 Signal 을 사용하면 Flag를 얻을 수 있다.

"SIGALRM | 14 | 종료 | 알림에 의해 발생"

명령어 "14" 를 삽입하면 30초 후에 알람이 나오면서 FLAG가 나온다.

 

 

 

두번째방법

 

VScode를 통해서 파이썬 파일을 열고 아래와 같이 주소값을 맞춰준다.

 

BINARY : file name

HOST 와 PORT: 파일의 주소값 (nc 3.34.49.33 1002)

 

 

 

위와 같이 주소와 포트값을 맞추고 python3 example_02.py 입력하여 실행

 

아래와 같이 main 함수 수정하여 결과값을 도출해낼 수 있다.

 


Pwntools

  • 익스플로잇 작성 라이브러리
  • CTF 익스플로잇을 최대한 쉽게 작성
  • 로컬 익스플로잇을 원격 익스플로잇으로 전환하기 용이

 

300x250
320x100

Computer Science

컴퓨터 관련된 알고리즘, 계산, 컴퓨터 구조, 하드웨어/소프트웨어 등 컴퓨터의 전반에 대한 학문

  • 어셈블리
  • 레지스터
  • 메모리 맵
  • 인스트럭션
  • 함수 호출 규약

어셈블리란 ? Assembly 

  • 기계어와 일대일로 대응이 되는 컴퓨터 언어 (고급언어와 저급언어 사이에 있는 언어)
  • 컴파일된 기계어를 어셈블리, 해석하는 것을 Disassemble 이라고 함

 

 

프로세스 메모리 맵 Process Memory Map

  • OS가 실행파일을 실행할 때 메모리에 각각의 데이터 영역을 분리하여 할당된 Layout을 말한다.
  • 전역변수, 지역변수, 동적변수, 상수 등이 위치해있다.
  • 각 Layout마다 역할이 나뉜다.

메모리는 크게 2가지로 나뉜다.

  • 동적 메모리: 실행 중에 필요에 따라 메모리를 할당하고 해제할 수 있어 유연성이 높지만, 관리에 주의가 필요합니다.
  • 정적 메모리: 변수를 사전에 정의하여 고정된 메모리 공간을 사용하므로, 크기 변경이 불가능하지만 관리가 간편합니다.

 

레지스터란?

CPU내에 존재하는 기억장치로 메모리 외 빠른 데이터 자장 및 읽기가 가능한 장치

 

범용레지스터: 연산 결과 저장, 산술 논리 연산, 주소 저장 등 다목적으로 사용되는 레지스터 // eax, ebx, ecx, edx

인덱스레지스터: 메모리 내 데이터 접근 시 주소를 가리킬 때 사용하는 레지스터 // esi, edi

그밖에 포인터레지스터, 세그먼트레지스터, 플래그레지스터가 있다.

 

Byte Ordering

→주소를 표기하는 방식으로 크게 두가지 방식이 존재한다.

 

  • Big-endian (사람눈에 읽기 쉬움 / 디버깅 시 유리 / 네트워크 바이트 오더에서 사용)

0x12345678 → 0x12345678

  • Little-endian (대부분 사용 // 연산, 타입변환시 유리하다)

0x12345678 → 78 56 34 12 순으로 한 바이트씩 끊어서 배열된다.

 

 

ISA(Instruction Set Architecture)란?

-> 프로세서가 이해하고 실행할 수 있는 형태의 기계어 명령어

 

ex)

mov eax, 10H  - 0x10을 EAX에 넣는다.

mov | 레지스터 | 10 HEX

 

*operand : 인자

 


리눅스 중요한 명령어

 

PUSH/POP

  • PUSH: 스택에 데이터를 추가하는 연산.
  • POP: 스택에서 데이터를 제거하고 반환하는 연산.

esp(스택의 최상위) / ebp(스택의 최하위)

 

ESP: 스택의 최상위(top)를 가리키며, 함수 호출 및 리턴, 변수 저장 및 로드 시에 사용됩니다.
EBP: 스택의 최하위(bottom) 또는 함수의 스택 프레임의 기준 지점을 가리키며, 함수의 로컬 변수나 인수에 접근할 때 기준이 됩니다.

MOV

데이터나 값을 한 위치에서 다른 위치로 이동시키는 역할

 

ex)

mov eax, ebx

ebx에 있는 값을 eax에 넣는다.

eax = ebx

 

LEA

메모리 주소를 계산하여 레지스터에 로드하는 데 사용되는 어셈블리 언어의 중요한 명령어입니다. 이를 통해 복잡한 주소 계산을 간편하게 수행할 수 있으며, 포인터 연산이나 배열 처리에 유용합니다. (두줄로 적어야 할 코드를 LEA 를 사용하면 한줄에 요약해서 적을 수 있다.)

 

lea eax, dword ptr ds: [esp+8]

esp+8 한 값을 eax에 넣는다.

 

 

mov eax, dword ptr ds : [esp+8] → eax == ???

→ 0x1234aaaa

lea eax, dword ptr ds : [esp+8] → eax == ???

→ 0x40008

 

 

 

 

 

 

mov eax, dword ptr ds: [esp+8]는 esp+8이 가리키는 메모리 주소에 저장된 값을 eax에 복사합니다. 즉, 메모리에서 데이터를 가져오는 동작입니다. eax는 메모리에서 읽은 값, 즉 0x1234aaaa가 됩니다.
lea eax, dword ptr ds: [esp+8]는 esp+8의 주소값을 계산하고, 그 계산된 주소를 eax에 저장합니다. 즉, eax는 esp+8의 값인 주소 0x40008이 됩니다.

 

 

ADD/SUB

ADD와 SUB는 어셈블리 언어에서 사용되는 기본적인 산술 명령어로, 각각 덧셈과 뺄셈을 수행합니다.

 

 

INT/SYSCALL

 

int 0x80

x86에서 eax에 들어있는 값에 따라 시스템콜을 호출한다.

 

syscall

x64에서 rax에 들어있는 값에 따라 시스템콜을 호출한다.

 

* EAX는 x86 아키텍처에서 사용되며, RAX는 x86-64 아키텍처에서 사용됩니다.

* EAX는 32비트 레지스터이며, RAX는 64비트 레지스터입니다.

 

 

CMP, JMP (compare, jump)

 

cmp : if구문과 동일하다.

 

JMP 0x40001

특정 주소나 레이블로 무조건 점프하여 실행 흐름을 변경합니다. 이를 통해 루프나 조건문, 서브루틴 등을 구현할 수 있습니다

 

0x40001로 실행 흐름(eip/rip)을 변경하는 명령어

위 cmp 조건에 따라 분기하는 명령어도 존재한다.

 

 

CALL 0x400000

함수 호출

 

leave

함수의 실행이 끝나면 해당 스택 프레임이 "leave"되어 스택에서 제거됩니다. 이 과정을 통해 함수의 지역 변수와 상태가 관리됩니다

leave 명령어는 현재 스택 프레임을 정리하고 이전 스택 프레임으로 복귀하는 데 사용됩니다.

 

 

ret (return)

함수 또는 서브루틴의 실행을 마치고, 스택에 저장된 복귀 주소를 참조하여 원래의 호출 위치로 돌아가는 데 사용됩니다. 이는 프로그램의 흐름을 제어하는 데 중요한 역할을 하며, 스택을 통해 복귀 주소를 관리합니다.


 

함수 프롤로그/에필로그

메인 루틴에서 특정 함수 실행 흐름이 옮겨졌을 때 사용할 Stack과 Register를 정리하는 과정

 

프롤로그 (시작점) / 에필로그 (끝점)


SFP는 "Stack Frame Pointer"의 약자로, 스택 프레임의 시작 주소를 가리키는 레지스터입니다

RSP(=ESP)는 "Stack Pointer"의 약자로, 현재 스택의 최상위 주소를 가리킵니다. 스택의 가장 최근에 푸시된 데이터의 주소를 나타냅니다.

RBP(=EBP)는 "Base Pointer"의 약자로, 현재 스택 프레임의 시작 주소를 가리킵니다. 함수가 호출될 때 RBP는 함수의 스택 프레임을 설정하는 데 사용됩니다.

 

 

push rbp ----- [1] 

 

mov rbp, rsp -----[2]

RSP 값이 RBP에 복사되어 새로운 스택 프레임이 설정 됩니다.  (-> rbp=rsp 이므로, rbp 값이 rsp 값으로 올라온다고 볼 수 있음)

 

sub rsp, 0x10 -----[3]

0x10(HEX) = 16(DEC) 바이트

 

  • sub rsp, 0x10 명령어는 스택 포인터(RSP)를 16바이트 감소시켜 3개의 새로운 공간을 확보합니다.
  • 이 새로운 공간은 나중에 로컬 변수나 임시 데이터를 저장하는 데 사용될 수 있습니다.
  • 스택의 내용은 변하지 않지만, RSP가 새로운 스택 최상단을 가리키게 됩니다.

공간이 생기는 이유

메모리 공간 확보: sub rsp, 0x10 명령어는 RSP의 값을 16바이트 감소시킵니다. 이로 인해 스택의 최상단이 16바이트 아래로 이동하게 됩니다. 스택에서 데이터가 추가되면, 새로운 공간이 생긴다고 할 수 있습니다.

 

 

 

leave -----[4]

RSP가 RBP의 값으로 설정되며, 이전 스택 프레임의 RBP가 스택에서 꺼내져 RBP에 저장됩니다.

 

 

 

ret -----[5]

RIP는 "Instruction Pointer"의 약자로, 현재 실행 중인 명령어의 주소를 가리키는 레지스터입니다. x86-64 아키텍처에서 사용하는 64비트 레지스터로, 프로그램의 흐름 제어에 중요한 역할을 합니다.

 


함수 호출 규약

메인루틴에서 서브루틴으로 실행 흐름을 옮길 때, 어떻게 인자를 전달하고 메모리를 할당하며 결과를 반환할 지에 대한 규약

 

intel x86_64는 크게 cdecl, stdcall, fastcall, thiscall 등이 존재한다.

*fastcall : 레지스터에 사용할 인자를 적어서 사용한다.

 

아래의 어셈블리 언어를 -> C언어로 트랜스퍼 하였다.

 

Reverse Engineering

일반적인 의미로 물건, 장치, 시스템 등의 기능 및 구조를 분석한 뒤 그 원리를 이해하는 방식

→ 해킹관점에선 프로그램의 원리를 분석하는 것을 말함

프로그램의 구조를 분석하기 위해 다양한 역공학 작업을 수행함

  • 리버스 엔지니어링의 중요성

소프트웨어 취약점

악성코드 분석

비즈니스 재산 보호

저작권 침해 보호

리버스 엔지니어링은 위법인가?

→ 악의적으로 사용하지 않는이상 바이너리를 확인해서 분석하는 것은 위법이 아님.

하지만 바이너리를 패치해서 불법적인 게임 핵을 만들거나 하면 당연히 위법이 된다.

 

Static vs Dynamic

Static analysis

  • 바이너리를 실행하지 않고 디스어셈블러, 디컴파일러를 이용해 코드를 분석하는 방식
  • 프로그램이 실행중이 아니기 떄문에 분석환경의 제약이 존재하지 않는다.
  • 프로그램의 전반적인 구조를 파악하기에는 편하다.
  • 난독화가 걸려잇을 경우 분석시 어려움이 있다.

Dynamic analysis

  • 디버거 등을 이용해 메모리, 레지스터, 코드 흐름등을 프로그램을 실행하는 중에 실시간 분석하는 방식
  • Data, Code flow를 읽기 쉬움
  • 분석 환경 구축이 필요함
  • 코드가 클 경우 분석 시 많은 시간이 소요될 수 있음

리버싱엔지니어링 이론 (분석순서)

  • 파일구조확인, 파일정보확인

윈도우에서 돌아가는지, 리눅스에서 돌아가는지 .. 어떤 인스트럭션 셋을 가지고 코드가 구현이되어 있으며 파일의 크기는 어느정도인지

  • 정적분석

코드에 대한 전반적 구조를 파악하고 취약할 것 같은 것을 리스트업함

  • 동적분석

프로그램의 취약해보이는 부분을 가지고 내가 A라는 값을 넣었을때 특정 영역에 프로그램을 잠깐 멈추는 걸 넣어서 분석, 확인하는 방법

  • 취약점 테스트

나는 이걸로 어떻게 취약점을 식별할 수 있는데를 확인해야함 예를들어, 페이로드(공격시 사용)을 해봤을떄 상대 컴퓨터에서 뭐가 날라오는지 테스트

  • 취약점 식별

 

Disassemble 디스어셈블

컴파일된 바이너리 코드를 어셈블리어로 변환하는 과정

 

Decompile 디컴파일

어셈블리어라는 로우 레벨의 언어를 고수준의 언어로 변환하는 작업


Usage of Reversing Tools

정적분석도구 Static analysis

  • IDA Decompiler

아키텍쳐, ISA 별로 디컴파일러를 만들어서 각 ISA별로 매우 잘 분석을 해준다. 단, 과금하는 방식이 아키텍쳐 하나에 얼마씩으로 나와서 가격이 비쌈

  • Ghidra (기드라를 사용해서 실습할 예정)

NSA(National Security Agency)에서 개발한 오픈 소스 리버스 엔지니어링 도구, 디스어셈블/디컴파일 지원

  • Binary Ninja

동적분석도구 Dynamic analysis

  • x64dbg, WinDbg : window 에서 사용가능
  • gdb : 리눅스에서 사용 가능

Ghidra 기드라 실습

symbol tree 왼쪽 중간

프로그램이 바이너리 형태로 되면 심볼같은게 없다.

여러가지 펑션을 자기 마음대로 명령한 것이 보인다.

실제 펑션에 대해 내용을 확인하고 싶으면 각 띄워서 분석하면되고

Assembly - 가운데 화면

어셈블리가 위치해 있는 화면, 펑선에 대한 프롤로그가 보이고, 메모리 세팅하는 것이 보임

Pseudo-Code 오른쪽 화면

 

분석을 쉽게 하기 위한 단축키

  • ctrl + L 을 눌러서 내가 분석하기 쉽게 변수를 rename 을 할 수있다
  • ; 를 누르면 코멘트를 달 수 있다.

아래와 같이 원하는 String을 Search 할 수 있다.

 

HANDSON 5

 

 


시험문제

용어관련

 

레지스터, 어셈블리 쪽에서 제출

 

아래와 같은 내용으로 시험 출제 1문제 예정

  • push instruction의 역할이 무엇인가요?
  • push instsruction을 수행하면 메모리주소가 어떻게 바뀔가요?
  • push instsruction을 수행하면 esp 가 어떻게 바뀔가요?
300x250
320x100

망법 - 정보보호최고책임자, 정보보호 관리체계 인증(자세히보기)

개인정보보호법 - 정의, 수집/이용, 제공, 유출신고, 개인정보 책임자, 가명정보


 

망법

정보보호 최고책임자의 지정

 

정보보호 관리체계 인증(자세히보기)


개인정보보호법

정의

수집/이용

제공

가명정보

유출신고

개인정보 책임자

300x250

+ Recent posts