背景
在某次比赛中碰到一题很魔幻的题目,让我印象深刻,特别是赛后主办方提供的wp(见下图)看得我久久不能忘怀,机缘巧合之下,又碰到了这一题目,故来分析一下。
正文
题目打开只有一个500报错
扫描源代码文件,发现index.php.swo
备份文件(坑!少见的备份文件格式,其是vim打开文件后的缓存文件),以下为文件内容:
分析题目,猜测flag是藏在类的注释中,我们能够实例化任意类,并调用类方法,那么就可以利用PHP 内置类中的 ReflectionMethod
来读取User
类里面各个函数的注释,本地测试如下:
构造成题目中的http参数则是:?rc=ReflectionMethod&ra=User&rb=a&rd=getDocComment
因为不知道是在哪个函数的注释中,所以逐个函数暴破,暴破rb
的值a-z
,可以发现flag
在q
的注释中
小结
本题考察的是PHP反射
,ReflectionMethod
构造User
类中的函数方法,再通过getDocComment
获取函数的注释,本例中使用__toString
同样可以输出函数注释内容。
附
ReflectionClass API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| $ref = new ReflectionClass(B::class);
print_r($ref->getProperties()); var_dump($ref->getConstructor()); var_dump($ref->inNamespace()); var_dump($ref->getConstants()); var_dump($ref->getConstant('TEST_1')); print_r($ref->getDefaultProperties()); var_dump($ref->getDocComment()); var_dump($ref->getExtension()); var_dump($ref->getFileName()); var_dump($ref->getInterfaceNames()); var_dump($ref->getInterfaces()); var_dump($ref->getMethods()); var_dump($ref->getMethod('foo4')); var_dump($ref->getName()); var_dump($ref->getNamespaceName()); var_dump($ref->getParentClass()); var_dump($ref->getProperty('prop3')); var_dump($ref->getShortName()); var_dump($ref->getStartLine()); print_r($ref->getStaticProperties()); print_r($ref->getStaticPropertyValue('prop_static')); print_r($ref->getTraitAliases()); print_r($ref->getTraitNames()); print_r($ref->getTraits()); var_dump($ref->hasConstant('AB')); var_dump($ref->hasMethod('AB')); var_dump($ref->hasProperty('AB')); var_dump($ref->implementsInterface('reflection\Abc')); var_dump($ref->isAbstract()); var_dump($ref->isAnonymous()); var_dump($ref->isCloneable()); var_dump($ref->isFinal()); var_dump($ref->isInstance($obj)); var_dump($ref->isInstantiable()); var_dump($ref->isInterface()); var_dump($ref->isInternal()); var_dump($ref->isIterateable()); var_dump($ref->isSubclassOf(A::class)); var_dump($ref->isTrait()); var_dump($ref->isUserDefined());
var_dump($ref->newInstance());
var_dump($ref->newInstanceArgs([])); var_dump($ref->newInstanceWithoutConstructor()); $ref->setStaticPropertyValue ('prop_static', '222'); var_dump($ref->__toString ()); ```
|
ReflectionMethod API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
|
ReflectionMethod extends ReflectionFunctionAbstract implements Reflector {
const integer IS_STATIC = 1 ; const integer IS_PUBLIC = 256 ; const integer IS_PROTECTED = 512 ; const integer IS_PRIVATE = 1024 ; const integer IS_ABSTRACT = 2 ; const integer IS_FINAL = 4 ;
public $name ; public $class ;
public __construct ( mixed $class , string $name ) public static export ( string $class , string $name [, bool $return = false ] ) : string public getClosure ( object $object ) : Closure public getDeclaringClass ( ) : ReflectionClass public getModifiers ( ) : int public getPrototype ( ) : ReflectionMethod public invoke ( object $object [, mixed $parameter [, mixed $... ]] ) : mixed public invokeArgs ( object $object , array $args ) : mixed public isAbstract ( ) : bool public isConstructor ( ) : bool public isDestructor ( ) : bool public isFinal ( ) : bool public isPrivate ( ) : bool public isProtected ( ) : bool public isPublic ( ) : bool public isStatic ( ) : bool public setAccessible ( bool $accessible ) : void public __toString ( ) : string
final private ReflectionFunctionAbstract::__clone ( ) : void public ReflectionFunctionAbstract::getClosureScopeClass ( ) : ReflectionClass public ReflectionFunctionAbstract::getClosureThis ( ) : object public ReflectionFunctionAbstract::getDocComment ( ) : string public ReflectionFunctionAbstract::getEndLine ( ) : int public ReflectionFunctionAbstract::getExtension ( ) : ReflectionExtension public ReflectionFunctionAbstract::getExtensionName ( ) : string public ReflectionFunctionAbstract::getFileName ( ) : string public ReflectionFunctionAbstract::getName ( ) : string public ReflectionFunctionAbstract::getNamespaceName ( ) : string public ReflectionFunctionAbstract::getNumberOfParameters ( ) : int public ReflectionFunctionAbstract::getNumberOfRequiredParameters ( ) : int public ReflectionFunctionAbstract::getParameters ( ) : array public ReflectionFunctionAbstract::getReturnType ( ) : ReflectionType public ReflectionFunctionAbstract::getShortName ( ) : string public ReflectionFunctionAbstract::getStartLine ( ) : int public ReflectionFunctionAbstract::getStaticVariables ( ) : array public ReflectionFunctionAbstract::hasReturnType ( ) : bool public ReflectionFunctionAbstract::inNamespace ( ) : bool public ReflectionFunctionAbstract::isClosure ( ) : bool public ReflectionFunctionAbstract::isDeprecated ( ) : bool public ReflectionFunctionAbstract::isGenerator ( ) : bool public ReflectionFunctionAbstract::isInternal ( ) : bool public ReflectionFunctionAbstract::isUserDefined ( ) : bool public ReflectionFunctionAbstract::isVariadic ( ) : bool public ReflectionFunctionAbstract::returnsReference ( ) : bool abstract public ReflectionFunctionAbstract::__toString ( ) : void }
|
伪源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
| <?php class User { private static $c = 0;
function a() { return ++self::$c; }
function b() { return ++self::$c; }
function c() { return ++self::$c; }
function d() { return ++self::$c; }
function e() { return ++self::$c; }
function f() { return ++self::$c; }
function g() { return ++self::$c; }
function h() { return ++self::$c; }
function i() { return ++self::$c; }
function j() { return ++self::$c; }
function k() { return ++self::$c; }
function l() { return ++self::$c; }
function m() { return ++self::$c; }
function n() { return ++self::$c; }
function o() { return ++self::$c; }
function p() { return ++self::$c; }
function q() { return ++self::$c; }
function r() { return ++self::$c; }
function s() { return ++self::$c; }
function t() { return ++self::$c; } }
$rc=$_GET["rc"]; $rb=$_GET["rb"]; $ra=$_GET["ra"]; $rd=$_GET["rd"]; $method= new $rc($ra, $rb); var_dump($method->$rd());
|