Skip to content

Commit 2528877

Browse files
author
Julien Pivotto
authored
Merge pull request from GHSA-7rg2-cxvp-9p7p
* Fix authentication bypass if stored password hash is known Signed-off-by: Julien Pivotto <[email protected]> * Add test for CVE-2022-46146 Signed-off-by: Julien Pivotto <[email protected]> Signed-off-by: Julien Pivotto <[email protected]>
1 parent 48868f5 commit 2528877

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

web/handler.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"encoding/hex"
2020
"fmt"
2121
"net/http"
22+
"strings"
2223
"sync"
2324

2425
"github.com/go-kit/log"
@@ -113,7 +114,12 @@ func (u *webHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
113114
hashedPassword = "$2y$10$QOauhQNbBCuQDKes6eFzPeMqBSjb7Mr5DUmpZ/VcEd00UAV/LDeSi"
114115
}
115116

116-
cacheKey := hex.EncodeToString(append(append([]byte(user), []byte(hashedPassword)...), []byte(pass)...))
117+
cacheKey := strings.Join(
118+
[]string{
119+
hex.EncodeToString([]byte(user)),
120+
hex.EncodeToString([]byte(hashedPassword)),
121+
hex.EncodeToString([]byte(pass)),
122+
}, ":")
117123
authOk, ok := u.cache.get(cacheKey)
118124

119125
if !ok {
@@ -122,7 +128,7 @@ func (u *webHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
122128
err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(pass))
123129
u.bcryptMtx.Unlock()
124130

125-
authOk = err == nil
131+
authOk = validUser && err == nil
126132
u.cache.set(cacheKey, authOk)
127133
}
128134

web/handler_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,54 @@ func TestBasicAuthWithFakepassword(t *testing.T) {
129129
login()
130130
}
131131

132+
// TestByPassBasicAuthVuln tests for CVE-2022-46146.
133+
func TestByPassBasicAuthVuln(t *testing.T) {
134+
server := &http.Server{
135+
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
136+
w.Write([]byte("Hello World!"))
137+
}),
138+
}
139+
140+
done := make(chan struct{})
141+
t.Cleanup(func() {
142+
if err := server.Shutdown(context.Background()); err != nil {
143+
t.Fatal(err)
144+
}
145+
<-done
146+
})
147+
148+
go func() {
149+
flags := FlagConfig{
150+
WebListenAddresses: &([]string{port}),
151+
WebSystemdSocket: OfBool(false),
152+
WebConfigFile: OfString("testdata/web_config_users_noTLS.good.yml"),
153+
}
154+
ListenAndServe(server, &flags, testlogger)
155+
close(done)
156+
}()
157+
158+
login := func(username, password string) {
159+
client := &http.Client{}
160+
req, err := http.NewRequest("GET", "http://localhost"+port, nil)
161+
if err != nil {
162+
t.Fatal(err)
163+
}
164+
req.SetBasicAuth(username, password)
165+
r, err := client.Do(req)
166+
if err != nil {
167+
t.Fatal(err)
168+
}
169+
if r.StatusCode != 401 {
170+
t.Fatalf("bad return code, expected %d, got %d", 401, r.StatusCode)
171+
}
172+
}
173+
174+
// Poison the cache.
175+
login("alice$2y$12$1DpfPeqF9HzHJt.EWswy1exHluGfbhnn3yXhR7Xes6m3WJqFg0Wby", "fakepassword")
176+
// Login with a wrong password.
177+
login("alice", "$2y$10$QOauhQNbBCuQDKes6eFzPeMqBSjb7Mr5DUmpZ/VcEd00UAV/LDeSifakepassword")
178+
}
179+
132180
// TestHTTPHeaders validates that HTTP headers are added correctly.
133181
func TestHTTPHeaders(t *testing.T) {
134182
server := &http.Server{

0 commit comments

Comments
 (0)