Repository navigation
Expand file tree
/
Copy pathtest_wp2shell_detect.py
More file actions
117 lines (93 loc) · 4.21 KB
/
Copy pathtest_wp2shell_detect.py
File metadata and controls
117 lines (93 loc) · 4.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/usr/bin/env python3
"""Offline unit tests for the version/verdict logic (no network)."""
import unittest
from unittest import mock
from wp2shell_detect import (
RCE_RANGES,
SQLI_RANGES,
Resp,
_core_asset_version,
assess,
in_ranges,
parse_version,
)
class ParseVersion(unittest.TestCase):
def test_three_segments(self):
self.assertEqual(parse_version("6.9.3"), (6, 9, 3))
def test_two_segments_pads_patch(self):
self.assertEqual(parse_version("7.0"), (7, 0, 0))
def test_non_numeric_segment_is_none(self):
self.assertIsNone(parse_version("6.9.x"))
def test_suffix_rejected(self):
# strict: a beta/suffix string is not trusted as a clean version
self.assertIsNone(parse_version("7.1-beta2"))
class Verdict(unittest.TestCase):
def rce(self, v):
return in_ranges(parse_version(v), RCE_RANGES)
def sqli(self, v):
return in_ranges(parse_version(v), SQLI_RANGES)
def test_rce_range(self):
for v in ("6.9.0", "6.9.4", "7.0.0", "7.0.1"):
self.assertTrue(self.rce(v), v)
def test_fixed_versions_not_rce(self):
for v in ("6.9.5", "7.0.2", "6.8.6", "7.1.0"):
self.assertFalse(self.rce(v), v)
def test_sqli_only_range(self):
for v in ("6.8.0", "6.8.5"):
self.assertTrue(self.sqli(v), v)
self.assertFalse(self.rce(v), v)
def test_old_versions_clean(self):
for v in ("6.7.0", "5.9.0"):
self.assertFalse(self.rce(v), v)
self.assertFalse(self.sqli(v), v)
class Fingerprinting(unittest.TestCase):
def test_csp_wordpress_domain_is_not_a_wordpress_site(self):
# Regression: a non-WP front (Next.js) whose CSP references a
# wordpress.* media domain must NOT be flagged as WordPress.
def fake(url, method="GET", insecure=False):
if any(s in url for s in ("/wp-json", "/feed", "readme")):
return Resp(404, "not found", {})
return Resp(
200,
"<html><body>a Next.js site</body></html>",
{"content-security-policy": "img-src https://wordpress.example.io"},
)
with mock.patch("wp2shell_detect._request", side_effect=fake):
r = assess("https://front.example.io", insecure=False)
self.assertEqual(r.verdict, "not-wordpress")
def test_discovers_headless_wordpress_host_from_csp(self):
def fake(url, method="GET", insecure=False):
if any(s in url for s in ("/wp-json", "/feed", "readme")):
return Resp(404, "not found", {})
return Resp(
200,
"<html><body>Next.js</body></html>",
{"content-security-policy": "img-src https://wordpress.example.io"},
)
with mock.patch("wp2shell_detect._request", side_effect=fake):
r = assess("https://front.example.io", insecure=False)
self.assertIn("wordpress.example.io", r.discovered)
def test_discovery_ignores_cross_domain_and_wordpress_org(self):
# A generator link to wordpress.org and a foreign CDN must NOT be
# reported as the target's headless back-end.
def fake(url, method="GET", insecure=False):
if any(s in url for s in ("/wp-json", "/feed", "readme")):
return Resp(404, "not found", {})
body = (
"<a href='https://wordpress.org/?v=6.9'>"
"<img src='https://cdn.othercdn.net/wp-content/x.png'>"
)
return Resp(200, body, {})
with mock.patch("wp2shell_detect._request", side_effect=fake):
r = assess("https://front.example.io", insecure=False)
self.assertEqual(r.discovered, [])
def test_core_asset_version_ignores_plugin_assets(self):
body = (
"<link href='/wp-includes/css/dist/block-library/style.min.css?ver=6.9.3'>"
"<script src='/wp-content/plugins/foo/f.js?ver=1.2.3'></script>"
)
self.assertEqual(_core_asset_version(body), "6.9.3")
def test_core_asset_version_none_without_core_asset(self):
self.assertIsNone(_core_asset_version("<script src='/wp-content/x.js?ver=1.0'>"))
if __name__ == "__main__":
unittest.main()