Skip to content

Commit 4317e58

Browse files
author
Yunus AYDIN
committed
Add Web Cache Deception QHelp and Example Code Snippet for Vulnerable and Fixed Version
1 parent 78a6522 commit 4317e58

3 files changed

Lines changed: 215 additions & 0 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
2+
<qhelp>
3+
<overview>
4+
<p>
5+
Web Cache Deception is a security vulnerability where an attacker tricks a web server into caching sensitive information and then accesses that cached data.
6+
</p>
7+
<p>
8+
This attack exploits certain behaviors in caching mechanisms by requesting URLs that trick the server into thinking that a non-cachable page is cachable. If a user then accesses sensitive information on these pages, it could be cached and later retrieved by the attacker.
9+
</p>
10+
</overview>
11+
<recommendation>
12+
<p>
13+
To prevent Web Cache Deception attacks, web applications should clearly define cacheable and non-cacheable resources. Implementing strict cache controls and validating requested URLs can mitigate the risk of sensitive data being cached.
14+
</p>
15+
</recommendation>
16+
<example>
17+
<p>
18+
Vulnerable code example: A web server is configured to cache all responses ending in '.css'. An attacker requests 'profile.css', and the server processes 'profile', a sensitive page, and caches it.
19+
</p>
20+
<sample src="WebCacheDeceptionBad.go" />
21+
</example>
22+
<example>
23+
<p>
24+
Secure 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.
25+
</p>
26+
<sample src="WebCacheDeceptionGood.go" />
27+
</example>
28+
<references>
29+
<li>
30+
OWASP Web Cache Deception Attack:
31+
<a href="https://owasp.org/www-community/attacks/Web_Cache_Deception">Understanding Web Cache Deception Attacks</a>
32+
</li>
33+
<!-- Additional references can be added here -->
34+
</references>
35+
</qhelp>
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"html/template"
7+
"log"
8+
"net/http"
9+
"os/exec"
10+
"strings"
11+
"sync"
12+
)
13+
14+
var sessionMap = make(map[string]string)
15+
16+
var (
17+
templateCache = make(map[string]*template.Template)
18+
mutex = &sync.Mutex{}
19+
)
20+
21+
type Lists struct {
22+
Uid string
23+
UserName string
24+
UserLists []string
25+
ReadFile func(filename string) string
26+
}
27+
28+
func parseTemplateFile(templateName string, tmplFile string) (*template.Template, error) {
29+
mutex.Lock()
30+
defer mutex.Unlock()
31+
32+
// Check if the template is already cached
33+
if cachedTemplate, ok := templateCache[templateName]; ok {
34+
fmt.Println("cached")
35+
return cachedTemplate, nil
36+
}
37+
38+
// Parse and store the template in the cache
39+
parsedTemplate, _ := template.ParseFiles(tmplFile)
40+
fmt.Println("not cached")
41+
42+
templateCache[templateName] = parsedTemplate
43+
return parsedTemplate, nil
44+
}
45+
46+
func ShowAdminPageCache(w http.ResponseWriter, r *http.Request) {
47+
48+
if r.Method == "GET" {
49+
fmt.Println("cache called")
50+
sessionMap[r.RequestURI] = "admin"
51+
52+
// Check if a session value exists
53+
if _, ok := sessionMap[r.RequestURI]; ok {
54+
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" + "\");'"
55+
56+
// 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");'
57+
fmt.Println(cmd)
58+
59+
res, err := exec.Command("sh", "-c", cmd).Output()
60+
if err != nil {
61+
fmt.Println("err : ", err)
62+
}
63+
64+
splitedRes := strings.Split(string(res), "\n")
65+
66+
p := Lists{Uid: "1", UserName: "admin", UserLists: splitedRes}
67+
68+
parsedTemplate, _ := parseTemplateFile("page", "./views/admin/userlists.gtpl")
69+
w.Header().Set("Cache-Control", "no-store, no-cache")
70+
err = parsedTemplate.Execute(w, p)
71+
}
72+
} else {
73+
http.NotFound(w, nil)
74+
}
75+
76+
}
77+
78+
func main() {
79+
var portNum = flag.String("p", "80", "Specify application server listening port")
80+
flag.Parse()
81+
fmt.Println("Vulnapp server listening : " + *portNum)
82+
83+
http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/"))))
84+
85+
http.HandleFunc("/adminusers/", ShowAdminPageCache)
86+
err := http.ListenAndServe(":"+*portNum, nil)
87+
if err != nil {
88+
log.Fatal("ListenAndServe: ", err)
89+
}
90+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"html/template"
7+
"log"
8+
"net/http"
9+
"os/exec"
10+
"strings"
11+
"sync"
12+
)
13+
14+
var sessionMap = make(map[string]string)
15+
16+
var (
17+
templateCache = make(map[string]*template.Template)
18+
mutex = &sync.Mutex{}
19+
)
20+
21+
type Lists struct {
22+
Uid string
23+
UserName string
24+
UserLists []string
25+
ReadFile func(filename string) string
26+
}
27+
28+
func parseTemplateFile(templateName string, tmplFile string) (*template.Template, error) {
29+
mutex.Lock()
30+
defer mutex.Unlock()
31+
32+
// Check if the template is already cached
33+
if cachedTemplate, ok := templateCache[templateName]; ok {
34+
fmt.Println("cached")
35+
return cachedTemplate, nil
36+
}
37+
38+
// Parse and store the template in the cache
39+
parsedTemplate, _ := template.ParseFiles(tmplFile)
40+
fmt.Println("not cached")
41+
42+
templateCache[templateName] = parsedTemplate
43+
return parsedTemplate, nil
44+
}
45+
46+
func ShowAdminPageCache(w http.ResponseWriter, r *http.Request) {
47+
48+
if r.Method == "GET" {
49+
fmt.Println("cache called")
50+
sessionMap[r.RequestURI] = "admin"
51+
52+
// Check if a session value exists
53+
if _, ok := sessionMap[r.RequestURI]; ok {
54+
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" + "\");'"
55+
56+
// 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");'
57+
fmt.Println(cmd)
58+
59+
res, err := exec.Command("sh", "-c", cmd).Output()
60+
if err != nil {
61+
fmt.Println("err : ", err)
62+
}
63+
64+
splitedRes := strings.Split(string(res), "\n")
65+
66+
p := Lists{Uid: "1", UserName: "admin", UserLists: splitedRes}
67+
68+
parsedTemplate, _ := parseTemplateFile("page", "./views/admin/userlists.gtpl")
69+
w.Header().Set("Cache-Control", "no-store, no-cache")
70+
err = parsedTemplate.Execute(w, p)
71+
}
72+
} else {
73+
http.NotFound(w, nil)
74+
}
75+
76+
}
77+
78+
func main() {
79+
var portNum = flag.String("p", "80", "Specify application server listening port")
80+
flag.Parse()
81+
fmt.Println("Vulnapp server listening : " + *portNum)
82+
83+
http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/"))))
84+
http.HandleFunc("/adminusers", ShowAdminPageCache)
85+
86+
err := http.ListenAndServe(":"+*portNum, nil)
87+
if err != nil {
88+
log.Fatal("ListenAndServe: ", err)
89+
}
90+
}

0 commit comments

Comments
 (0)