Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4c779ce

Browse files
committed
Fix buffer overflow when parsing SCRAM verifiers in backend
Any authenticated user can overflow a stack-based buffer by changing theuser's own password to a purpose-crafted value. This often suffices toexecute arbitrary code as the PostgreSQL operating system account.This fix is contributed by multiple folks, based on an initial analysisfrom Tom Lane. This issue has been introduced by68e61ee, so it waspossible to make use of it at authentication time. It became moreeasily to trigger afterccae190 which has made the SCRAM parsing morestrict when changing a password, in the case where the client passesdown a verifier already hashed using SCRAM. Back-patch to v10 whereSCRAM has been introduced.Reported-by: Alexander LakhinAuthor: Jonathan Katz, Heikki Linnakangas, Michael PaquierSecurity:CVE-2019-10164Backpatch-through: 10
1 parent28dc2c2 commit4c779ce

File tree

3 files changed

+68
-8
lines changed

3 files changed

+68
-8
lines changed

‎src/backend/libpq/auth-scram.c

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,12 @@ scram_verify_plain_password(const char *username, const char *password,
543543
/*
544544
* Parse and validate format of given SCRAM verifier.
545545
*
546+
* On success, the iteration count, salt, stored key, and server key are
547+
* extracted from the verifier, and returned to the caller. For 'stored_key'
548+
* and 'server_key', the caller must pass pre-allocated buffers of size
549+
* SCRAM_KEY_LEN. Salt is returned as a base64-encoded, null-terminated
550+
* string. The buffer for the salt is palloc'd by this function.
551+
*
546552
* Returns true if the SCRAM verifier has been parsed, and false otherwise.
547553
*/
548554
bool
@@ -558,6 +564,8 @@ parse_scram_verifier(const char *verifier, int *iterations, char **salt,
558564
char*serverkey_str;
559565
intdecoded_len;
560566
char*decoded_salt_buf;
567+
char*decoded_stored_buf;
568+
char*decoded_server_buf;
561569

562570
/*
563571
* The verifier is of form:
@@ -590,36 +598,47 @@ parse_scram_verifier(const char *verifier, int *iterations, char **salt,
590598
* although we return the encoded version to the caller.
591599
*/
592600
decoded_salt_buf=palloc(pg_b64_dec_len(strlen(salt_str)));
593-
decoded_len=pg_b64_decode(salt_str,strlen(salt_str),decoded_salt_buf);
601+
decoded_len=pg_b64_decode(salt_str,strlen(salt_str),
602+
decoded_salt_buf);
594603
if (decoded_len<0)
595604
gotoinvalid_verifier;
596605
*salt=pstrdup(salt_str);
597606

598607
/*
599608
* Decode StoredKey and ServerKey.
600609
*/
601-
if (pg_b64_dec_len(strlen(storedkey_str)!=SCRAM_KEY_LEN))
602-
gotoinvalid_verifier;
610+
decoded_stored_buf=palloc(pg_b64_dec_len(strlen(storedkey_str)));
603611
decoded_len=pg_b64_decode(storedkey_str,strlen(storedkey_str),
604-
(char*)stored_key);
612+
decoded_stored_buf);
605613
if (decoded_len!=SCRAM_KEY_LEN)
606614
gotoinvalid_verifier;
615+
memcpy(stored_key,decoded_stored_buf,SCRAM_KEY_LEN);
607616

608-
if (pg_b64_dec_len(strlen(serverkey_str)!=SCRAM_KEY_LEN))
609-
gotoinvalid_verifier;
617+
decoded_server_buf=palloc(pg_b64_dec_len(strlen(serverkey_str)));
610618
decoded_len=pg_b64_decode(serverkey_str,strlen(serverkey_str),
611-
(char*)server_key);
619+
decoded_server_buf);
612620
if (decoded_len!=SCRAM_KEY_LEN)
613621
gotoinvalid_verifier;
622+
memcpy(server_key,decoded_server_buf,SCRAM_KEY_LEN);
614623

615624
return true;
616625

617626
invalid_verifier:
618-
pfree(v);
619627
*salt=NULL;
620628
return false;
621629
}
622630

631+
/*
632+
* Generate plausible SCRAM verifier parameters for mock authentication.
633+
*
634+
* In a normal authentication, these are extracted from the verifier
635+
* stored in the server. This function generates values that look
636+
* realistic, for when there is no stored verifier.
637+
*
638+
* Like in parse_scram_verifier(), for 'stored_key' and 'server_key', the
639+
* caller must pass pre-allocated buffers of size SCRAM_KEY_LEN, and
640+
* the buffer for the salt is palloc'd by this function.
641+
*/
623642
staticvoid
624643
mock_scram_verifier(constchar*username,int*iterations,char**salt,
625644
uint8*stored_key,uint8*server_key)

‎src/test/regress/expected/password.out

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,26 @@ SELECT rolpassword FROM pg_authid WHERE rolname='regress_passwd_empty';
100100

101101
(1 row)
102102

103+
-- Test with invalid stored and server keys.
104+
--
105+
-- The first is valid, to act as a control. The others have too long
106+
-- stored/server keys. They will be re-hashed.
107+
CREATE ROLE regress_passwd_sha_len0 PASSWORD 'SCRAM-SHA-256$4096:A6xHKoH/494E941doaPOYg==$Ky+A30sewHIH3VHQLRN9vYsuzlgNyGNKCh37dy96Rqw=:COPdlNiIkrsacU5QoxydEuOH6e/KfiipeETb/bPw8ZI=';
108+
CREATE ROLE regress_passwd_sha_len1 PASSWORD 'SCRAM-SHA-256$4096:A6xHKoH/494E941doaPOYg==$Ky+A30sewHIH3VHQLRN9vYsuzlgNyGNKCh37dy96RqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=:COPdlNiIkrsacU5QoxydEuOH6e/KfiipeETb/bPw8ZI=';
109+
CREATE ROLE regress_passwd_sha_len2 PASSWORD 'SCRAM-SHA-256$4096:A6xHKoH/494E941doaPOYg==$Ky+A30sewHIH3VHQLRN9vYsuzlgNyGNKCh37dy96Rqw=:COPdlNiIkrsacU5QoxydEuOH6e/KfiipeETb/bPw8ZIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=';
110+
-- Check that the invalid verifiers were re-hashed. A re-hashed verifier
111+
-- should not contain the original salt.
112+
SELECT rolname, rolpassword not like '%A6xHKoH/494E941doaPOYg==%' as is_rolpassword_rehashed
113+
FROM pg_authid
114+
WHERE rolname LIKE 'regress_passwd_sha_len%'
115+
ORDER BY rolname;
116+
rolname | is_rolpassword_rehashed
117+
-------------------------+-------------------------
118+
regress_passwd_sha_len0 | f
119+
regress_passwd_sha_len1 | t
120+
regress_passwd_sha_len2 | t
121+
(3 rows)
122+
103123
DROP ROLE regress_passwd1;
104124
DROP ROLE regress_passwd2;
105125
DROP ROLE regress_passwd3;
@@ -109,6 +129,9 @@ DROP ROLE regress_passwd6;
109129
DROP ROLE regress_passwd7;
110130
DROP ROLE regress_passwd8;
111131
DROP ROLE regress_passwd_empty;
132+
DROP ROLE regress_passwd_sha_len0;
133+
DROP ROLE regress_passwd_sha_len1;
134+
DROP ROLE regress_passwd_sha_len2;
112135
-- all entries should have been removed
113136
SELECT rolname, rolpassword
114137
FROM pg_authid

‎src/test/regress/sql/password.sql

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,21 @@ ALTER ROLE regress_passwd_empty PASSWORD 'md585939a5ce845f1a1b620742e3c659e0a';
7575
ALTER ROLE regress_passwd_empty PASSWORD'SCRAM-SHA-256$4096:hpFyHTUsSWcR7O9P$LgZFIt6Oqdo27ZFKbZ2nV+vtnYM995pDh9ca6WSi120=:qVV5NeluNfUPkwm7Vqat25RjSPLkGeoZBQs6wVv+um4=';
7676
SELECT rolpasswordFROM pg_authidWHERE rolname='regress_passwd_empty';
7777

78+
-- Test with invalid stored and server keys.
79+
--
80+
-- The first is valid, to act as a control. The others have too long
81+
-- stored/server keys. They will be re-hashed.
82+
CREATE ROLE regress_passwd_sha_len0 PASSWORD'SCRAM-SHA-256$4096:A6xHKoH/494E941doaPOYg==$Ky+A30sewHIH3VHQLRN9vYsuzlgNyGNKCh37dy96Rqw=:COPdlNiIkrsacU5QoxydEuOH6e/KfiipeETb/bPw8ZI=';
83+
CREATE ROLE regress_passwd_sha_len1 PASSWORD'SCRAM-SHA-256$4096:A6xHKoH/494E941doaPOYg==$Ky+A30sewHIH3VHQLRN9vYsuzlgNyGNKCh37dy96RqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=:COPdlNiIkrsacU5QoxydEuOH6e/KfiipeETb/bPw8ZI=';
84+
CREATE ROLE regress_passwd_sha_len2 PASSWORD'SCRAM-SHA-256$4096:A6xHKoH/494E941doaPOYg==$Ky+A30sewHIH3VHQLRN9vYsuzlgNyGNKCh37dy96Rqw=:COPdlNiIkrsacU5QoxydEuOH6e/KfiipeETb/bPw8ZIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=';
85+
86+
-- Check that the invalid verifiers were re-hashed. A re-hashed verifier
87+
-- should not contain the original salt.
88+
SELECT rolname, rolpassword notlike'%A6xHKoH/494E941doaPOYg==%'as is_rolpassword_rehashed
89+
FROM pg_authid
90+
WHERE rolnameLIKE'regress_passwd_sha_len%'
91+
ORDER BY rolname;
92+
7893
DROP ROLE regress_passwd1;
7994
DROP ROLE regress_passwd2;
8095
DROP ROLE regress_passwd3;
@@ -84,6 +99,9 @@ DROP ROLE regress_passwd6;
8499
DROP ROLE regress_passwd7;
85100
DROP ROLE regress_passwd8;
86101
DROP ROLE regress_passwd_empty;
102+
DROP ROLE regress_passwd_sha_len0;
103+
DROP ROLE regress_passwd_sha_len1;
104+
DROP ROLE regress_passwd_sha_len2;
87105

88106
-- all entries should have been removed
89107
SELECT rolname, rolpassword

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp