代码审计(1):CVE-2022-4957分析及复现

news2024/10/7 18:27:24

0x00漏洞描述:

ѕрееdtеѕt iѕ а vеrу liɡhtԝеiɡht nеtԝоrk ѕрееd tеѕtinɡ tооl imрlеmеntеd in Jаvаѕсriрt. Thеrе iѕ а Crоѕѕ-ѕitе Sсriрtinɡ vulnеrаbilitу in librеѕроndеd ѕрееdtеѕt 5.2.4 аnd еаrliеr vеrѕiоnѕ. Thе vulnеrаbilitу iѕ саuѕеd bу thе раrаmеtеr id оf thе filе rеѕultѕ/ѕtаtѕ.рhр thаt ԝill саuѕе Crоѕѕ-ѕitе Sсriрtinɡ.

0x01 分析:

先到Github把ѕрееdtеѕt的5.2.4版本的源代码下下来,然后直接看rеѕultѕ/ѕtаtѕ.рhр文件:

<?php
session_start();
error_reporting(0);

require 'telemetry_settings.php';
require_once 'telemetry_db.php';

header('Content-Type: text/html; charset=utf-8');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0, s-maxage=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
?>
<!DOCTYPE html>
<html>
    <head>
        <title>LibreSpeed - Stats</title>
        <style type="text/css">
            html,body{
                margin:0;
                padding:0;
                border:none;
                width:100%; min-height:100%;
            }
            html{
                background-color: hsl(198,72%,35%);
                font-family: "Segoe UI","Roboto",sans-serif;
            }
            body{
                background-color:#FFFFFF;
                box-sizing:border-box;
                width:100%;
                max-width:70em;
                margin:4em auto;
                box-shadow:0 1em 6em #00000080;
                padding:1em 1em 4em 1em;
                border-radius:0.4em;
            }
            h1,h2,h3,h4,h5,h6{
                font-weight:300;
                margin-bottom: 0.1em;
            }
            h1{
                text-align:center;
            }
            table{
                margin:2em 0;
                width:100%;
            }
            table, tr, th, td {
                border: 1px solid #AAAAAA;
            }
            th {
                width: 6em;
            }
            td {
                word-break: break-all;
            }
            div {
                margin: 1em 0;
            }
        </style>
    </head>
    <body>
        <h1>LibreSpeed - Stats</h1>
        <?php
        if (!isset($stats_password) || $stats_password === 'PASSWORD') {
            ?>
                Please set $stats_password in telemetry_settings.php to enable access.
            <?php
        } elseif ($_SESSION['logged'] === true) {
            if ($_GET['op'] === 'logout') {
                $_SESSION['logged'] = false;
                ?><script type="text/javascript">window.location=location.protocol+"//"+location.host+location.pathname;</script><?php
            } else {
                ?>
                <form action="stats.php" method="GET"><input type="hidden" name="op" value="logout" /><input type="submit" value="Logout" /></form>
                <form action="stats.php" method="GET">
                    <h3>Search test results</h3>
                    <input type="hidden" name="op" value="id" />
                    <input type="text" name="id" id="id" placeholder="Test ID" value=""/>
                    <input type="submit" value="Find" />
                    <input type="submit" onclick="document.getElementById('id').value=''" value="Show last 100 tests" />
                </form>
                <?php
                if ($_GET['op'] === 'id' && !empty($_GET['id'])) {
                    $speedtest = getSpeedtestUserById($_GET['id']);
                    $speedtests = [];
                    if (false === $speedtest) {
                        echo '<div>There was an error trying to fetch the speedtest result for ID "'.$_GET['id'].'".</div>';
                    } elseif (null === $speedtest) {
                        echo '<div>Could not find a speedtest result for ID "'.$_GET['id'].'".</div>';
                    } else {
                        $speedtests = [$speedtest];
                    }
                } else {
                    $speedtests = getLatestSpeedtestUsers();
                    if (false === $speedtests) {
                        echo '<div>There was an error trying to fetch latest speedtest results.</div>';
                    } elseif (empty($speedtests)) {
                        echo '<div>Could not find any speedtest results in database.</div>';
                    }
                }
                foreach ($speedtests as $speedtest) {
                    ?>
                    <table>
                        <tr>
                            <th>Test ID</th>
                            <td><?= htmlspecialchars($speedtest['id_formatted'], ENT_HTML5, 'UTF-8') ?></td>
                        </tr>
                        <tr>
                            <th>Date and time</th>
                            <td><?= htmlspecialchars($speedtest['timestamp'], ENT_HTML5, 'UTF-8') ?></td>
                        </tr>
                        <tr>
                            <th>IP and ISP Info</th>
                            <td>
                                <?= htmlspecialchars($speedtest['ip'], ENT_HTML5, 'UTF-8') ?><br/>
                                <?= htmlspecialchars($speedtest['ispinfo'], ENT_HTML5, 'UTF-8') ?>
                            </td>
                        </tr>
                        <tr>
                            <th>User agent and locale</th>
                            <td><?= htmlspecialchars($speedtest['ua'], ENT_HTML5, 'UTF-8') ?><br/>
                                <?= htmlspecialchars($speedtest['lang'], ENT_HTML5, 'UTF-8') ?>
                            </td>
                        </tr>
                        <tr>
                            <th>Download speed</th>
                            <td><?= htmlspecialchars($speedtest['dl'], ENT_HTML5, 'UTF-8') ?></td>
                        </tr>
                        <tr>
                            <th>Upload speed</th>
                            <td><?= htmlspecialchars($speedtest['ul'], ENT_HTML5, 'UTF-8') ?></td>
                        </tr>
                        <tr>
                            <th>Ping</th>
                            <td><?= htmlspecialchars($speedtest['ping'], ENT_HTML5, 'UTF-8') ?></td>
                        </tr>
                        <tr>
                            <th>Jitter</th>
                            <td><?= htmlspecialchars($speedtest['jitter'], ENT_HTML5, 'UTF-8') ?></td>
                        </tr>
                        <tr>
                            <th>Log</th>
                            <td><?= htmlspecialchars($speedtest['log'], ENT_HTML5, 'UTF-8') ?></td>
                        </tr>
                        <tr>
                            <th>Extra info</th>
                            <td><?= htmlspecialchars($speedtest['extra'], ENT_HTML5, 'UTF-8') ?></td>
                        </tr>
                    </table>
                    <?php
                }
            }
        } elseif ($_GET['op'] === 'login' && $_POST['password'] === $stats_password) {
            $_SESSION['logged'] = true;
            ?><script type="text/javascript">window.location=location.protocol+"//"+location.host+location.pathname;</script><?php
        } else {
            ?>
            <form action="stats.php?op=login" method="POST">
                <h3>Login</h3>
                <input type="password" name="password" placeholder="Password" value=""/>
                <input type="submit" value="Login" />
            </form>
            <?php
        }
        ?>
    </body>
</html>

直接看第89行的漏洞点:

 <?php
                if ($_GET['op'] === 'id' && !empty($_GET['id'])) {
                    $speedtest = getSpeedtestUserById($_GET['id']);
                    $speedtests = [];
                    if (false === $speedtest) {
                        echo '<div>There was an error trying to fetch the speedtest result for ID "'.$_GET['id'].'".</div>';
                    } elseif (null === $speedtest) {
                        echo '<div>Could not find a speedtest result for ID "'.$_GET['id'].'".</div>';
                    } else {
                        $speedtests = [$speedtest];
                    }
                } else {
                    $speedtests = getLatestSpeedtestUsers();
                    if (false === $speedtests) {
                        echo '<div>There was an error trying to fetch latest speedtest results.</div>';
                    } elseif (empty($speedtests)) {
                        echo '<div>Could not find any speedtest results in database.</div>';
                    }
                }
                foreach ($speedtests as $speedtest) {
                    ?>

当接收参数op=id,参数id=空或者flase时,直接将$_GET[‘id’]拼接到HTML代码中,导致了一个反射型的XSS。

0x02 复现

直接docker pull下来官方镜像,把里面的内容换成5.2.4版本的代码,然后点击登录:
在这里插入图片描述
这里由于stats.php的代码里有一句:

<?php
        if (!isset($stats_password) || $stats_password === 'PASSWORD') {
            ?>
                Please set $stats_password in telemetry_settings.php to enable access.
            <?php
        } elseif ($_SESSION['logged'] === true) {
            if ($_GET['op'] === 'logout') {
                $_SESSION['logged'] = false;
                ?><script type="text/javascript">window.location=location.protocol+"//"+location.host+location.pathname;</script><?php

因此,还要到telemetry_settings.php里去把$stats_password改掉。
登录进去之后输入payload:
在这里插入图片描述
利用成功:
在这里插入图片描述

0x03利用条件

1.知道stats.php的登录密码
2.目标给results文件夹配置了php执行的权限(实际上很多目标都没有给results文件夹php文件的解析权限)
3.反射型XSS,必须要与目标有交互
4.版本有极大限制,仅限于5.2.3和5.2.4版本,如5.2.2版本就不存在这个问题:

<?php
		$q=null;
		if($_GET["op"]=="id"&&!empty($_GET["id"])){
			$id=$_GET["id"];
			if($enable_id_obfuscation) $id=deobfuscateId($id);
			if($db_type=="mysql"){
				$q=$conn->prepare("select id,timestamp,ip,ispinfo,ua,lang,dl,ul,ping,jitter,log,extra from speedtest_users where id=?");
				$q->bind_param("i",$id);
				$q->execute();
				$q->store_result();
				$q->bind_result($id,$timestamp,$ip,$ispinfo,$ua,$lang,$dl,$ul,$ping,$jitter,$log,$extra);
			} else if($db_type=="sqlite"||$db_type=="postgresql"){
				$q=$conn->prepare("select id,timestamp,ip,ispinfo,ua,lang,dl,ul,ping,jitter,log,extra from speedtest_users where id=?");
				$q->execute(array($id));
			} else die();
		}else{
			if($db_type=="mysql"){
				$q=$conn->prepare("select id,timestamp,ip,ispinfo,ua,lang,dl,ul,ping,jitter,log,extra from speedtest_users order by timestamp desc limit 0,100");
				$q->execute();
				$q->store_result();
				$q->bind_result($id,$timestamp,$ip,$ispinfo,$ua,$lang,$dl,$ul,$ping,$jitter,$log,$extra);
			} else if($db_type=="sqlite"||$db_type=="postgresql"){
				$q=$conn->prepare("select id,timestamp,ip,ispinfo,ua,lang,dl,ul,ping,jitter,log,extra from speedtest_users order by timestamp desc limit 100");
				$q->execute();
			}else die();
		}
		while(true){
			$id=null; $timestamp=null; $ip=null; $ispinfo=null; $ua=null; $lang=null; $dl=null; $ul=null; $ping=null; $jitter=null; $log=null; $extra=null;
			if($db_type=="mysql"){
				if(!$q->fetch()) break;
			} else if($db_type=="sqlite"||$db_type=="postgresql"){
				if(!($row=$q->fetch())) break;
				$id=$row["id"];
				$timestamp=$row["timestamp"];
				$ip=$row["ip"];
				$ispinfo=$row["ispinfo"];
				$ua=$row["ua"];
				$lang=$row["lang"];
				$dl=$row["dl"];
				$ul=$row["ul"];
				$ping=$row["ping"];
				$jitter=$row["jitter"];
				$log=$row["log"];
				$extra=$row["extra"];
			}else die();
	?>
		<table>
			<tr><th>Test ID</th><td><?=htmlspecialchars(($enable_id_obfuscation?(obfuscateId($id)." (deobfuscated: ".$id.")"):$id), ENT_HTML5, 'UTF-8') ?></td></tr>
			<tr><th>Date and time</th><td><?=htmlspecialchars($timestamp, ENT_HTML5, 'UTF-8') ?></td></tr>
			<tr><th>IP and ISP Info</th><td><?=$ip ?><br/><?=htmlspecialchars($ispinfo, ENT_HTML5, 'UTF-8') ?></td></tr>
			<tr><th>User agent and locale</th><td><?=$ua ?><br/><?=htmlspecialchars($lang, ENT_HTML5, 'UTF-8') ?></td></tr>
			<tr><th>Download speed</th><td><?=htmlspecialchars($dl, ENT_HTML5, 'UTF-8') ?></td></tr>
			<tr><th>Upload speed</th><td><?=htmlspecialchars($ul, ENT_HTML5, 'UTF-8') ?></td></tr>
			<tr><th>Ping</th><td><?=htmlspecialchars($ping, ENT_HTML5, 'UTF-8') ?></td></tr>
			<tr><th>Jitter</th><td><?=htmlspecialchars($jitter, ENT_HTML5, 'UTF-8') ?></td></tr>
			<tr><th>Log</th><td><?=htmlspecialchars($log, ENT_HTML5, 'UTF-8') ?></td></tr>
			<tr><th>Extra info</th><td><?=htmlspecialchars($extra, ENT_HTML5, 'UTF-8') ?></td></tr>
		</table>
	<?php
		}
	?>

综合评价:利用条件极其苛刻,鸡肋漏洞。这种洞居然也是CVE,我真是服了。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大学侵权责任法试题及答案,分享几个实用搜题和学习工具 #其他#媒体#知识分享

当今社会&#xff0c;技术的发展给我们带来了许多便利&#xff0c;包括了许多实用的学习工具。 1.东西题库 这是一个网站 为学校教师提供试题试卷、课件及教案等服务的题库资源共享型网站&#xff0c;由必刷题、必刷卷教研团队研发与审核&#xff0c;涵盖初高中全学段、全学…

Foxmail邮箱的简单实用

Foxmail邮箱是我们办公邮箱中比较有代表性和使用性的一款邮箱软件&#xff0c;今天笔者为大家介绍一下Foxmail邮箱的功能和使用方法。 1、首先我们从安装Foxmail邮箱开始 2、点击安装等待安装成功 3、双击打开 &#xff0c;出现邮箱设置界面输入我们的账号密码&#xff0c;点击…

轻松解决问题!教你文件怎么解除只读模式!

在日常使用电脑时&#xff0c;我们有时会遇到文件或文件夹被设定为只读模式的情况&#xff0c;这可能会限制我们对文件的修改和编辑。然而&#xff0c;解除只读模式并获得文件的完全控制是一个相对简单的过程&#xff0c;只需要掌握一些基本的技巧和方法。在本文中&#xff0c;…

SpringBootWeb 篇-深入了解 AOP 面向切面编程与 AOP 记录操作日志案例

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 AOP 概述 1.1 构造简单 AOP 类 2.0 AOP 核心概念 2.1 AOP 执行流程 3.0 AOP 通知类型 4.0 AOP 通知顺序 4.1 默认按照切面类的类名字母排序 4.2 用 Order(数字) 注…

ubuntu-server(22.04)安装

准备工作 首先我们先从网上获取ubuntu的iso镜像文件 Index of /ubuntu-releases/22.04/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 我们安装这个最小包即可 找到我们ubuntu安装完成后所需要下载安装源的网址&#xff08;常用是阿里云&#xff09; ubuntu安装…

QT Creator与QT的下载安装

0.起因/小结&#xff1a; 因为运行项目需要更高版本的QT。 下载了QT 6.2.0&#xff0c;但是里面的gcc&#xff0c;g&#xff0c;gdb是64bit的&#xff0c;而我的QT Creator是32bit的&#xff0c;所以又下载了QT 13.0.0的64bit版本。 遇到问题&#xff1a;msvcp140_1.dll找不到…

TSINGSEE青犀视频:城市道路积水智能监管,智慧城市的守护者

随着城市化进程的加快&#xff0c;城市道路网络日益复杂&#xff0c;尤其在夏季&#xff0c;由于暴雨频发&#xff0c;道路积水问题成为影响城市交通和市民生活的重要因素之一。传统的道路积水监测方式往往依赖于人工巡逻和简单的监控设备&#xff0c;这些方法存在效率低下、响…

Qt5学习笔记(一):Qt Widgets Application项目初探

笔者长期使用MFC开发Windows GUI软件。随着软件向Linux平台迁移的趋势越发明朗&#xff0c;GUI程序的跨平台需求也越来越多。因此笔者计划重新抓一下Qt来实现跨平台GUI程序的实现。 0x01. 看看Qt Widgets Application项目结构 打开Qt5&#xff0c;点击“ New”按钮新建项目。…

C语言—内存函数

1. memcpy 使用和模拟实现 void* memcpy&#xff08;void* destination&#xff0c;const void* source&#xff0c;size_t num&#xff09;&#xff1b; 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。这个函数在遇到 ‘\0’ 的时候并不…

YOLOv8+PyQt5苹果叶病害检测(可以重新训练,yolov8模型,从图像、视频和摄像头三种路径识别检测)

效果视频&#xff1a;YOLOv8PyQt5苹果叶病害检测系统完整资源集合 资源包含可视化的苹果叶病害检测系统&#xff0c;基于最新的YOLOv8训练的苹果叶病害检测模型&#xff0c;和基于PyQt5制作的可视苹果叶病害系统&#xff0c;包含登陆页面和检测页面&#xff0c;该系统可自动检…

k8s AIOps

k8s AIOps 主要介绍下k8sgpt 官站 github 介绍 k8sgpt 是一个用于扫描Kubernetes集群、诊断和分级问题的工具。它以简单的英语呈现问题&#xff0c;并将站点可靠性工程&#xff08;SRE&#xff09;的经验编码到其分析器中。通过AI丰富问题的解释&#xff0c;k8sgpt帮助提取最…

简单聊下办公白环境

在当今信息化时代&#xff0c;办公环境对于工作效率和员工满意度有着至关重要的影响。而白名单作为一种网络安全策略&#xff0c;其是否适合办公环境&#xff0c;成为了许多企业和组织需要思考的问题。本文将从白名单的定义、特点及其在办公环境中的应用等方面&#xff0c;探讨…

企业数字化转型的主要方面有哪些?

本人研究企业数字化转型10余年&#xff0c;为企业软件选型、数字化提供咨询服务&#xff01;目前重点研究低代码数字化转型玩法&#xff0c;力争为各行各业探索出一条最具性价比的数字化方式。 关于“企业数字化转型包括哪些方面”这个问题&#xff0c;咱先来看个例子哈~ 比如…

常用的Linux命令,linux下文件的读、写、打开、关闭append用法

vim demoq.c打开写的.c文件 内容为 按a可以编辑页面代码。按ESC退出编辑然后按shift&#xff1a;wq保存文件并退出 Linux 系统中采用三位十进制数表示权限&#xff0c;如0755&#xff0c; 0644.7 124(可读、可写、可执行&#xff09; 5 14(可读、不可写、可执行&#xff09; …

西门子学习笔记9 - 中断式的触摸屏报警处理

Time delay interrupt"延时中断" OB&#xff08;达到设定延时时间后扫描一次程序&#xff0c;扫描完成后退出程序&#xff0c;继续执行主程序。&#xff09; 注&#xff1a;中断的触摸屏配置不需要改变&#xff0c;只是改变程序部分&#xff0c;在不需要使用的时候不…

WindowManager相关容器类

窗口中容器类介绍&#xff1a; 本节内容较多&#xff0c;建议结合前面的内容一起阅读&#xff1a; 1、addWindow的宏观概念 2、WindowManager#addView_1 3、WindowManager#addView_2 1&#xff09;、WindowContainer&#xff1a; class WindowContainer<E extends WindowC…

先激活还是先插卡?流量卡的激活顺序你知道吗?

拿到流量卡后&#xff0c;先激活还是先插卡吗&#xff1f;你知道是流量卡的激活顺序吗&#xff1f; 在这里&#xff0c;小编提醒大家&#xff0c;拿到卡后先别着急着操作&#xff0c;一定要先看一遍激活流程。 以下为流量卡的激活方法&#xff1a; 如果你是快递激活的话&…

ProxySQL + MySQL MGR 实现读写分离实战

文章目录 前言1、ProxySQL 介绍1.1、ProxySQL 如何工作1.2、ProxySQL 工作原理 2、ProxySQL 安装3、ProxySQL MGR 读写分离3.1、读写分离配置3.2、读写分离测试3.3、SpringBoot 整合 前言 该文章实践之前&#xff0c;需要搭建MySQL MGR集群&#xff0c;关于 MySQL MGR 集群搭…

Java 18 新功能概述

Java 18 在 2022 年 3 月 22 日正式发布&#xff0c;Java 18 不是一个长期支持版本。 包含多项新特性和改进&#xff0c;如文件系统链接、文本块、表达式求值API、ForkJoinPool优化、Optional新方法等。 亮点还包括预览特性&#xff1a;Record Pattern Matching for Switch和增…

BIM分析简明教程

大多数建筑师和工程师都会遇到过建筑信息模型 (BIM) 的概念。 这是一种可以为你的公司带来巨大利益的方法。 建筑信息模型允许你集中项目的信息。 你可以将所有相关数据集中到一个数据库中&#xff0c;而不是处理大量文档。 这样做的好处是显而易见的。 随着你的项目变得越来越…