TSCTF-J 2021 [Ezphp]

一、题目

 

 点进去看到登录界面

可以考虑抓包,看能否可以利用里面的条件

 抓到一个302之后的get包,访问对应的页面

当然这里也可以用admin + 万能密码绕过

"or "a"="a

 二、解题

进到网页之后发现提示信息

需要我们构造含有 /tmp/hint.php的参数

在path里直接传参试试

 发现进不了,编码也不行,后面我又试了php://filter伪协议也不行

瞎试了一下file://

 发现行了,属于是运气比较好

点开源代码

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

 提取信息:

1. flag的路径是 /home/flaaag.txt

2. 这里有多个魔法函数,需要构造pop链一个一个触发

POP链的构造:

观察到存在文件输出函数的在 class read{}里面,为file_get_contents()

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

 这里有一个魔术方法__toString()

当我们调试程序时,需要知道是否得出正确的数据。比如打印一个对象时,看看这个对象都有哪些属性,其值是什么,如果类定义了toString方法,就能在测试时,echo打印对象体,对象就会自动调用它所属类定义的toString方法,格式化输出这个对象所包含的数据。__toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。此方法必须返回一个字符串(或者执行语句),否则将发出一条 E_RECOVERABLE_ERROR 级别的致命错误。

 可以确定这是POP链的尾巴,执行 echo 语句时可能会触发__toString()方法,继续往下看

 发现有两处都执行了echo

那就找链头吧

class A是class service的继承类,而只有class A里面有自定义的析构函数,析构函数只需要在对象销毁的时候就能触发

function __destruct() {
		$flag = $this->event["name"];
		return $this->$flag();
	}

分析,这里flag获得的值是传进来的数组参数event里键名为name的键值

return 的是一个以flag值为名的方法,即name的键值

而__call()方法的调用条件是,当对象里一个不可访问(包括父类,自身)的方法被调用时被调用

找到__call()方法的位置

function __call($method, $args) {
		if (is_string($this->server->str)) {
			echo "hello" . $method . $this->server->str;
		} else {
			die("");
		}
	}

其中$method是自动收集的无法访问的方法名,$args是对应的参数

而__get()方法的调用条件如下:

在 php 面向对象编程中,类的成员属性被设定为 private 后,如果我们试图在外面调用它则会出现“不能访问某个私有属性”的错误。那么为了解决这个问题,我们可以使用魔术方法 __get()。或者对象中有不存在的属性被调用也能触发__get()。

在这里,所有对象都没有私有属性,让$this->server=另一个对象 

经过上面的排除加之“另一个对象”不能含有$str属性,只能是test了

所以POP链的逻辑如下:

A类的__destruct()触发父类service的__call(),__call()来触发test类的__get(),最后用__get()触发read类的__toString(),由__toString()回显flag的值

构造exp:

在脚本之家工具里面运行php代码 

 

将序列化的结果赋值给cmd,拿到flag

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值