反射

Reflection in PHP

通过反射可以调用执行类中的私有方法。PHP自5.0版本以后添加了反射机制,它提供了一套强大的反射API,允许你在PHP运行环境中,访问和使用类、方法、属性、参数和注释等,其功能十分强大,经常用于高扩展的PHP框架,自动加载插件,自动生成文档,甚至可以用来扩展PHP语言。

demo

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
<?php
class test {
private $name = "Glarcy";
private function hello(){
return "Hello ".$this -> name;
}
private function get(){
return "My name is ".$this -> name;
}
}

//通过类名MyClass进行反射
$ref = new ReflectionClass('test');
//通过反射类进行实例化
$instance = $ref -> newInstance();
//通过方法名hello获取指定方法
$method = $ref -> getMethod('hello');
//设置可访问性
$method -> setAccessible(true);
//执行方法
echo $method -> invoke($instance)."<br>";

$test = new test();
$reflect = new ReflectionClass($test);
$way = $reflect -> getMethod('get');
$way -> setAccessible(true);
echo $way -> invoke($test);

输出:

1
2
Hello Glarcy
My name is Glarcy

例子

国赛的RefSpace

flag.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use interesting\FlagSDK;
$sdk = new FlagSDK();
$key = $_GET['key'] ?? false;
if (!$key) {
echo "Please provide access key<br \>";
echo '$_GET["key"];';
exit();
}
$flag = $sdk->verify($key);
if ($flag) {
echo $flag;
} else {
echo "Wrong Key";
exit();
}

sdk.php

1
2
3
4
5
6
7
public function verify($key)
{
if (sha1($key) === $this->getHash()) {
return "too{young-too-simple}";
}
return false;
}

这里就可以利用反射来获得getHash()的返回值

1
2
3
4
5
6
7
use interesting\FlagSDK; 
$sdk = new FlagSDK();
$ref = new ReflectionClass($sdk);
$instance = $ref->newInstance();
$method = $ref->getmethod("getHash");
$method->setAccessible(true);
echo $method->invoke($instance);

Reflection in Java

Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。

demo

hello.java

1
2
3
4
5
6
7
8
9
10
11
package glarcy.demo;

public class hello {
public void show(String s){
System.out.println("hello " + s);
}

private void hello(){
System.out.println("hello glarcy" );
}
}

reflect.java

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
package glarcy.demo;

import java.lang.reflect.Method;

public class reflect {
public static void main(String[] args) throws Exception{
//获取class对象
Class hello = Class.forName("glarcy.demo.hello");
//获取所有公有方法
System.out.println("获取所有公有方法");
hello.getMethods();
Method[] methodArr = hello.getMethods();
for (Method m : methodArr) {
System.out.println(m.getName());
}

//获取所有私有方法
System.out.println("获取类的所有方法");
hello.getDeclaredMethods();
Method[] methodAll = hello.getDeclaredMethods();
for (Method m : methodAll) {
System.out.println(m.getName());
}

//通过反射调用hello下的show方法
System.out.println("通过反射调用hello下的show方法");
Method m = hello.getMethod("show", String.class);
System.out.println(m);
//实例化一个hello对象
Object obj = hello.newInstance();
m.invoke(obj,"Glarcy");

//通过反射调用hello下的hello方法
System.out.println("通过反射调用hello下的hello方法");
Method m1 = hello.getDeclaredMethod("hello");
m1.setAccessible(true);
System.out.println(m1);
//实例化一个hello对象
Object obj1 = hello.newInstance();
m1.invoke(obj1);
}
}

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
获取所有公有方法
show
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll
获取类的所有方法
show
hello
通过反射调用hello下的show方法
public void glarcy.demo.hello.show(java.lang.String)
hello Glarcy
通过反射调用hello下的hello方法
private void glarcy.demo.hello.hello()
hello glarcy

例子

利用java反射进行命令执行

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
package glarcy.demo;

import java.io.*;
import java.lang.reflect.Method;

public class test {
public static void main(String args[]) throws Exception{
//定义myObj对象
MyObject myObj = new MyObject();
myObj.name = "hello";
//创建一个包含对象进行反序列化信息的"object"数据文件
FileOutputStream fos = new FileOutputStream("object");
ObjectOutputStream os = new ObjectOutputStream(fos);
//writeObject()方法将myObj对象写入object文件
os.writeObject(myObj);
os.close();
//从文件中反序列化obj对象
FileInputStream fis = new FileInputStream("object");
ObjectInputStream ois = new ObjectInputStream(fis);
//恢复对象
MyObject objectFromDisk = (MyObject)ois.readObject();
System.out.println(objectFromDisk.name);
ois.close();
}
}

class MyObject implements Serializable {
public String name;
//重写readObject()方法
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
//执行默认的readObject()方法
in.defaultReadObject();
//执行打开计算器程序命令
try {
Method method = java.lang.Runtime.class.getMethod("exec", String.class);
Object result = method.invoke(Runtime.getRuntime(), "calc.exe");
} catch (Exception e){

}

}
}

Apache-Commons-Collections反序列化漏洞:http://pupiles.com/java_unserialize2.html

Code Breaking 上面一道相关的题目 javacon:http://rui0.cn/archives/1015

参考链接:

https://paper.seebug.org/312/