Skip to content

Commit 5b1eab3

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 c6a2415 commit 5b1eab3

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

web/handler.go

+8-2
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

+48
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,54 @@ func TestBasicAuthWithFakepassword(t *testing.T) {
137137
login()
138138
}
139139

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

0 commit comments

Comments
 (0)