03 多重加密

源代码为:

<?php
include 'common.php';
$requset = array_merge($_GET, $_POST, $_SESSION, $_COOKIE);
//把一个或多个数组合并为一个数组
class db
{
public $where;
function __wakeup()
{
if(!empty($this->where))
{
$this->select($this->where);
}
}
function select($where)
{
$sql = mysql_query('select * from user where '.$where);
//函数执行一条 MySQL 查询。
return @mysql_fetch_array($sql);
//从结果集中取得一行作为关联数组,或数字数组,或二者兼有返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false
}
} if(isset($requset['token']))
//测试变量是否已经配置。若变量已存在则返回 true 值。其它情形返回 false 值。
{
$login = unserialize(gzuncompress(base64_decode($requset['token'])));
//gzuncompress:进行字符串压缩
//unserialize: 将已序列化的字符串还原回 PHP 的值 $db = new db();
$row = $db->select('user=\''.mysql_real_escape_string($login['user']).'\'');
//mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。 if($login['user'] === 'ichunqiu')
{
echo $flag;
}else if($row['pass'] !== $login['pass']){
echo 'unserialize injection!!';
}else{
echo "(╯‵□′)╯︵┴─┴ ";
}
}else{
header('Location: index.php?error=1');
} ?>

这道题目直接部署的话会有一些配置问题,根据报错修改了配置文件之后,在同目录文件夹下创建了common.php,设置$flag=123456

可以看到获取flag的操作为:

if($login['user'] === 'ichunqiu')
{
echo $flag;
}else if($row['pass'] !== $login['pass']){
echo 'unserialize injection!!';
}else{
echo "(╯‵□′)╯︵┴─┴ ";
}

当$login['user']==='ichunqiu'的时候,就输出flag,继续往上看$login的赋值位置

$login = unserialize(gzuncompress(base64_decode($requset['token'])));

进行了base64解密,gzuncompress字符串压缩和字符串反序列化。

而$requset的赋值在:

$requset = array_merge($_GET, $_POST, $_SESSION, $_COOKIE);

将从GET,POST或者COOKIE中获取到的值合并到request里面

为了满足:

$login['user'] === 'ichunqiu'

我们需要令

$token=array(['user']==='ichunqiu');

然后再对其进行相应的加密,最后的token为:

$token=array(['user']==='ichunqiu');
$token=base64_encode(gzcompress(serialize($token)));
echo $token;

得到payload为:

eJxLtDK0qs60MrBOAuJaAB5uBBQ=

最后本地输出还是有问题,就写写解题思路趴

04 SQL注入_WITH ROLLUP绕过

源代码为:

<?php
error_reporting(0); if (!isset($_POST['uname']) || !isset($_POST['pwd'])) {
echo '<form action="" method="post">'."<br/>";
echo '<input name="uname" type="text"/>'."<br/>";
echo '<input name="pwd" type="text"/>'."<br/>";
echo '<input type="submit" />'."<br/>";
echo '</form>'."<br/>";
echo '<!--source: source.txt-->'."<br/>";
die;
} function AttackFilter($StrKey,$StrValue,$ArrReq){
if (is_array($StrValue)){ //检测变量是否是数组 $StrValue=implode($StrValue); //返回由数组元素组合成的字符串 }
if (preg_match("/".$ArrReq."/is",$StrValue)==1){ //匹配成功一次后就会停止匹配 print "水可载舟,亦可赛艇!";
exit();
}
} $filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
foreach($_POST as $key=>$value){ //遍历数组 AttackFilter($key,$value,$filter);
} $con = mysql_connect("XXXXXX","XXXXXX","XXXXXX");
if (!$con){
die('Could not connect: ' . mysql_error());
}
$db="XXXXXX";
mysql_select_db($db, $con); //设置活动的 MySQL 数据库 $sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
$query = mysql_query($sql); //执行一条 MySQL 查询 if (mysql_num_rows($query) == 1) { //返回结果集中行的数目 $key = mysql_fetch_array($query); //返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false if($key['pwd'] == $_POST['pwd']) {
print "CTF{XXXXXX}";
}else{
print "亦可赛艇!";
}
}else{
print "一颗赛艇!";
}
mysql_close($con);
?>

本地环境的原因,只能直接分析代码了。

首先是登录框POST输入用户名和密码

if (!isset($_POST['uname']) || !isset($_POST['pwd'])) {
echo '<form action="" method="post">'."<br/>";
echo '<input name="uname" type="text"/>'."<br/>";
echo '<input name="pwd" type="text"/>'."<br/>";
echo '<input type="submit" />'."<br/>";
echo '</form>'."<br/>";
echo '<!--source: source.txt-->'."<br/>";
die;
}

然后对POST的值使用AttackFilter函数进行过滤

$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
foreach($_POST as $key=>$value){ //遍历数组 AttackFilter($key,$value,$filter);
}

AttackFilter函数为:

function AttackFilter($StrKey,$StrValue,$ArrReq){
if (is_array($StrValue)){ //检测变量是否是数组 $StrValue=implode($StrValue); //返回由数组元素组合成的字符串 }
if (preg_match("/".$ArrReq."/is",$StrValue)==1){ //匹配成功一次后就会停止匹配 print "水可载舟,亦可赛艇!";
exit();
}
}

匹配到了黑名单中的元素时就会退出

$con = mysql_connect("XXXXXX","XXXXXX","XXXXXX");
if (!$con){
die('Could not connect: ' . mysql_error());
}
$db="XXXXXX";
mysql_select_db($db, $con);

这里是链接本地数据库的操作,接着查询输入的uname的相关数据

$sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
$query = mysql_query($sql);

返回结果集中行的数目为1,才能进入if,也就是说interest表中不止一行,然后将值赋给$key

if (mysql_num_rows($query) == 1) { 

//返回结果集中行的数目

    $key = mysql_fetch_array($query);

如果输入的密码和数据库中的密码是相同的就输出flag,否则输出提示信息

    if($key['pwd'] == $_POST['pwd']) {
print "CTF{XXXXXX}";
}else{
print "亦可赛艇!";
}
}else{
print "一颗赛艇!";
}
mysql_close($con);
?>

这里使用到的绕过技巧是GROUP BY WITH ROLLUP

关于函数的介绍可以看这个:

https://blog.csdn.net/id19870510/article/details/6254358

分组后会多一行进行统计,而多出的一行的pwd会是NULL!而user会是数据库表中已存在的字段。

因为存在限制

mysql_num_rows($query) == 1

所以我们使用

limit m offset n
m: 展示m条
n: 跳过n条

来筛选出每一条数据,直到筛选出为user存在,pwd为空的那一行

最终的payload为:

1' or 1 group by pwd with rollup limit 1 offset 2#

而密码栏不需要输入,不输入则为NULL,在该位置:

if($key['pwd'] == $_POST['pwd']) {
print "CTF{XXXXXX}";

即可满足条件输出flag

参考链接:

http://www.bubuko.com/infodetail-2169730.html

https://blog.csdn.net/qq_35078631/article/details/54772798

https://blog.csdn.net/id19870510/article/details/6254358

PHP代码审计分段讲解(2)的更多相关文章

  1. PHP代码审计分段讲解(14)

    30题利用提交数组绕过逻辑 本篇博客是PHP代码审计分段讲解系列题解的最后一篇,对于我这个懒癌患者来说,很多事情知易行难,坚持下去,继续学习和提高自己. 源码如下: <?php $role = ...

  2. PHP代码审计分段讲解(13)

    代码审计分段讲解之29题,代码如下: <?php require("config.php"); $table = $_GET['table']?$_GET['table']: ...

  3. PHP代码审计分段讲解(11)

    后面的题目相对于之前的题目难度稍微提升了一些,所以对每道题进行单独的分析 27题 <?php if(!$_GET['id']) { header('Location: index.php?id= ...

  4. PHP代码审计分段讲解(1)

    PHP源码来自:https://github.com/bowu678/php_bugs 快乐的暑期学习生活+1 01 extract变量覆盖 <?php $flag='xxx'; extract ...

  5. PHP代码审计分段讲解(12)

    28题 <!DOCTYPE html> <html> <head> <title>Web 350</title> <style typ ...

  6. PHP代码审计分段讲解(10)

    26 unserialize()序列化 <!-- 题目:http://web.jarvisoj.com:32768 --> <!-- index.php --> <?ph ...

  7. PHP代码审计分段讲解(9)

    22 弱类型整数大小比较绕过 <?php error_reporting(0); $flag = "flag{test}"; $temp = $_GET['password' ...

  8. PHP代码审计分段讲解(8)

    20 十六进制与数字比较 源代码为: <?php error_reporting(0); function noother_says_correct($temp) { $flag = 'flag ...

  9. PHP代码审计分段讲解(7)

    17 密码md5比较绕过 <?php if($_POST[user] && $_POST[pass]) { mysql_connect(SAE_MYSQL_HOST_M . ': ...

  10. PHP代码审计分段讲解(6)

    14 intval函数四舍五入 <?php if($_GET[id]) { mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_M ...

随机推荐

  1. 解决IE9弹出json下载提示框

    <!-- 开启注解 --> <mvc:annotation-driven> <mvc:message-converters> <bean class=&quo ...

  2. linux常用命令-查看cpu、内存、磁盘和目录空间

    1. 查看磁盘空间: df -h Filesystem      Size  Used Avail Use% Mounted on /dev/xvda1       40G  4.5G   33G   ...

  3. pandas.DataFarme内置的绘图功能参数说明

    可视化是数据探索性分析及结果表达的一种非常重要的形式,因此打算写一个python绘图系列,本文是第一篇,先说一下pandas.DataFrame.plot()绘图功能. pandas.DataFram ...

  4. Java基础 之三 继承

    1.子类 1) 定义子类 //假设父类(也叫做超类)是Employee类,用extends来表示继承 public class Manager extends Employee{ //域和方法 pri ...

  5. NOIP前一些题目的理解

    ZYB和售货机(图论,环) 题目链接 个人感觉这道题与基环树没有任何关系,你会发现,每个点最多只有一个入度和出度,所以只能是链或环. 还有就是本题的突破点就在于正确建图,题目的限制保证每个点的入度不大 ...

  6. WPF窗体中嵌入/使用WinForm类/控件(基于.NET Core)

    如题,WPF中嵌入WinForm的做法,网络上已经很多示例,都是基于.NET XXX版的. 今天King様在尝试WPF(基于.NET Core 3.1)中加入Windows.Forms.ColorDi ...

  7. Flink处理函数实战之二:ProcessFunction类

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  8. CorelDRAW常用工具之渐变工具

    我们在进行宣传单页或者LOGO等等各种平面设计时,颜色的使用是极为重要的一方面.有些新手可能还不知道怎么填充多种颜色的渐变,有的背景色不止2个颜色渐变,而是由多种颜色调成的. 我们在画布上画两个图形, ...

  9. CDR排钻教程-CorelDRAW服装设计中的排钻技术

    服装设计一直都是一个很火热的行业,也是一个比较高端的行业,随着时代的步伐,以前的人都是用手绘的方式来设计服装,现在不一样了,电脑可以说普及到了每一个家庭,让软件以更快的速度,更准确的数据来设计服装中的 ...

  10. Luogu P2656 采蘑菇

    尽管是缩点的习题,思路也是在看了题解后才明白的. 首先,每个强连通分量内的点都是一定互通的,也就是可以完全把这里面的边都跑满,摘掉所有能摘的蘑菇.那么,考虑给每一个强连通分量化为的新点一个点权,代表摘 ...