본문 바로가기
hacking/pwnable

[Dream hack] Logical Bug: Path Traversal

by ilp 2024. 9. 1.
반응형

들어가며

서론

리눅스는 파일 시스템에 접근해서 파일의 데이터를 읽거나, 쓸 수다.

cat으로 출력하면, cat은 파일을 열고, 일고 stdout에 데이터를 출력한다.


로컬에서 접근하는걸 외부에 공개할때 접근에 제한을 두어야 한다..

  • 예를 들어, 사용자에게 각자 디렉토리를 주고, 자유롭게 활용할 수 있게 한다면,
  • 개발자는 사용자의 디렉토리만 접근하게 해야한다. 
  • 나쁜 놈들이 다름 파일을 훔치거나, 조작하여 서버를 장악할 수 있기 때문이다.

 

Path Traversal

: 위와 같은 서비스에서 사용자가 허용되지 않은 경로에 접근할 수 있는 취약점을 말한다.

 

사용자가 접근하는 경로에 검사가 나빠서, 임의 파일 읽기 쓰기의 수단으로 활용될 수 있다.


리눅스 경로

절대 경로와 상대 경로

리눅스에는 파일의 경로를 지정하는데 2가지 방법이 있는데

  • 절대 경로(Absolute Path)
  • 상대경로(Relative Path)가 있따.

디렉토리 구조 예시


절대 경로

루트 디렉토리('/')부터 파일에 이를 때까지 거쳐하는 디렉토리 이름을 모두 연결해서 한다.

각 디렉토리는 '/'로 구분하고, 끝에 파일이름을 추가하여 완성한다

 

절대경로는 그 파일만의 값이 유일한 값이다. 그래서 현재 어디에 있더라도, 절대 경로로는 그 파일을 가리킨다.

ex) 아까 예시로 보면 /a/b/c/target 이게 절대 경로다.

 

상대 경로

현재 디렉토리를 기준으로 해서 다른 파일의 경로를 상대적으로 표현했따.

리눅스에서 '..이전 디렉토리를,  '.'현재 디렉토리를 의미한다.

여러게가 나올 수 잇다.

 

ex) 현재 디렉토리가 d 일때 target을 가리키려면, ../c/target , ./../c/target , ../../../a/b/c/target 등이 있다.


Path Traversal🗺️

: 권한 없는 경로에 접근하는 취약점

권한은 리눅스파일 시스템에서가 아니라, 서비스 로직에서의 권한임.

// Name: path_traversal.c
// Compile: gcc -o path_traversal path_traversal.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const int kMaxNameLen = 0x100;
const int kMaxPathLen = 0x200;
const int kMaxDataLen = 0x1000;
const char *kBasepath = "/tmp";

int main() {
  char file_name[kMaxNameLen];
  char file_path[kMaxPathLen];
  char data[kMaxDataLen];
  FILE *fp = NULL;

  // Initialize local variables
  memset(file_name, '\0', kMaxNameLen);
  memset(file_path, '\0', kMaxPathLen);
  memset(data, '\0', kMaxDataLen);

  // Receive input from user
  printf("File name: ");
  fgets(file_name, kMaxNameLen, stdin);

  // Trim trailing new line
  file_name[strcspn(file_name, "\n")] = '\0';

  // Construct the `file_path`
  snprintf(file_path, kMaxPathLen, "%s/%s", kBasepath, file_name);

  // Read the file and print its content
  if ((fp = fopen(file_path, "r")) == NULL) {
    fprintf(stderr, "No file named %s", file_name);
    return -1;
  }

  fgets(data, kMaxDataLen, fp);
  printf("%s", data);

  fclose(fp);

  return 0;
}

👆 이런 코드가 있다. 여기에는 path traversal 취약점이 있다.

'/etc/passwd'를 읽을 수 있는 입력을 찾아보자

아래는 코드를 분석한 것이다.

더보기

1. 헤더 파일 포함

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

stdio.h : 표준 입출력

stdlib.h : 일반적인 유틸리티 함수 제공

string.h : 문자열 관련 함수 사용

 

2. 상수 정의

const int kMaxNameLen = 0x100;
const int kMaxPathLen = 0x200;
const int kMaxDataLen = 0x1000;
const char *kBasepath = "/tmp";

 

  • kMaxNameLen: 파일 이름의 최대 길이를 256(0x100) 바이트로 정의합니다.
  • kMaxPathLen: 전체 파일 경로의 최대 길이를 512(0x200) 바이트로 정의합니다.
  • kMaxDataLen: 파일에서 읽어올 데이터의 최대 길이를 4096(0x1000) 바이트로 정의합니다.
  • kBasepath: 기본 경로로, /tmp 디렉토리를 지정합니다.

 

3. 변수 선언 및 초기화 

char file_name[kMaxNameLen];
char file_path[kMaxPathLen];
char data[kMaxDataLen];
FILE *fp = NULL;

사용자가 입력한 파일 이름, 파일 경로, 읽어온 데이터저장할 변수를 선언하고,

파일을 가리킬 포인터를 초기화합니다.

// Initialize local variables
memset(file_name, '\0', kMaxNameLen);
memset(file_path, '\0', kMaxPathLen);
memset(data, '\0', kMaxDataLen);

memset 함수를 사용하여 이 변수들을 모두 널 문자('\0')로 초기화합니다. 

버퍼의 불필요한 데이터를 없게 한다.

 

4. 사용자 입력 받기

// Receive input from user
printf("File name: ");
fgets(file_name, kMaxNameLen, stdin);

fgets: 입력 받아 file_name 변수에 저장합니다. 최대 256바이트까지 입력받을 수 있습니다.

 

5. 입력값 처리

// Trim trailing new line
file_name[strcspn(file_name, "\n")] = '\0';

 fgets는 입력후 자동으로 \n을 추가함. 이거를 제거하는 코드

'strcspn으로 \n을 찾고 null문자를 넣는다;.

 

6. 파일 경로 구성

// Construct the `file_path`
snprintf(file_path, kMaxPathLen, "%s/%s", kBasepath, file_name);

snprintf 를 사용하여 파일 경로를 구성

기본경로(/tmp)와 사용자가 입력한 파일 이름결 합쳐서 최종 경로를 만듬.

ex) temp.txt 입력하면 /temp/temp.txt 가 됨

 

7. 파일 열기 및 읽기

// Read the file and print its content
if ((fp = fopen(file_path, "r")) == NULL) {
    fprintf(stderr, "No file named %s", file_name);
    return -1;
}

fopen: 파일 경로를 이용해 파일을 읽기 모 드("r")로 연다. (파일이 없거나 실패하면 null 반환)

파일을 열지 못하면 에러 메세지 출력하고 종료한다.

 

fgets(data, kMaxDataLen, fp);
printf("%s", data);

fgets : 파일에서 데이터를 읽어 data 변수에 저장 ( 최대 4096바이트)

 그리고 읽은 데이터를 출력한다...

 

8. 파일 닫기 및 프로그램 종료..

fclose(fp);
return 0;

 열었던 파일을 닫고 정상적으로 종료한다.

File name: ../etc/passwd

이렇게 ../를 사용해 상위 디렉토리에 접근 할 수 있다.

path traversal은 서버의 데이터를 공격자에게 노출하고 파일에 데이터를 쓸 수 있다면 조작할 수 도 있다.


마치며

  • 절대 경로(Absolute Path): 루트 디렉토리에서 접근할 파일 및 디렉터리 위치까지 모두 표현하는 방식
  • 상대 경로(Relative Path): 현재 사용자의 위치를 기준으로 다른 파일이나 디렉터리의 경로를 표현하는 방식.
  • Path Traversal: 경로 문자열에 대한 검사가 미흡하여 허용되지 않는 경로에 접근할 수 있는 취약점

반응형

'hacking > pwnable' 카테고리의 다른 글

[Dream hack] sint (p32)  (0) 2024.09.05
[Dream hack] cmd_center  (0) 2024.09.04
[Dream hack] Tool: pwntools  (0) 2024.08.07
[Dream hack] Quiz: Static Link vs. Dynamic Link-4  (0) 2024.08.02
[Dream hack] Quiz: Static Link vs. Dynamic Link-3  (0) 2024.08.02