Skip to content

Commit 072e849

Browse files
committed
Targeted script for detect Web Cache Deception
Signed-off-by: eiliya keshtkar <iliyakeshtkar0@gmail.com>
1 parent 0e5e22b commit 072e849

File tree

1 file changed

+256
-0
lines changed

1 file changed

+256
-0
lines changed

targeted/web-cache-deception.js

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
/**
2+
* Contributed by Eiliya Keshtkar (https://www.hackmelocal.com/)
3+
* @author Eiliya Keshtkar <eiliyakeshtkar0@gmail.com>
4+
*/
5+
var HttpSender = Java.type("org.parosproxy.paros.network.HttpSender");
6+
var HttpMessage = Java.type("org.parosproxy.paros.network.HttpMessage");
7+
var URI = Java.type("org.apache.commons.httpclient.URI");
8+
var Model = Java.type("org.parosproxy.paros.model.Model");
9+
10+
// === Helper: Pretty Divider ===
11+
function divider(label) {
12+
print("\n" + "-".repeat(60));
13+
if (label) print("Target: " + label);
14+
print("-".repeat(60));
15+
}
16+
17+
// === Helper: Send GET Request with Original Headers ===
18+
function sendGetWithOriginalHeaders(originalReqHeader, url) {
19+
try {
20+
var uri = new URI(url, true);
21+
var msg = new HttpMessage();
22+
msg.getRequestHeader().setMethod("GET");
23+
msg.getRequestHeader().setURI(uri);
24+
25+
// Copy all request headers except Host & Content-Length
26+
var origHeaders = originalReqHeader.getHeaders();
27+
for (var i = 0; i < origHeaders.size(); i++) {
28+
var h = origHeaders.get(i);
29+
var name = h.getName();
30+
var value = h.getValue();
31+
if (!name.equalsIgnoreCase("Host") && !name.equalsIgnoreCase("Content-Length")) {
32+
msg.getRequestHeader().setHeader(name, value);
33+
}
34+
}
35+
36+
// Set Host header properly
37+
var host = uri.getHost();
38+
var port = uri.getPort();
39+
msg.getRequestHeader().setHeader("Host", port > 0 && port !== 80 && port !== 443 ? host + ":" + port : host);
40+
41+
// Send it
42+
var sender = new HttpSender(
43+
Model.getSingleton().getOptionsParam().getConnectionParam(),
44+
true,
45+
HttpSender.CHECK_FOR_UPDATES_INITIATOR
46+
);
47+
sender.sendAndReceive(msg, true);
48+
return msg;
49+
} catch (e) {
50+
print("[!] Error sending to: " + url + " => " + e);
51+
return null;
52+
}
53+
}
54+
55+
// === Main ===
56+
function invokeWith(msg) {
57+
var baseUrl = msg.getRequestHeader().getURI().toString();
58+
if (!baseUrl || baseUrl.trim() === "") return;
59+
60+
divider(baseUrl);
61+
62+
var originalBody = msg.getResponseBody().toString();
63+
var delimiters = [";", "%00", "%0A", "%09", ".", "/", "~"];
64+
var exts = [
65+
"css","js","jpg","png","gif","svg","webp","pdf","zip","docx","xlsx","mp3","mp4","ttf","woff","woff2","svgz"
66+
];
67+
var filename = "cachetest";
68+
69+
print("[+] Starting Web Cache Deception tests...");
70+
print("[i] Base: " + baseUrl + "\n");
71+
72+
// === Standard Delimiter + Extension tests ===
73+
for (var i = 0; i < delimiters.length; i++) {
74+
var d = delimiters[i];
75+
var probeUrl = baseUrl + d + filename;
76+
var probeMsg = sendGetWithOriginalHeaders(msg.getRequestHeader(), probeUrl);
77+
if (!probeMsg) continue;
78+
79+
var status = probeMsg.getResponseHeader().getStatusCode();
80+
if (status !== 200) continue;
81+
82+
print("\n[*] Delimiter accepted: '" + d + "'");
83+
print(" Baseline probe: " + probeUrl + " | Status: " + status);
84+
85+
for (var j = 0; j < exts.length; j++) {
86+
var ext = exts[j];
87+
var testUrl = baseUrl + d + filename + "." + ext;
88+
var newMsg = sendGetWithOriginalHeaders(msg.getRequestHeader(), testUrl);
89+
if (!newMsg) continue;
90+
91+
var code = newMsg.getResponseHeader().getStatusCode();
92+
if (code !== 200) continue;
93+
94+
var xCache = null;
95+
var hdrs = newMsg.getResponseHeader().getHeaders();
96+
for (var h = 0; h < hdrs.size(); h++) {
97+
var hh = hdrs.get(h);
98+
if (hh.getName().equalsIgnoreCase("X-Cache")) {
99+
xCache = hh.getValue();
100+
break;
101+
}
102+
}
103+
104+
var testBody = newMsg.getResponseBody().toString();
105+
var bodySame = (testBody === originalBody);
106+
print(" [+] Payload: " + testUrl);
107+
print(" Status: " + code +
108+
(xCache ? " | X-Cache: " + xCache : " | no X-Cache") +
109+
(bodySame ? " | SAME_BODY" : ""));
110+
111+
if (xCache && xCache.toLowerCase().includes("hit") && bodySame) {
112+
print(" [!] Potential Cache Deception detected!");
113+
}
114+
}
115+
}
116+
117+
// === Traversal-style encoded payload tests ===
118+
try {
119+
var urlObj = new java.net.URL(baseUrl);
120+
var origin = urlObj.getProtocol() + "://" + urlObj.getHost();
121+
if (urlObj.getPort() > 0) origin += ":" + urlObj.getPort();
122+
var path = urlObj.getPath();
123+
124+
var folders = ["static", "assets", "resources", "js", "css", "uploads", "files", "cdn"];
125+
var encoders = [
126+
"%23%2f..%2f", // #/../
127+
"%23%2F..%2F", // uppercase
128+
"%2e%2e%2f", // ../
129+
"..%2f" // simple
130+
];
131+
132+
print("\n[+] Testing encoded traversal-style payloads...\n");
133+
134+
for (var f = 0; f < folders.length; f++) {
135+
for (var e = 0; e < encoders.length; e++) {
136+
var folder = folders[f];
137+
var encoder = encoders[e];
138+
var testUrl = origin + path + encoder + folder;
139+
var tMsg = sendGetWithOriginalHeaders(msg.getRequestHeader(), testUrl);
140+
if (!tMsg) continue;
141+
142+
var code = tMsg.getResponseHeader().getStatusCode();
143+
if (code !== 200) continue;
144+
145+
var hdrs = tMsg.getResponseHeader().getHeaders();
146+
var xCache = null;
147+
for (var h = 0; h < hdrs.size(); h++) {
148+
var hh = hdrs.get(h);
149+
if (hh.getName().equalsIgnoreCase("X-Cache")) {
150+
xCache = hh.getValue();
151+
break;
152+
}
153+
}
154+
155+
var testBody = tMsg.getResponseBody().toString();
156+
var bodySame = (testBody === originalBody);
157+
158+
print(" [+] Traversal Payload: " + testUrl +
159+
" | Status: " + code +
160+
(xCache ? " | X-Cache: " + xCache : " | no X-Cache") +
161+
(bodySame ? " | SAME_BODY" : ""));
162+
163+
if (xCache && xCache.toLowerCase().includes("hit") && bodySame) {
164+
print(" [!] Potential Cache Deception via encoded traversal!");
165+
}
166+
}
167+
}
168+
169+
// === Semicolon traversal and encoded path confusion tests ===
170+
print("\n[+] Testing semicolon and encoded path confusion payloads...\n");
171+
172+
try {
173+
var sensitiveFiles = [
174+
"robots.txt", "sitemap.xml", "index.html", "index.php",
175+
"login", "admin", "config", "api", "dashboard"
176+
];
177+
178+
for (var s = 0; s < sensitiveFiles.length; s++) {
179+
var sf = sensitiveFiles[s];
180+
var testUrl = baseUrl + ";%2f%2e%2e%2f" + sf + "?test";
181+
182+
var tMsg = sendGetWithOriginalHeaders(msg.getRequestHeader(), testUrl);
183+
if (!tMsg) continue;
184+
185+
var code = tMsg.getResponseHeader().getStatusCode();
186+
if (code !== 200) continue;
187+
188+
var hdrs = tMsg.getResponseHeader().getHeaders();
189+
var xCache = null;
190+
for (var h = 0; h < hdrs.size(); h++) {
191+
var hh = hdrs.get(h);
192+
if (hh.getName().equalsIgnoreCase("X-Cache")) {
193+
xCache = hh.getValue();
194+
break;
195+
}
196+
}
197+
198+
var testBody = tMsg.getResponseBody().toString();
199+
var bodySame = (testBody === originalBody);
200+
201+
print(" [+] Semicolon Payload: " + testUrl +
202+
" | Status: " + code +
203+
(xCache ? " | X-Cache: " + xCache : " | no X-Cache") +
204+
(bodySame ? " | SAME_BODY" : ""));
205+
206+
if (xCache && xCache.toLowerCase().includes("hit") && bodySame) {
207+
print(" [!] Potential Cache Deception via semicolon traversal!");
208+
}
209+
}
210+
} catch (e) {
211+
print("[!] Semicolon traversal error: " + e);
212+
}
213+
214+
215+
// === Folder-prefixed traversal tests ===
216+
print("\n[+] Testing folder-prefixed traversal payloads...\n");
217+
for (var f = 0; f < folders.length; f++) {
218+
var folder = folders[f];
219+
var testUrl = origin + "/" + folder + "/..%2f" + path + "?";
220+
var tMsg = sendGetWithOriginalHeaders(msg.getRequestHeader(), testUrl);
221+
if (!tMsg) continue;
222+
223+
var code = tMsg.getResponseHeader().getStatusCode();
224+
if (code !== 200) continue;
225+
226+
var hdrs = tMsg.getResponseHeader().getHeaders();
227+
var xCache = null;
228+
for (var h = 0; h < hdrs.size(); h++) {
229+
var hh = hdrs.get(h);
230+
if (hh.getName().equalsIgnoreCase("X-Cache")) {
231+
xCache = hh.getValue();
232+
break;
233+
}
234+
}
235+
236+
var testBody = tMsg.getResponseBody().toString();
237+
var bodySame = (testBody === originalBody);
238+
239+
print(" " +
240+
(xCache ? "[X]" : "[!]") +
241+
" Prefix Payload: " + testUrl +
242+
" | Status: " + code +
243+
(xCache ? " | X-Cache: " + xCache : " | no X-Cache") +
244+
(bodySame ? " | SAME_BODY" : ""));
245+
246+
if (xCache && xCache.toLowerCase().includes("hit") && bodySame) {
247+
print(" [!] Potential Cache Deception via folder prefix traversal!");
248+
}
249+
}
250+
251+
} catch (e) {
252+
print("[!] Traversal error: " + e);
253+
}
254+
255+
divider();
256+
}

0 commit comments

Comments
 (0)