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. 内网渗透 day1-基础

    粘滞键和放大镜 1. 到/windows/system32下用takeown改变该文件夹下的文件拥有权(因为粘滞键和放大镜都在system32文件夹下) cd /Windows/system32    ...

  2. Azure 静态 web 应用集成 Azure 函数 API

    前几次我们演示了如果通过Azure静态web应用功能发布vue跟blazor的项目.但是一个真正的web应用,总是免不了需要后台api服务为前端提供数据或者处理数据的能力.同样前面我们也介绍了Azur ...

  3. 《GNU_makefile》第七章——makefile的条件执行

    条件执行即,通过变量的值,来控制make的执行和忽略. 条件执行只能控制makefile的make语法部分,不能控制shell部分 1.一个例子 - libs_for_gcc = -lgnu norm ...

  4. linux 图解笔记

  5. CSS浮动和清除浮动

    1.浮动float div配合float浮动来做页面的布局,浮动最常用的地方就是用来做布局.只有一个标签设置了浮动float属性,就会变成块级标签. <!DOCTYPE html> < ...

  6. C++深拷贝与浅拷贝区别

    浅拷贝只是对指针的拷贝,浅拷贝后两个指针指向同一个内存空间: 深拷贝不仅对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针. 当对一个已知对象进行拷贝时,编译系统会 ...

  7. pandas 对时间索引进行分割

    截取最近1个月时间,截取最近一段时间,进行统计分析 df.loc["2016-01-05":"2016-02-05",:].tail() 在index为有序数据 ...

  8. iMindMap思维导图中可以插入哪些附件?

    iMindMap(Windows系统)不仅拥有灵活的排版功能,而且还允许用户插入多种附件,丰富思维导图的内容.用户可以为思维导图添加图片.网址.录音等文件,让导图更显生动性.实用性. 将图片.录音等文 ...

  9. Fruity Granulizer合成器功能简介

    本章节采用图文结合的方式给大家介绍电音编曲软件-FL Studio的插件Fruity Granulizer合成器,感兴趣的朋友可以一起沟通交流. Fruity Granulizer合成器是一个使用了粒 ...

  10. 基于gin的golang web开发:永远不要相信用户的输入

    作为后端开发者我们要记住一句话:"永远不要相信用户的输入",这里所说的用户可能是人,也可能是另一个应用程序."永远不要相信用户的输入"是安全编码的准则,也就是说 ...