Skip to content

Commit 85636cc

Browse files
author
Yunus AYDIN
committed
Add Web Cache Deception QHelp and Example Code Snippet for Vulnerable Go Fiber usage
1 parent 7819dcf commit 85636cc

File tree

7 files changed

+240
-0
lines changed

7 files changed

+240
-0
lines changed

go/ql/src/experimental/CWE-525/WebCacheDeception.expected

Whitespace-only changes.

go/ql/src/experimental/CWE-525/WebCacheDeception.qhelp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
</p>
2626
<sample src="WebCacheDeceptionGood.go" />
2727
</example>
28+
<example>
29+
<p>
30+
Vulnerable code example: The server is configured with strict cache controls and URL validation, preventing caching of dynamic or sensitive pages regardless of their URL pattern.
31+
</p>
32+
<sample src="WebCacheDeceptionFiber.go" />
33+
</example>
2834
<references>
2935
<li>
3036
OWASP Web Cache Deception Attack:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
WARNING: Unused variable f (WebCacheDeceptionFiber.ql:15,77-78)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* @name Web Cache Deception
3+
* @description A caching system has been detected on the application and is vulnerable to web cache deception on Gofiber. By manipulating the URL it is possible to force the application to cache pages that are only accessible by an authenticated user. Once cached, these pages can be accessed by an unauthenticated user.
4+
* @kind problem
5+
* @problem.severity error
6+
* @security-severity 9
7+
* @precision high
8+
* @id go/web-cache-deception
9+
* @tags security
10+
* external/cwe/cwe-525
11+
*/
12+
13+
import go
14+
15+
from DataFlow::CallNode httpHandleFuncCall, ImportSpec importSpec, Function f
16+
where
17+
importSpec.getPath() = "github.com/gofiber/fiber/v2" and
18+
httpHandleFuncCall.getCall().getArgument(0).toString().matches("%/*%") and
19+
not httpHandleFuncCall.getCall().getArgument(0).toString().matches("%$%")
20+
select httpHandleFuncCall.getCall().getArgument(0),
21+
"Wildcard Endpoint used with " + httpHandleFuncCall.getCall().getArgument(0)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package bad
2+
3+
import (
4+
"fmt"
5+
"html/template"
6+
"log"
7+
"net/http"
8+
"os/exec"
9+
"strings"
10+
"sync"
11+
)
12+
13+
var sessionMap = make(map[string]string)
14+
15+
var (
16+
templateCache = make(map[string]*template.Template)
17+
mutex = &sync.Mutex{}
18+
)
19+
20+
type Lists struct {
21+
Uid string
22+
UserName string
23+
UserLists []string
24+
ReadFile func(filename string) string
25+
}
26+
27+
func parseTemplateFile(templateName string, tmplFile string) (*template.Template, error) {
28+
mutex.Lock()
29+
defer mutex.Unlock()
30+
31+
// Check if the template is already cached
32+
if cachedTemplate, ok := templateCache[templateName]; ok {
33+
fmt.Println("cached")
34+
return cachedTemplate, nil
35+
}
36+
37+
// Parse and store the template in the cache
38+
parsedTemplate, _ := template.ParseFiles(tmplFile)
39+
fmt.Println("not cached")
40+
41+
templateCache[templateName] = parsedTemplate
42+
return parsedTemplate, nil
43+
}
44+
45+
func ShowAdminPageCache(w http.ResponseWriter, r *http.Request) {
46+
47+
if r.Method == "GET" {
48+
fmt.Println("cache called")
49+
sessionMap[r.RequestURI] = "admin"
50+
51+
// Check if a session value exists
52+
if _, ok := sessionMap[r.RequestURI]; ok {
53+
cmd := "mysql -h mysql -u root -prootwolf -e 'select id,name,mail,age,created_at,updated_at from vulnapp.user where name not in (\"" + "admin" + "\");'"
54+
55+
// mysql -h mysql -u root -prootwolf -e 'select id,name,mail,age,created_at,updated_at from vulnapp.user where name not in ("test");--';echo");'
56+
fmt.Println(cmd)
57+
58+
res, err := exec.Command("sh", "-c", cmd).Output()
59+
if err != nil {
60+
fmt.Println("err : ", err)
61+
}
62+
63+
splitedRes := strings.Split(string(res), "\n")
64+
65+
p := Lists{Uid: "1", UserName: "admin", UserLists: splitedRes}
66+
67+
parsedTemplate, _ := parseTemplateFile("page", "./views/admin/userlists.gtpl")
68+
w.Header().Set("Cache-Control", "no-store, no-cache")
69+
err = parsedTemplate.Execute(w, p)
70+
}
71+
} else {
72+
http.NotFound(w, nil)
73+
}
74+
75+
}
76+
77+
func main() {
78+
fmt.Println("Vulnapp server listening : 1337")
79+
80+
http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/"))))
81+
82+
http.HandleFunc("/adminusers/", ShowAdminPageCache)
83+
err := http.ListenAndServe(":1337", nil)
84+
if err != nil {
85+
log.Fatal("ListenAndServe: ", err)
86+
}
87+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package fiber
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"github.com/gofiber/fiber/v2"
8+
)
9+
10+
func main() {
11+
app := fiber.New()
12+
log.Println("We are logging in Golang!")
13+
14+
// GET /api/register
15+
app.Get("/api/*", func(c *fiber.Ctx) error {
16+
msg := fmt.Sprintf("✋")
17+
return c.SendString(msg) // => ✋ register
18+
})
19+
20+
app.Post("/api/*", func(c *fiber.Ctx) error {
21+
msg := fmt.Sprintf("✋")
22+
return c.SendString(msg) // => ✋ register
23+
})
24+
25+
// GET /flights/LAX-SFO
26+
app.Get("/flights/:from-:to", func(c *fiber.Ctx) error {
27+
msg := fmt.Sprintf("💸 From: %s, To: %s", c.Params("from"), c.Params("to"))
28+
return c.SendString(msg) // => 💸 From: LAX, To: SFO
29+
})
30+
31+
// GET /dictionary.txt
32+
app.Get("/:file.:ext", func(c *fiber.Ctx) error {
33+
msg := fmt.Sprintf("📃 %s.%s", c.Params("file"), c.Params("ext"))
34+
return c.SendString(msg) // => 📃 dictionary.txt
35+
})
36+
37+
log.Fatal(app.Listen(":3000"))
38+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package good
2+
3+
import (
4+
"fmt"
5+
"html/template"
6+
"log"
7+
"net/http"
8+
"os/exec"
9+
"strings"
10+
"sync"
11+
)
12+
13+
var sessionMap = make(map[string]string)
14+
15+
var (
16+
templateCache = make(map[string]*template.Template)
17+
mutex = &sync.Mutex{}
18+
)
19+
20+
type Lists struct {
21+
Uid string
22+
UserName string
23+
UserLists []string
24+
ReadFile func(filename string) string
25+
}
26+
27+
func parseTemplateFile(templateName string, tmplFile string) (*template.Template, error) {
28+
mutex.Lock()
29+
defer mutex.Unlock()
30+
31+
// Check if the template is already cached
32+
if cachedTemplate, ok := templateCache[templateName]; ok {
33+
fmt.Println("cached")
34+
return cachedTemplate, nil
35+
}
36+
37+
// Parse and store the template in the cache
38+
parsedTemplate, _ := template.ParseFiles(tmplFile)
39+
fmt.Println("not cached")
40+
41+
templateCache[templateName] = parsedTemplate
42+
return parsedTemplate, nil
43+
}
44+
45+
func ShowAdminPageCache(w http.ResponseWriter, r *http.Request) {
46+
47+
if r.Method == "GET" {
48+
fmt.Println("cache called")
49+
sessionMap[r.RequestURI] = "admin"
50+
51+
// Check if a session value exists
52+
if _, ok := sessionMap[r.RequestURI]; ok {
53+
cmd := "mysql -h mysql -u root -prootwolf -e 'select id,name,mail,age,created_at,updated_at from vulnapp.user where name not in (\"" + "admin" + "\");'"
54+
55+
// mysql -h mysql -u root -prootwolf -e 'select id,name,mail,age,created_at,updated_at from vulnapp.user where name not in ("test");--';echo");'
56+
fmt.Println(cmd)
57+
58+
res, err := exec.Command("sh", "-c", cmd).Output()
59+
if err != nil {
60+
fmt.Println("err : ", err)
61+
}
62+
63+
splitedRes := strings.Split(string(res), "\n")
64+
65+
p := Lists{Uid: "1", UserName: "admin", UserLists: splitedRes}
66+
67+
parsedTemplate, _ := parseTemplateFile("page", "./views/admin/userlists.gtpl")
68+
w.Header().Set("Cache-Control", "no-store, no-cache")
69+
err = parsedTemplate.Execute(w, p)
70+
}
71+
} else {
72+
http.NotFound(w, nil)
73+
}
74+
75+
}
76+
77+
func main() {
78+
fmt.Println("Vulnapp server listening : 1337")
79+
80+
http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/"))))
81+
82+
http.HandleFunc("/adminusers", ShowAdminPageCache)
83+
err := http.ListenAndServe(":1337", nil)
84+
if err != nil {
85+
log.Fatal("ListenAndServe: ", err)
86+
}
87+
}

0 commit comments

Comments
 (0)