CTF 全讲解:[SWPUCTF 2021 新生赛]jicao

文章目录

  • 参考
  • 环境
  • 题目
  • index.php
      • highlight_file()
      • include()
        • 多次调用,多次执行
        • 单次调用,单次执行
      • $_POST
        • 超全局变量
        • HackBar
          • HackBar 插件的获取
        • $_POST
          • 打开 HackBar 插件
          • 通过 HackBar 插件发起 POST 请求
      • GET 请求
        • 查询字符串
        • 超全局变量 $_GET
      • JSON
        • JSON 数据格式
          • JSON 基本结构
        • json_decode()
      • 弱比较
        • 隐式类型转换
          • 字符串连接
          • 数学运算
          • 布尔判断
        • 相等运算符
  • 进攻
      • 整体分析
      • 构造数据
      • 攻击
      • 为什么 id 不能等于 0

参考

项目 描述
搜索引擎 BingGoogle
AI 大模型 文心一言通义千问讯飞星火认知大模型ChatGPT
PHP 手册 PHP Manual

环境

项目 描述
PHP 5.5.05.6.87.0.07.2.57.4.98.0.08.2.9

题目

项目 描述
得分项 HTTP 请求方法JSON 数据格式发起 POST 请求
题目来源 NSSCTF

index.php

访问题目首页 index.php,你将得到如下 PHP 代码。


highlight_file('index.php');
include("flag.php");
$id=$_POST['id'];
$json=json_decode($_GET['json'],true);
if ($id=="wllmNB"&&$json['x']=="wllm")
{echo $flag;}
?>

接下来,让我们对 index.php 中的代码逐一进行讲解。

highlight_file()

highlight_file() 函数是 PHP 提供的一个用于 PHP 代码高亮显示 的函数,使用该函数将能够获取到 指定文件中的内容 通过 HTML 标签 实现高亮显示的结果。

highlight_file(string $filename, bool $return = false): string|bool

其中:

项目 描述
$filename 欲高亮显示的文件的 路径
$return 若该参数的值为 true,则 highlight_file() 函数将返回文件高亮处理后的 HTML 文本,而不是将其 直接 输出。

举个栗子



// 按照一定规则通过 HTML 标签高亮显示
// 指定 PHP 文件中的内容。
highlight_file(__FILE__);

// 通过在网页中嵌入 HTML 标签 
// 实现换行效果。 echo '
'
; var_dump('Hello World');

注:

在 PHP 中,__FILE__ 是一个包含当前 正在执行的 PHP 文件字符串形式的完整路径 的内置全局常量。

执行效果

执行 highlight_file(__FILE__); 后,PHP 会自动将全局变量 __FILE__ 所指向的文件中的内容 高亮处理后得到的 HTML 文本进行输出。尝试通过浏览器访问 __FILE__ 所指向的文件将得到类似如下效果:

CTF 全讲解:[SWPUCTF 2021 新生赛]jicao_第1张图片

highlight_file() 高亮处理目标文件后得到的 HTML 文本如下:

<code><span style="color: #000000">
<br />span><span style="color: #0000BB">var_dumpspan><span style="color: #007700">(span><span style="color: #DD0000">'Hello World'span><span style="color: #007700">);span>
span>
code>

注:

highlight_file() 函数 并不是仅能够 对 PHP 代码进行高亮处理,实际上,highlight_file() 函数将通过 PHP 内置的语法高亮器 按照一定的高亮规则对文件中 后与?>(可被省略) 前的内容进行高亮处理。对此,请参考如下示例:



// 按照一定规则通过 HTML 标签高亮显示
// 指定 PHP 文件中的内容。
highlight_file('./calc.js');

// 通过在网页中嵌入 HTML 标签 
// 实现换行效果。 echo '
'
; var_dump('Hello World');

calc.js 文件中的内容



foreach(str_split('Hello World') as $char){
    print($char . "\n");
}

执行效果

CTF 全讲解:[SWPUCTF 2021 新生赛]jicao_第2张图片

include()

在 PHP 中,include 函数常用于将一个文件的内容包含到另一个 PHP 文件中,以便在多个文件中共享相同的代码,提高代码的可维护性和重用性。与 include 函数起着相同功能还有 require 函数。

举个栗子




# 包含文件 another.php
include('another.php');

# 被 include 包含的内容可以理解为
# 与相关的 include 语句发生了跨文件的覆盖。

# 实例化 MyClass 类对象
$myClass = new MyClass();

# 尝试获取 myClass 对象的属性
print($myClass -> name . "\n");
print($myClass -> nation . "\n");
# 尝试调用 myClass 对象的方法
$myClass -> sayHello();

上述 PHP 代码尝试通过调用 include 函数来包含文件 another.phpanother.php 文件的具体内容如下:




# 定义一个名为 MyClass 的类
class MyClass
{
    public $name = 'RedHeart';
    public $nation = 'China';

    public function sayHello(){
        print('Hello World' . "\n");
    }
}

执行效果

RedHeart
China
Hello World

多次调用,多次执行

每当你通过调用 includerequire 函数来包含其他文件中的内容时,被包含文件中的内容都将 立即被 PHP 解释器执行,当你对某一文件进行 多次包含操作 时,该文件的内容 将被执行多次。对此,请参考如下示例:




include('./another.php');
include('./another.php');
include('./another.php');

require('./another.php');
require('./another.php');
require('./another.php');

another.php 文件的具体内容如下:




print('Hello World' . "\n");

执行效果

Hello World
Hello World
Hello World
Hello World
Hello World
Hello World

单次调用,单次执行

includerequire 函数多次调用多次执行的特性可能导致 数据被污染程序性能下降等问题,在大型项目中尤其如此。使用 require_onceinclude_once 函数代替 requireinclude 函数执行文件包含操作将能够拒绝隐患的发生。对此,请参考如下示例:




# ./another.php 文件中的内容保持不变
include('./another.php');
require_once('./another.php');
include_once('./another.php');

执行效果

无论使用 includerequireinclude_oncerequire_once 中的哪一个函数包含文件,再次使用 include_oncerequire_once 包含 相同文件 都将导致文件 包含失败,或者说文件 执行失败

Hello World

$_POST

超全局变量

在 PHP 中,超全局变量(Superglobals) 是一类特殊的变量,这些变量在脚本的任何地方都可以访问,而无需使用 global 关键字或其他特殊的语法。超全局变量在 PHP 中起着重要的作用,用于存储和传递与请求、会话、服务器配置等相关的信息

PHP 中常用到的超全局变量:

项目 描述
$_POST $_POST 是 PHP 中用于处理从客户端通过 POST 方法 提交的数据的 超全局变量,该变量 允许你访问通过 HTTP POST 请求传递到服务器的数据
$_GET $_GET 用于获取客户端通过 URL 的 查询字符串 传递的参数。
$_COOKIE $_COOKIE 用于获取客户端发送的 Cookie 数据。
$_SESSION $_SESSION 用于在服务器端 存储和访问会话数据,该变量允许你 在不同页面之间共享和保持用户会话数据
$_SERVER $_SERVER 包含有关 服务器当前请求的相关信息(例如请求的 URL、请求方法、服务器的 IP 地址)

注:

大多数 的超全局变量都存储着一个 关联数组(上述列举的超全局变量均是如此),其中的每个元素对应一个与超全局变量功能相关的信息。

HackBar

Hackbar 是一个 浏览器扩展,该扩展工具为安全专家、渗透测试人员和开发人员提供了一组工具,用于测试和评估 Web 应用程序的安全性HackBar 可以帮助用户识别潜在的安全漏洞,进行渗透测试,以及执行各种与网络安全相关的任务。以下是 Hackbar 的一些 主要 特点和功能:

  1. HTTP 请求和响应拦截
    HackBar 允许用户 查看编辑浏览器发送的 HTTP 请求报文及接收到的 HTTP 响应报文。在需要的时候,你可以通过 修改 HTTP 请求报文 来实现 对请求的精细化控制

  2. Cookie 编辑和管理
    HackBar 允许用户轻松编辑和管理浏览器中的 Cookie,这对于模拟不同的用户会话非常有用。

  3. 表单处理
    HackBar 提供了表单提交和数据包装功能,以帮助用户测试应用程序的输入验证和表单处理。你 可以手动构建 POST 或 GET 请求,并查看服务器对此进行的响应

  4. 编码和加密工具
    HackBar 包括一些编码和加密工具,可用于处理 Base64MD5SHA1 等的相关数据。

  5. XSS 攻击测试
    HackBar 提供了一些工具,用于 检测和测试跨站脚本(XSS)漏洞

  6. SQL 注入测试
    HackBar 还包括用于 测试 SQL 注入漏洞 的工具,可以帮助用户评估 Web 应用程序的数据库安全性。

由于微软的 Edge 浏览器的插件官网没有提供 HackBar 这款扩展工具,而 Google 的 Chrome 浏览器的插件官网由需要科学上网,所以推荐需要这款插件的朋友可以使用 Firefox 浏览器。

HackBar 插件的获取

首先,打开 Firefox 浏览器并进入其 插件官网,搜索插件 HackBar,你将得到如下类似界面。

CTF 全讲解:[SWPUCTF 2021 新生赛]jicao_第3张图片

选择图中 红色箭头指向的两个插件中的其中一个 进行安装即可。

$_POST



# 超全局变量 $_POST 保持着一个关联数组
var_dump($_POST);

# 输出一个具有换行功能的 HTML 标签
echo '
'
; # 获取名为 X 的 POST 参数的值 var_dump($_POST['X']);

访问上述 PHP 页面,你将得到如下内容:

PHP 解释器抛出了 Notice 异常信息,这是由于我们还未提交 POST 数据,导致 $_POST['X'] 正在 尝试访问一个不存在的元素 从而引发了异常。

打开 HackBar 插件

右键 当前页面,得到如下类似界面:

CTF 全讲解:[SWPUCTF 2021 新生赛]jicao_第4张图片

点击其中的 检查,得到如下类似界面:

CTF 全讲解:[SWPUCTF 2021 新生赛]jicao_第5张图片

选择其中的 HackBar 分栏,得到如下类似界面:

CTF 全讲解:[SWPUCTF 2021 新生赛]jicao_第6张图片

通过 HackBar 插件发起 POST 请求

点击 LOAD 按钮 加载与当前页面相关的 URL 至输入框中,当然你也可以自己输入 URL,URL 所指向的页面是插件将处理的页面,不一定需要是当前页面的 URL。

点击 Use POST method 旁边的按钮尝试进行 POST 请求,enctype 下拉框中提供了 可供选择的 POST 请求数据的编码方式

CTF 全讲解:[SWPUCTF 2021 新生赛]jicao_第7张图片

默认选项 application/x-www-form-urlencode 允许我们使用 同 URL 查询字符串相同的格式编写 POST 数据。于是构造如下 POST 数据:

name=RedHeart&X=BinaryMoon&special_symbol=%26%25%24

点击 EXECUTE 发起请求,得到如下类似界面:

CTF 全讲解:[SWPUCTF 2021 新生赛]jicao_第8张图片

GET 请求

查询字符串

在 Web 开发中,查询字符串(Query String) 是指 URL 中位于 问号 ? 后的 部分 文本。查询字符串常用于客户端浏览器 通过 URL 传递数据给服务器
查询字符串由 一个或多个参数 组成,每个参数之间使用 & 符号 进行 分隔

举个栗子

https://example.com/index.php?ID=1&UserName=RedHeart#BinaryMoon

在上述 URL 中,查询字符串为 ID=1&UserName=RedHeart,其中包含两个参数,即 ID=1UserName=RedHeart。这意味着,参数名为 ID 的参数对应的参数值为 1,而参数名为 UserName 参数对应的参数值为 RedHeart

超全局变量 $_GET

在 PHP 中,可以使用超全局变量 $_GET 来获取由浏览器客户端提交的查询字符串中的 参数信息$_GET 是一个 关联数组,其中的 为查询字符串中的参数名, 为参数对应的值。

index.php 页面所包含的内容



// 获取由查询字符串中的参数组成的关联数组
var_dump($_GET);

// 通过向网页中输入一个 
HTML 标签来实现换行的效果
echo '
'
; // 获取查询字符串中参数名为 Name 的参数所对应的参数值 var_dump($_GET['Name']);

执行效果

在客户端浏览器访问 index.php 页面后,服务器端的输出结果。

array(2) { ["Name"]=> string(8) "RedHeart" ["Host"]=> string(10) "BinaryMoon" }
string(8) "RedHeart"

JSON

JSON 数据格式

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,它以易于阅读和编写的文本形式表示数据。JSON 最初是为JavaScript开发 的,但已成为一种 通用的数据格式,常用于数据存储与交换。

JSON 数据格式的特点

优势 具体描述
键值对结构 JSON 数据是以 键值对 的形式表示的,键值对的结构使得 JSON 非常适合表示结构化数据
跨语言兼容性 JSON 是一种 独立于编程语言的数据格式,因此 可以在不同编程语言之间轻松传输和解析数据,几乎所有现代编程语言都支持 JSON 的编码和解码。
支持的数据类型 JSON 支持多种数据类型,包括 字符串数字布尔值数组null 以及 JSON
不支持注释 JSON 主要用于对数据的描述,故 JSON 不支持注释,这意味着你 不能在 JSON 数据中添加注释以解释数据的含义
无循环引用 JSON 不支持循环引用,也就是说,JSON 中的键值对不能引用包含它的对象,这有助于避免数据结构的无限递归。
支持嵌套 JSON 内部可以嵌套 JSON 数据。

JSON 的典型用途包括 配置文件API 数据交换日志记录 和各种应用程序中的数据传输和存储。JSON 的 简洁性通用性 使它成为一种流行的数据交换格式,广泛应用于Web开发、移动应用程序和云计算等领域。

JSON 基本结构

JSON 数据是由一组 键值对 组成的,其中键是字符串,值可以是 字符串数值布尔值数组JSONnull
JSON 对象使用花括号 {} 包围,键与值之间使用冒号 : 分隔,键值对之间使用逗号 , 分隔。
JSON 数组使用方括号 [] 包围,数组元素之间使用逗号 , 分隔。

举个栗子

{
  "name": "John",
  "age": 30,
  "hometown": "New York",
  "pets": [
    {
      "name": "Fido",
      "species": "dog"
    },
    {
      "name": "Fluffy",
      "species": "cat"
    }
  ],
  "car": null
}

注:

  1. JSON 数据中,键必须为字符串,而值可以是 字符串数值布尔值数组JSONnull
  2. JSON 格式中,字符串 必须使用双引号而不能使用单引号
json_decode()

json_decode() 是 PHP 中的一个 内置函数,用于将 JSON 解析为 PHP 数据。
json_decode() 中存在参数 $associative,默认值为 false。参数 $associative 用于指定是否将 JSON 解析为 关联数组,若该参数的值为 true,则 json_decode() 函数将返回一个关联数组;否则,返回一个 PHP 对象。对此,请参考如下示例:




# 定义 JSON 数据
$json_content = '{
    "name": "John",
    "age": 30,
    "hometown": "New York",
    "pets": [
        {
            "name": "Fido",
            "species": "dog"
        },
        {
            "name": "Fluffy",
            "species": "cat"
        }
    ],
    "car": null
}';

print('【将 JSON 数据解析为对象进行返回】' . "\n");
$result_1 = json_decode($json_content);
var_dump($result_1);

print("\n" . '【将 JSON 数据解析为关联数组进行返回' . "\n");
$result_2 = json_Decode($json_content, true);
var_dump($result_2);

执行效果

【将 JSON 数据解析为对象进行返回】
object(stdClass)#1 (5) {
  ["name"]=>
  string(4) "John"
  ["age"]=>
  int(30)
  ["hometown"]=>
  string(8) "New York"
  ["pets"]=>
  array(2) {
    [0]=>
    object(stdClass)#2 (2) {
      ["name"]=>
      string(4) "Fido"
      ["species"]=>
      string(3) "dog"
    }
    [1]=>
    object(stdClass)#3 (2) {
      ["name"]=>
      string(6) "Fluffy"
      ["species"]=>
      string(3) "cat"
    }
  }
  ["car"]=>
  NULL
}

【将 JSON 数据解析为关联数组进行返回
array(5) {
  ["name"]=>
  string(4) "John"
  ["age"]=>
  int(30)
  ["hometown"]=>
  string(8) "New York"
  ["pets"]=>
  array(2) {
    [0]=>
    array(2) {
      ["name"]=>
      string(4) "Fido"
      ["species"]=>
      string(3) "dog"
    }
    [1]=>
    array(2) {
      ["name"]=>
      string(6) "Fluffy"
      ["species"]=>
      string(3) "cat"
    }
  }
  ["car"]=>
  NULL
}

弱比较

隐式类型转换

在 PHP 中,隐式类型转换(Implicit Type Conversion) 是指在某些操作中,PHP 会 自动 将数据 由一种数据类型转换为另一个数据类型,而 无需显式 地编写 类型转换 代码。

PHP 的隐式类型转换会按照一定规则(具体情况具体分析)对操作数进行转换,以使得相关操作 能够正常进行 下去。

字符串连接

在通过使用句点运算符 . 进行字符串连接操作时,PHP 将会尝试将其他数据类型 转换为字符串数据类型。对此,请参考如下示例:



// 尝试将两个字符串进行拼接
var_dump('Hello ' . 'World');

// 尝试将数值与字符串进行拼接
var_dump('1 + 1 = ' . 2);

// 尝试将两个数值进行拼接
var_dump(1 . 1);

执行效果

string(11) "Hello World"
string(9) "1 + 1 = 2"
string(2) "11"
数学运算

在通过 数学运算符 进行数学运算时,PHP 将会尝试将其他数据类型的数据 转换为数值类型。对此,请参考如下示例:



// 尝试对布尔值 true 与数值 1 进行减法运算
var_dump(true - 1);

// 尝试对布尔值 true 与 false 进行加法运算
var_dump(true + false);

// 尝试进行字符串之间的乘法运算
var_dump('2' * '150');

// 字符串 100djdj 将被转换为 100
var_dump('100djdj' / 10);

// 字符串 djdj100 将被转换为零
var_dump('djdj100' / 10);

执行效果

int(0)
int(1)
int(300)
int(10)
int(0)
布尔判断

在需要使用布尔值的位置,PHP 将尝试将非布尔值的数据 转换为布尔类型的数据。对此,请参考如下示例:



// 尝试将空字符串转换为布尔值
if(''){
    print('Hello World' . "\n");
}

// 尝试将字符串 Hello World 转换为布尔值
if('Hello World'){
    print('Hello China' . "\n");
}

// 尝试将数值 999 转换为布尔值
if(999){
    print('久久久' . "\n");
}

执行效果

Hello China
久久久
相等运算符

在 PHP 中存在两种相等运算符,即弱类型相等运算符 == 和强类型相等运算符 ===,两者都可以用于判断两个操作数是否相等,但存在一些区别。

两者的 区别 在于,弱类型相等运算符 在对操作数进行比较之前,将 自动 进行类型转换以 使两者所属的数据类型相同。而 强类型相等运算符 在进行比较时,要求两个值的 类型 都必须 完全相同不进行类型转换。对此,请参考如下示例:



// 在通过弱类型比较运算符对数值与字符串进
// 行比较时,PHP 优先将字符串转换为数值。

// 由于两者转换为同一类型后,值相同,
// 故将返回 true。
var_dump('123' == 123);

// 由于两者的数据类型及值均不相同,故
// 将返沪 false。
var_dump('123' === 123);

执行效果

bool(true)
bool(false)

进攻

整体分析

让我们对 index.php 的整体进行分析:


highlight_file('index.php');
include("flag.php");
$id=$_POST['id'];
$json=json_decode($_GET['json'],true);
if ($id=="wllmNB"&&$json['x']=="wllm")
{echo $flag;}
?>

首先,该页面通过 highlight_file() 函数将当前页面的内容以高亮的形式显示出来,这使得在访问 index.php 页面时能够看到该页面的 PHP 代码而 不是一片空白(访问 PHP 页面通常能够看到的是服务器端响应的内容而不是该页面的源代码)。
其次,该页面通过调用 include() 函数将 flag.php 页面中的内容包含到当前页面。正常情况下,包含 flag 的名称进行命名的文件通常包含了我们所需要的 flag。在该页面代码下方的判断语句中出现了 未在当前页面定义的变量 $flag,所以我们的目标也变明确了,即 绕过判断语句使服务器返回 $flag 变量中的值
最后,该页面通过获取 GETPOST 方式提交的数据来 得到两个比较对象。我们的任务是 构造合适的 GET 与 POST 数据来使得判断语句成立以执行其中的代码

构造数据

根据判断语句,客户端提交的数据需要满足 $id=="wllmNB"$json['x']=="wllm"。故构造查询字符串:

?json={"x": "wllm"}

构造 POST 数据:

id=wllmNB

攻击

将构造的数据准备好后向服务器发起请求,得到如下界面:

CTF 全讲解:[SWPUCTF 2021 新生赛]jicao_第9张图片

至此,得到 flag

为什么 id 不能等于 0

了解 PHP 弱比较的同学可能会想着通过 POST 提交数据 id=0 来使得判断语句成立。这是由于在 PHP 中,倘若 数值与字符串进行弱比较,则 PHP 会优先将字符串转化为数值后再进行比较。而 wllmNB 转化为数值的结果为零,与 $id 的比较结果将为 true
这样思考有一定的依据,但 忽略了一个事实,即通过 POSTGET 向服务器提交的数据都将以 字符串的方式 存储在 $_GET$_POST 中。你以为提交 POST 数据 id=1 后,$id 中存储的数据将为 数值 1 ,而实际上 $id 中存储的数据为 字符串 1,因此也就不存在数值与字符串的弱比较了,故 id 不能等于 0 。对此,请参考如下示例:




var_dump($_POST['X']);

echo '
'
; var_dump($_GET['X']);

执行效果

CTF 全讲解:[SWPUCTF 2021 新生赛]jicao_第10张图片

你可能感兴趣的:(安全,PHP,HTTP,请求方法,POST,请求,超全局变量,弱比较,HackBar)