閱讀562 返回首頁    go 阿裏雲 go 技術社區[雲棲]


解讀2017-08-10發布的幾個安全漏洞

標簽

PostgreSQL , 安全漏洞 , CVE-2017-7546 , CVE-2017-7547 , CVE-2017-7548


背景

PostgreSQL 社區於08-10發布了新版本,修複了三個安全漏洞。

https://www.postgresql.org/about/news/1772/

CVE-2017-7546:   
Empty password accepted in some authentication methods  
  
CVE-2017-7547:   
The "pg_user_mappings" catalog view discloses passwords to users lacking server privileges  
  
CVE-2017-7548:   
lo_put() function ignores ACLs  

下麵一一進行解讀。

CVE-2017-7546 允許空密碼登陸漏洞

注意,libpq接口的客戶端,都會自動拒絕空密碼的用戶登陸,這個行為可能誤導用戶認為空密碼就是不允許登陸的。

而實際上並非如此,其他客戶端驅動可能允許空密碼登陸,這個漏洞修複了這個問題。在服務端拒絕空密碼的用戶登陸。

所以你如果不使用空密碼,就不會有這個問題。

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=bf6b9e94445610a3d84cf9521032fab993f96fd6

Don't allow logging in with empty password.  
  
Some authentication methods allowed it, others did not. In the client-side,  
libpq does not even try to authenticate with an empty password, which makes  
using empty passwords hazardous: an administrator might think that an  
account with an empty password cannot be used to log in, because psql  
doesn't allow it, and not realize that a different client would in fact  
allow it. To clear that confusion and to be be consistent, disallow empty  
passwords in all authentication methods.  
  
All the authentication methods that used plaintext authentication over the  
wire, except for BSD authentication, already checked that the password  
received from the user was not empty. To avoid forgetting it in the future  
again, move the check to the recv_password_packet function. That only  
forbids using an empty password with plaintext authentication, however.  
MD5 and SCRAM need a different fix:  
  
* In stable branches, check that the MD5 hash stored for the user does not  
not correspond to an empty string. This adds some overhead to MD5  
authentication, because the server needs to compute an extra MD5 hash, but  
it is not noticeable in practice.  
  
* In HEAD, modify CREATE and ALTER ROLE to clear the password if an empty  
string, or a password hash that corresponds to an empty string, is  
specified. The user-visible behavior is the same as in the stable branches,  
the user cannot log in, but it seems better to stop the empty password from  
entering the system in the first place. Secondly, it is fairly expensive to  
check that a SCRAM hash doesn't correspond to an empty string, because  
computing a SCRAM hash is much more expensive than an MD5 hash by design,  
so better avoid doing that on every authentication.  
  
We could clear the password on CREATE/ALTER ROLE also in stable branches,  
but we would still need to check at authentication time, because even if we  
prevent empty passwords from being stored in pg_authid, there might be  
existing ones there already.  
  
Reported by Jeroen van der Ham, Ben de Graaff and Jelte Fennema.  
  
Security: CVE-2017-7546  

CVE-2017-7547 允許未授予USAGE權限的用戶讀取foreign server配置

這個漏洞和foreign server有關,通常某個用戶u1要使用FOREIGN SERVER需要分為幾個步驟。

1、創建foreign server S1,裏麵包含SERVER的連接信息。

2、賦予foreign server S1的usage權限給某個用戶u1。(本漏洞所在。)

3、基於這個foreign server S1創建u1的user mapping,裏麵包含登陸這個foreign server的信息。

4、現在u1可以基於這個foreign server S1創建外部表。

現在的漏洞是,沒有操作第2步,普通用戶u1可以查詢pg_user_mapping表,得到登陸這個foreign server的信息(例如連接這個外部server的用戶和密碼)。

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=e568e1eee4650227170cf8c64eedb74bafd7d1f0

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=3eefc51053f250837c3115c12f8119d16881a2d7

Again match pg_user_mappings to information_schema.user_mapping_options.  
  
Commit 3eefc51053f250837c3115c12f8119d16881a2d7 claimed to make  
pg_user_mappings enforce the qualifications user_mapping_options had  
been enforcing, but its removal of a longstanding restriction left them  
distinct when the current user is the subject of a mapping yet has no  
server privileges.  user_mapping_options emits no rows for such a  
mapping, but pg_user_mappings includes full umoptions.  Change  
pg_user_mappings to show null for umoptions.  Back-patch to 9.2, like  
the above commit.  
  
Reviewed by Tom Lane.  Reported by Jeff Janes.  
  
Security: CVE-2017-7547  

https://git.postgresql.org/gitweb/?p=postgresql.git;a=blobdiff;f=src/test/regress/expected/foreign_data.out;h=927d0189a0c26c5875cbe5af44d71d3819bd34eb;hp=7f2f529393d6682a69702cb32d3975074b97f87d;hb=e568e1eee4650227170cf8c64eedb74bafd7d1f0;hpb=bf6b9e94445610a3d84cf9521032fab993f96fd6

已修複後,例子

-GRANT USAGE ON FOREIGN SERVER s10 TO regress_unprivileged_role;  
--- owner of server can see option fields  
+CREATE USER MAPPING FOR regress_unprivileged_role SERVER s10 OPTIONS (user 'secret');  
  
+-- unprivileged user cannot see any option field  
 SET ROLE regress_unprivileged_role;  
 \deu+  
               List of user mappings  
  Server |         User name         | FDW options   
 --------+---------------------------+-------------  
  s10    | public                    |   
+ s10    | regress_unprivileged_role | -- 未修複時,這裏會顯示user 'secret'  
  s4     | regress_foreign_data_user |   
  s5     | regress_test_role         |   
  s6     | regress_test_role         |   

老版本要修複這個問題,請參考 https://www.postgresql.org/about/news/1772/ ,需要修改係統表的信息。

所以,如果你繼續使用老版本,你要回收某個用戶的foreign server權限,請同時刪除user mapping。就不會有問題。

CVE-2017-7548 大對象操作函數lo_put()未檢測寫權限

漏洞描述:

在沒有某個大對象的UPDATE權限時,用戶依舊可以使用lo_put()函數操作這個大對象。

修複後,需要賦予這個大對象UPDATE權限,才可以調用lo_put()操作這個大對象。

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=8d9881911f0d30e0783a6bb1363b94a2c817433d

Require update permission for the large object written by lo_put().  
  
lo_put() surely should require UPDATE permission, the same as lowrite(),  
but it failed to check for that, as reported by Chapman Flack.  Oversight  
in commit c50b7c09d; backpatch to 9.4 where that was introduced.  
  
Tom Lane and Michael Paquier  
  
Security: CVE-2017-7548  

修複後的例子如下

src/test/regress/expected/privileges.out

SET SESSION AUTHORIZATION regress_user1;  
1186 SELECT lo_create(1001);  
1187  lo_create   
1188 -----------  
1189       1001  
1190 (1 row)  
1191   
1192 SELECT lo_create(1002);  
1193  lo_create   
1194 -----------  
1195       1002  
1196 (1 row)  
1197   
  
  
1216 GRANT ALL ON LARGE OBJECT 1001 TO PUBLIC;  
1217 GRANT SELECT ON LARGE OBJECT 1003 TO regress_user2;  
1218 GRANT SELECT,UPDATE ON LARGE OBJECT 1004 TO regress_user2;  
1219 GRANT ALL ON LARGE OBJECT 1005 TO regress_user2;  
1220 GRANT SELECT ON LARGE OBJECT 1005 TO regress_user2 WITH GRANT OPTION;  
1221 GRANT SELECT, INSERT ON LARGE OBJECT 1001 TO PUBLIC;    -- to be failed  
1222 ERROR:  invalid privilege type INSERT for large object  
1223 GRANT SELECT, UPDATE ON LARGE OBJECT 1001 TO nosuchuser;    -- to be failed  
1224 ERROR:  role "nosuchuser" does not exist  
1225 GRANT SELECT, UPDATE ON LARGE OBJECT  999 TO PUBLIC;    -- to be failed  
1226 ERROR:  large object 999 does not exist  
1227 \c -  
  
1228 SET SESSION AUTHORIZATION regress_user2;  
  
1299 -- confirm ACL setting  
1300 SELECT oid, pg_get_userbyid(lomowner) ownername, lomacl FROM pg_largeobject_metadata WHERE oid >= 1000 AND oid < 3000 ORDER BY oid;  
1301  oid  |   ownername   |                                             lomacl                                               
1302 ------+---------------+------------------------------------------------------------------------------------------------  
1303  1001 | regress_user1 | {regress_user1=rw/regress_user1,=rw/regress_user1}  
1304  1002 | regress_user1 |   
1305  1003 | regress_user1 | {regress_user1=rw/regress_user1,regress_user2=r/regress_user1}  
1306  1004 | regress_user1 | {regress_user1=rw/regress_user1,regress_user2=rw/regress_user1}  
1307  1005 | regress_user1 | {regress_user1=rw/regress_user1,regress_user2=r*w/regress_user1,regress_user3=r/regress_user2}  
1308  2001 | regress_user2 | {regress_user2=rw/regress_user2,regress_user3=rw/regress_user2}  
1309 (6 rows)  
  
  
+SELECT loread(lo_open(1001, x'20000'::int), 32);   -- allowed, for now  
+ loread   
+--------  
+ \x  
+(1 row)  
+  
+SELECT lowrite(lo_open(1001, x'40000'::int), 'abcd');  -- fail, wrong mode  
+ERROR:  large object descriptor 0 was not opened for writing  
  
+SELECT lo_put(1002, 1, 'abcd');                -- to be denied  
+ERROR:  permission denied for large object 1002  

最後更新:2017-08-20 17:06:16

  上一篇:go  如何檢測、清理Greenplum垃圾 - 阿裏雲HybridDB for PG最佳實踐
  下一篇:go  PostgreSQL on ECS多雲盤的部署、快照備份和恢複