Compare commits
1083 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
641108e7eb | ||
|
|
0e87384b0a | ||
|
|
5175170c4b | ||
|
|
79864cae7b | ||
|
|
ca5f92ca61 | ||
|
|
d29de83c41 | ||
|
|
1f42ce6e2f | ||
|
|
0dc7128582 | ||
|
|
21f4de2ec1 | ||
|
|
d65567fc8f | ||
|
|
20af778fa1 | ||
|
|
5f77832386 | ||
|
|
6ccfe70775 | ||
|
|
6b0f687abb | ||
|
|
67ba526b5b | ||
|
|
e186ec7534 | ||
|
|
23ef1e75b3 | ||
|
|
8170390f92 | ||
|
|
c148295f64 | ||
|
|
37b99f9baa | ||
|
|
8e4643874d | ||
|
|
0522023fd4 | ||
|
|
711ee730a0 | ||
|
|
f3bd995528 | ||
|
|
beec0bd35a | ||
|
|
9d7f35f3b2 | ||
|
|
c7488e28f7 | ||
|
|
9150e0ca52 | ||
|
|
475288deeb | ||
|
|
82335d7399 | ||
|
|
338eacd63b | ||
|
|
0b9b79f55f | ||
|
|
5303b28957 | ||
|
|
11c05a3590 | ||
|
|
862c0a9014 | ||
|
|
487a483aa6 | ||
|
|
030c20a11b | ||
|
|
ec831f7fed | ||
|
|
50fa79b331 | ||
|
|
edab0e812a | ||
|
|
f0126ca860 | ||
|
|
01261d4d29 | ||
|
|
f97d3436a5 | ||
|
|
0bcb8b4b3b | ||
|
|
489545dd75 | ||
|
|
f6c152f58a | ||
|
|
16734418be | ||
|
|
b17ee20f58 | ||
|
|
aaee6f1e6d | ||
|
|
64d8240b8a | ||
|
|
0a6d430c9f | ||
|
|
7bf0314561 | ||
|
|
409897fec4 | ||
|
|
91b0d20665 | ||
|
|
f6644eebf9 | ||
|
|
88bddd4f87 | ||
|
|
c61b023fb7 | ||
|
|
1b5df8751f | ||
|
|
314c98f101 | ||
|
|
8274e2efe9 | ||
|
|
2bff063805 | ||
|
|
53d9956829 | ||
|
|
6e98678c3c | ||
|
|
f0f21f5ac2 | ||
|
|
aa233b1c4d | ||
|
|
93f9123f45 | ||
|
|
5c710d88e4 | ||
|
|
ded70ff743 | ||
|
|
9df7443aa4 | ||
|
|
8362975691 | ||
|
|
49771419ae | ||
|
|
d344f84824 | ||
|
|
89c0b8d4d0 | ||
|
|
3c74ee8d97 | ||
|
|
785c6efa5b | ||
|
|
4e2bf5322e | ||
|
|
54ed148c87 | ||
|
|
b08e298eba | ||
|
|
89e2088357 | ||
|
|
f3cc35bd74 | ||
|
|
a007d283e5 | ||
|
|
70902aa013 | ||
|
|
91151fc53b | ||
|
|
d4ee82dac5 | ||
|
|
88d3c26113 | ||
|
|
054a4ee6aa | ||
|
|
c291022753 | ||
|
|
2fc488b602 | ||
|
|
009ddd690e | ||
|
|
88b5cd8751 | ||
|
|
cfd19d02b1 | ||
|
|
19ce30d862 | ||
|
|
c6df6e0e89 | ||
|
|
e942a5bcf6 | ||
|
|
c0f5163d07 | ||
|
|
f5aa9f117f | ||
|
|
498d93377d | ||
|
|
52242e706b | ||
|
|
22d69a1bf9 | ||
|
|
0b1fa13696 | ||
|
|
19b15b5327 | ||
|
|
e63e96f5ed | ||
|
|
e8ac8f26a7 | ||
|
|
13e4327de4 | ||
|
|
c22a1ed12a | ||
|
|
be5662b5f1 | ||
|
|
6e840ca920 | ||
|
|
8492190f4c | ||
|
|
93ab6ee2a0 | ||
|
|
7075e01886 | ||
|
|
436a83434c | ||
|
|
d270391b56 | ||
|
|
7f2762eb6f | ||
|
|
2cc5bb0311 | ||
|
|
d697127261 | ||
|
|
825523a851 | ||
|
|
0f3f9cac33 | ||
|
|
f9b545b100 | ||
|
|
943bfc39b3 | ||
|
|
b1a8f445c6 | ||
|
|
5435df4345 | ||
|
|
8e9d29e94f | ||
|
|
1afa761f09 | ||
|
|
d626913ce9 | ||
|
|
9c52e4a5ee | ||
|
|
72c2c1992b | ||
|
|
e1b4b5e8e5 | ||
|
|
0243522854 | ||
|
|
5118c68f45 | ||
|
|
442884b5c5 | ||
|
|
f832e27b49 | ||
|
|
6ce29f73c5 | ||
|
|
920338fb62 | ||
|
|
49d0a9e6d9 | ||
|
|
fe401e622b | ||
|
|
6e32cb0db2 | ||
|
|
73171eb39d | ||
|
|
2e05f4171e | ||
|
|
75b8c303e2 | ||
|
|
bd7a493f1c | ||
|
|
9dada7c8f4 | ||
|
|
fe7aede458 | ||
|
|
cdf2b38780 | ||
|
|
a09dbab6a8 | ||
|
|
49a6d275d2 | ||
|
|
8192a4a215 | ||
|
|
1d6593fd4d | ||
|
|
bf99e31e70 | ||
|
|
5386496bdc | ||
|
|
6451510449 | ||
|
|
cd68aa719c | ||
|
|
b328dc4ff9 | ||
|
|
1e1c79aa56 | ||
|
|
08650ce156 | ||
|
|
a1929719f3 | ||
|
|
d34da72cd3 | ||
|
|
816b18b604 | ||
|
|
a78a13bf3f | ||
|
|
33f8aaf1dc | ||
|
|
26ab95d822 | ||
|
|
cea01d8aa0 | ||
|
|
0e61f1e284 | ||
|
|
ddef061b90 | ||
|
|
addeab8947 | ||
|
|
55dc665404 | ||
|
|
8f8538e9e9 | ||
|
|
348ca55bee | ||
|
|
1bb5bc7f33 | ||
|
|
3be5e1fcf5 | ||
|
|
9df8cc9243 | ||
|
|
e28c84aa34 | ||
|
|
7db6b54761 | ||
|
|
e3a06f5694 | ||
|
|
7c5d15e098 | ||
|
|
d683c0f151 | ||
|
|
1e67fa26ff | ||
|
|
0ae6ef59ec | ||
|
|
e27ef40e0f | ||
|
|
380760d028 | ||
|
|
18cfdafc19 | ||
|
|
0934a2e329 | ||
|
|
d1a320324e | ||
|
|
361c96d746 | ||
|
|
e7dbf9278d | ||
|
|
6564fddb27 | ||
|
|
d382874e86 | ||
|
|
91b30bee9f | ||
|
|
7804aad776 | ||
|
|
b7552ac8aa | ||
|
|
a76c94cccf | ||
|
|
c0ae5c7cad | ||
|
|
cc55b39b83 | ||
|
|
d8a6884ab6 | ||
|
|
5ce3581386 | ||
|
|
2208f2a8c0 | ||
|
|
a4a14c7e63 | ||
|
|
aa464b476c | ||
|
|
3c92712a6e | ||
|
|
fd0c47f5d7 | ||
|
|
c03a44d225 | ||
|
|
d31d45ba71 | ||
|
|
db528b27f4 | ||
|
|
e6d29f6f18 | ||
|
|
e4d6b988ef | ||
|
|
ec68291bf0 | ||
|
|
3a6a451db1 | ||
|
|
7ec095d708 | ||
|
|
57f6206aee | ||
|
|
390f10e83f | ||
|
|
8727935cb2 | ||
|
|
d0e868f556 | ||
|
|
01c357e146 | ||
|
|
a0fed4a9d0 | ||
|
|
c4aed0ec89 | ||
|
|
cc737090a2 | ||
|
|
1652c09e95 | ||
|
|
2538b88579 | ||
|
|
8c2eb63840 | ||
|
|
36df5ee6e4 | ||
|
|
9720b4edf1 | ||
|
|
13d35b7607 | ||
|
|
13c2c51cfd | ||
|
|
f43175b0c3 | ||
|
|
1508aba8b2 | ||
|
|
5414ab05e5 | ||
|
|
bd5d2db634 | ||
|
|
3259dd29d8 | ||
|
|
6e56013a95 | ||
|
|
252f762209 | ||
|
|
15c0448cf1 | ||
|
|
4c800bacaa | ||
|
|
5902a483b4 | ||
|
|
ca73e4b93e | ||
|
|
ace64d88ce | ||
|
|
4cc9f7c8b5 | ||
|
|
f4f1390b67 | ||
|
|
14115761f9 | ||
|
|
ac3409e376 | ||
|
|
86a73229c0 | ||
|
|
cc41b96e88 | ||
|
|
e16c5584d1 | ||
|
|
94bab3f550 | ||
|
|
9d04b23fb2 | ||
|
|
2657e5050f | ||
|
|
3d6e5b2b9e | ||
|
|
bdd6b9727d | ||
|
|
6c8172c7cf | ||
|
|
ae5bae9899 | ||
|
|
b6bf306042 | ||
|
|
9c5196dfec | ||
|
|
3d7b8592ea | ||
|
|
e03f7691f2 | ||
|
|
7a54ac62d6 | ||
|
|
8db06d37d2 | ||
|
|
5ee5e76544 | ||
|
|
090cd999cb | ||
|
|
50b75354e0 | ||
|
|
c7b6b25851 | ||
|
|
b931df654d | ||
|
|
b5d5c4177d | ||
|
|
b22550ea55 | ||
|
|
04d50ebea5 | ||
|
|
202180909c | ||
|
|
0d806e6d74 | ||
|
|
54f31ebe7f | ||
|
|
227a39d2fa | ||
|
|
99d8faa38b | ||
|
|
9a7afe1549 | ||
|
|
e6751e0d89 | ||
|
|
371f1df830 | ||
|
|
8e1ba352ee | ||
|
|
7ebfe42eb2 | ||
|
|
df514d3b9f | ||
|
|
acae16e7ee | ||
|
|
deb8508ea5 | ||
|
|
a4bbf41086 | ||
|
|
4fbc535b0c | ||
|
|
36f6f98ce7 | ||
|
|
21cc7d604c | ||
|
|
44207161e6 | ||
|
|
dc20ef0754 | ||
|
|
413ee7a6d3 | ||
|
|
5b94714ca7 | ||
|
|
3675fe1ed7 | ||
|
|
e074a03c40 | ||
|
|
a7860f72a2 | ||
|
|
4b587593ee | ||
|
|
0aa8a97070 | ||
|
|
3c16f84853 | ||
|
|
346898e549 | ||
|
|
bcef4b2de7 | ||
|
|
e42bf7fd7c | ||
|
|
48cd0602d8 | ||
|
|
814e837ae5 | ||
|
|
a58b34eba8 | ||
|
|
7d790f8f79 | ||
|
|
7cf06f4989 | ||
|
|
61381b7168 | ||
|
|
df598c5900 | ||
|
|
aed74e029a | ||
|
|
6e01e1b9da | ||
|
|
42f278aafe | ||
|
|
884f64addb | ||
|
|
0c9cf4ddd5 | ||
|
|
f6dfe0e8dd | ||
|
|
9f4ca1add7 | ||
|
|
1f6edc5852 | ||
|
|
a74017f595 | ||
|
|
89bc7609ea | ||
|
|
2c93c8ef6d | ||
|
|
bfe370fa50 | ||
|
|
3b4850e1ba | ||
|
|
b2d1c25b8e | ||
|
|
093598ac99 | ||
|
|
585d22be46 | ||
|
|
9361cf4b00 | ||
|
|
298e9130dd | ||
|
|
41ae47f065 | ||
|
|
41f7fe1554 | ||
|
|
965be1c0f3 | ||
|
|
fa8ac37e8b | ||
|
|
d7975b6192 | ||
|
|
0a0fe55427 | ||
|
|
8e08a20178 | ||
|
|
9dd44808ec | ||
|
|
507cf1d511 | ||
|
|
53f3ce8b1f | ||
|
|
2d39e5b1fa | ||
|
|
60716dcf81 | ||
|
|
82141c2535 | ||
|
|
3d6de3fe75 | ||
|
|
03ab396353 | ||
|
|
6221601376 | ||
|
|
71fdef45c9 | ||
|
|
147a9e4968 | ||
|
|
8f7b56da32 | ||
|
|
4ef2452083 | ||
|
|
70cfa03ee8 | ||
|
|
5bd3d4fd96 | ||
|
|
c0fe02efb9 | ||
|
|
b0f4843526 | ||
|
|
a9e161268c | ||
|
|
cbad8857bd | ||
|
|
5adefda286 | ||
|
|
265bfcd7c8 | ||
|
|
b81a4987d9 | ||
|
|
6b9c9eb0ed | ||
|
|
4f82d618dc | ||
|
|
b7f7bdb9ac | ||
|
|
c5136fd330 | ||
|
|
e7e0e886fc | ||
|
|
42e8ab1680 | ||
|
|
ab7b7de60a | ||
|
|
21221d48d0 | ||
|
|
1f1a190c84 | ||
|
|
82d79c4662 | ||
|
|
08771a6d5d | ||
|
|
e01d18f224 | ||
|
|
8496650542 | ||
|
|
399245cd0f | ||
|
|
adfa5dddcf | ||
|
|
85971e0e91 | ||
|
|
3a3376ec41 | ||
|
|
d988b6ccbf | ||
|
|
6654f446a4 | ||
|
|
88808db9a5 | ||
|
|
dfad0fd6bd | ||
|
|
3fe49a24c7 | ||
|
|
ac609445fb | ||
|
|
0223f74a53 | ||
|
|
607a5b3fda | ||
|
|
e3ac331a71 | ||
|
|
e09b4cc76d | ||
|
|
c24ed707ef | ||
|
|
a8c55ddee3 | ||
|
|
e080835224 | ||
|
|
2fe675abce | ||
|
|
d230221999 | ||
|
|
91a01265e5 | ||
|
|
77286301a7 | ||
|
|
7c39827c16 | ||
|
|
8f789994eb | ||
|
|
79cb9c8142 | ||
|
|
de1d047c08 | ||
|
|
8252cb486b | ||
|
|
fb8ad72335 | ||
|
|
bc4f0c002b | ||
|
|
0a53c52645 | ||
|
|
7941a8accb | ||
|
|
5389923b34 | ||
|
|
9c1149cb25 | ||
|
|
c5130de805 | ||
|
|
020633503b | ||
|
|
74b9776801 | ||
|
|
5a605d686c | ||
|
|
4ba9bdf605 | ||
|
|
3f647348c3 | ||
|
|
de4f90dd72 | ||
|
|
4a7b4754f0 | ||
|
|
fe05534a95 | ||
|
|
c7c7e75b32 | ||
|
|
efc6aed388 | ||
|
|
197521d5b1 | ||
|
|
23420f62df | ||
|
|
33149caede | ||
|
|
67bec7136b | ||
|
|
57a12114dc | ||
|
|
e32abea46b | ||
|
|
b12b271a61 | ||
|
|
f337cccc68 | ||
|
|
7f9e178f75 | ||
|
|
b19696090f | ||
|
|
d7488bd402 | ||
|
|
604299a1ac | ||
|
|
6800d51347 | ||
|
|
7cecd249a8 | ||
|
|
a214ea9341 | ||
|
|
884a19b13d | ||
|
|
771f4ae766 | ||
|
|
9273398c0e | ||
|
|
a5ed6ad134 | ||
|
|
1bbf575e91 | ||
|
|
49582fd841 | ||
|
|
bdaf12c1fa | ||
|
|
ef27c98056 | ||
|
|
722f3ce384 | ||
|
|
9d084a7b2f | ||
|
|
c31a06e255 | ||
|
|
ea36c79c26 | ||
|
|
cbe33caeef | ||
|
|
8b44354fec | ||
|
|
619302cd11 | ||
|
|
3e94ca11df | ||
|
|
f818778e0a | ||
|
|
280a91f139 | ||
|
|
82367a81c9 | ||
|
|
93b1234d0f | ||
|
|
571bc5cf90 | ||
|
|
91de353307 | ||
|
|
7ec394a8f2 | ||
|
|
451c6c07ca | ||
|
|
a6b0548426 | ||
|
|
f89463c4d8 | ||
|
|
3be63d85f2 | ||
|
|
d271b63aa4 | ||
|
|
fb46fd7101 | ||
|
|
64513bb9d1 | ||
|
|
ef56f82de9 | ||
|
|
f775379f42 | ||
|
|
1b377dd674 | ||
|
|
99837127a6 | ||
|
|
f2d205e576 | ||
|
|
bf5bde0e36 | ||
|
|
18314adce2 | ||
|
|
d1a7a0ee1f | ||
|
|
eb73025338 | ||
|
|
66cd3e08a0 | ||
|
|
aa8e525681 | ||
|
|
7a36f89124 | ||
|
|
3e56acab64 | ||
|
|
012670b349 | ||
|
|
44cb13644a | ||
|
|
bd8e6db092 | ||
|
|
96ae8ade5d | ||
|
|
04b1cee71e | ||
|
|
bd07cf859f | ||
|
|
e937906647 | ||
|
|
03618f38b5 | ||
|
|
94fdddb056 | ||
|
|
12dfc60f75 | ||
|
|
a383d12061 | ||
|
|
3131c6cb5d | ||
|
|
5f53297f58 | ||
|
|
cebd808674 | ||
|
|
30a07f037e | ||
|
|
4ef1387781 | ||
|
|
1578ce2ebd | ||
|
|
391fd6c960 | ||
|
|
ef7ac1d77b | ||
|
|
ca2610d74f | ||
|
|
8d8aa52b9b | ||
|
|
84ec0c3964 | ||
|
|
f55736599e | ||
|
|
b890235a82 | ||
|
|
2cc3bc5759 | ||
|
|
ca100ef7e9 | ||
|
|
721cad75a2 | ||
|
|
c3110a4ab7 | ||
|
|
452aabf89b | ||
|
|
adcd6734ef | ||
|
|
a68c1f1cf7 | ||
|
|
712eaf9f1e | ||
|
|
7e119fa2ac | ||
|
|
ac90ad0129 | ||
|
|
6b61e273a0 | ||
|
|
aab8e85f9d | ||
|
|
3959892c20 | ||
|
|
420ad6cd37 | ||
|
|
664bff544e | ||
|
|
6716de6635 | ||
|
|
4f50fbdfe4 | ||
|
|
009abb3fd5 | ||
|
|
191b4402e1 | ||
|
|
13bc347897 | ||
|
|
187e2f1330 | ||
|
|
8d2ec115f5 | ||
|
|
921596f6f8 | ||
|
|
a00987efc8 | ||
|
|
b1a35d9df8 | ||
|
|
08dfa4cab2 | ||
|
|
63ca695b51 | ||
|
|
55310247c2 | ||
|
|
456334af75 | ||
|
|
38ce047d9e | ||
|
|
14be7dead5 | ||
|
|
ab2e368c6f | ||
|
|
0e7ca594ed | ||
|
|
f742287496 | ||
|
|
cb37919e76 | ||
|
|
933fc26b66 | ||
|
|
8ea94175ac | ||
|
|
013fb12c00 | ||
|
|
1e6b5a1e4d | ||
|
|
aed20db328 | ||
|
|
332684f4e2 | ||
|
|
12d275c26b | ||
|
|
9b1312c7d9 | ||
|
|
874b069357 | ||
|
|
03a917c326 | ||
|
|
6a5560a0b1 | ||
|
|
6b0bbdc605 | ||
|
|
4c0608d47d | ||
|
|
2e1aede8b4 | ||
|
|
2c3e968710 | ||
|
|
ecf45803e0 | ||
|
|
2e4ede4251 | ||
|
|
4f52649f28 | ||
|
|
11e58ff88d | ||
|
|
a7c097a5a9 | ||
|
|
8c53686697 | ||
|
|
6754f1467a | ||
|
|
fb98b3cc9a | ||
|
|
729f6fd308 | ||
|
|
e2b0711271 | ||
|
|
eb8cffb1a8 | ||
|
|
d7e534ca74 | ||
|
|
347e261748 | ||
|
|
7deb9c4fbf | ||
|
|
c1ab5ad929 | ||
|
|
2686c37aa1 | ||
|
|
45edb9973d | ||
|
|
2bd4ce08c4 | ||
|
|
460d1ac86c | ||
|
|
9df8da0b6f | ||
|
|
baaf85f567 | ||
|
|
6ffe817e86 | ||
|
|
edbdbdac56 | ||
|
|
11c3c6d20e | ||
|
|
81019b9fc8 | ||
|
|
4514123279 | ||
|
|
0fc4a448aa | ||
|
|
bde51cc946 | ||
|
|
4f7e29163f | ||
|
|
7837d1f6e8 | ||
|
|
99bb300559 | ||
|
|
f1108ef7d1 | ||
|
|
bd6cfec71c | ||
|
|
ef3ed86096 | ||
|
|
097898b120 | ||
|
|
6fbf2643a1 | ||
|
|
a1989c105e | ||
|
|
97426e6d7d | ||
|
|
b2e1b65ae5 | ||
|
|
06c8d34451 | ||
|
|
ecba81ea5b | ||
|
|
26e0066c82 | ||
|
|
6ebb9b6f66 | ||
|
|
102e30c29a | ||
|
|
a8a716e0bd | ||
|
|
9e23aaa5c0 | ||
|
|
9b059c3985 | ||
|
|
2d3c7e65d2 | ||
|
|
9e7d3462ab | ||
|
|
aececf980b | ||
|
|
e5f3b4bf1d | ||
|
|
9b629bb1c4 | ||
|
|
9e39a57231 | ||
|
|
47e9608aa2 | ||
|
|
2f012caa3e | ||
|
|
e835fc3ac0 | ||
|
|
5240e9ce98 | ||
|
|
b8ab2c839f | ||
|
|
1ee81b90bf | ||
|
|
1354f2debb | ||
|
|
7373ea24d8 | ||
|
|
7fc03461ba | ||
|
|
a5e45e2d79 | ||
|
|
42cf2ac19b | ||
|
|
6098d064a7 | ||
|
|
cd79f576b7 | ||
|
|
4039a4a820 | ||
|
|
919085d829 | ||
|
|
88f27b39c4 | ||
|
|
b1f38a51fe | ||
|
|
ef0253ee9e | ||
|
|
3cf33af0e2 | ||
|
|
3eaa060aac | ||
|
|
cf4efee340 | ||
|
|
0b04a96e15 | ||
|
|
c1d928c503 | ||
|
|
479b21a722 | ||
|
|
ceeaeaf487 | ||
|
|
d5179b742b | ||
|
|
b38055c497 | ||
|
|
ff1e9e63d6 | ||
|
|
a1a4293851 | ||
|
|
f39cc8ee53 | ||
|
|
9fc5b90f25 | ||
|
|
e7c9c884e9 | ||
|
|
0469128917 | ||
|
|
656e38eae7 | ||
|
|
95721350da | ||
|
|
98d9e87356 | ||
|
|
a69cb4f4c2 | ||
|
|
f42ea74e26 | ||
|
|
d9b86f9922 | ||
|
|
605e9cfe6d | ||
|
|
dd53c7b200 | ||
|
|
f9b10dc9db | ||
|
|
daef491d3e | ||
|
|
95fde17d97 | ||
|
|
2c6cbb7799 | ||
|
|
3498d4317a | ||
|
|
611ef49d03 | ||
|
|
fd2212db7b | ||
|
|
4d8b8ba64c | ||
|
|
32fe70a354 | ||
|
|
e2652df546 | ||
|
|
d1427d5f99 | ||
|
|
ef814f3602 | ||
|
|
00acc8289e | ||
|
|
341f980974 | ||
|
|
1b7ea5bed3 | ||
|
|
ee1c92ffa0 | ||
|
|
0114a50f61 | ||
|
|
c7c9e105ef | ||
|
|
3e31e71116 | ||
|
|
e74b1d2210 | ||
|
|
1ca2f28187 | ||
|
|
9fc75b651e | ||
|
|
934a6acdd2 | ||
|
|
88adc5676f | ||
|
|
f27483ea7b | ||
|
|
6a11c620cf | ||
|
|
7281f15051 | ||
|
|
b1196fb09b | ||
|
|
27fb875c0d | ||
|
|
3cdeac5dfb | ||
|
|
e1c47ce5c3 | ||
|
|
d9523cb1bc | ||
|
|
bd2403388e | ||
|
|
7511208b8b | ||
|
|
4586d44c1f | ||
|
|
717e5b07d1 | ||
|
|
2c6082f454 | ||
|
|
586239292b | ||
|
|
7bd1c87bf6 | ||
|
|
6eded4cdc2 | ||
|
|
5e693f2274 | ||
|
|
b0e3aeed6c | ||
|
|
dd9ef38636 | ||
|
|
32df782470 | ||
|
|
1d9162930c | ||
|
|
152d02bcbe | ||
|
|
2cc4dc724b | ||
|
|
1ee14f4c69 | ||
|
|
7748019a76 | ||
|
|
8241a1d8a3 | ||
|
|
83e3373561 | ||
|
|
c8c126d444 | ||
|
|
c12b1d0670 | ||
|
|
5caf4f45a9 | ||
|
|
8f51ff2910 | ||
|
|
6b8436f825 | ||
|
|
c4b146b36b | ||
|
|
098b14884d | ||
|
|
47d8818028 | ||
|
|
e3bc50a163 | ||
|
|
34ba6a86c9 | ||
|
|
2369ef53ac | ||
|
|
8d3907ff65 | ||
|
|
2760eaca85 | ||
|
|
af0319cc66 | ||
|
|
e050539747 | ||
|
|
451756c764 | ||
|
|
afa40df7ad | ||
|
|
fb2b606d26 | ||
|
|
e0ebd47730 | ||
|
|
e97f4e8020 | ||
|
|
79f07b7350 | ||
|
|
c1c8829536 | ||
|
|
ef20371562 | ||
|
|
c08f275cf7 | ||
|
|
6f995fe350 | ||
|
|
68aec92d3a | ||
|
|
dda328210c | ||
|
|
c3f4f232e3 | ||
|
|
302f1da066 | ||
|
|
a6e65d33dd | ||
|
|
7b0cb29466 | ||
|
|
a3eedb14f4 | ||
|
|
74d73a1d17 | ||
|
|
92e7e8516c | ||
|
|
61ac0b7d20 | ||
|
|
8b4ea7fd7c | ||
|
|
90846cf770 | ||
|
|
a9e33ea282 | ||
|
|
eea006e787 | ||
|
|
9e58098e5c | ||
|
|
ff49f574d4 | ||
|
|
599d816a88 | ||
|
|
4b0dd04114 | ||
|
|
36a0fbf181 | ||
|
|
3cfd8f40da | ||
|
|
23173c4bf4 | ||
|
|
722c31ccd9 | ||
|
|
7623a01272 | ||
|
|
1b90fdce73 | ||
|
|
ce57db9526 | ||
|
|
8b9e47cd11 | ||
|
|
a87a261b80 | ||
|
|
989d561679 | ||
|
|
b349990b19 | ||
|
|
2104b49cee | ||
|
|
77606efb77 | ||
|
|
6164ad2ab1 | ||
|
|
a60d58dcb0 | ||
|
|
4e45d17ad2 | ||
|
|
c8e614d064 | ||
|
|
544beeb078 | ||
|
|
a00f0d8367 | ||
|
|
ea57290792 | ||
|
|
603a4afaf3 | ||
|
|
19e2772729 | ||
|
|
82ebb82a5f | ||
|
|
516ae6b68c | ||
|
|
59225a4b9c | ||
|
|
1da9d36ecc | ||
|
|
0787e5c738 | ||
|
|
8a661088bb | ||
|
|
91659a32af | ||
|
|
5f8cd7e5c4 | ||
|
|
bc3f62a766 | ||
|
|
92faedb4a5 | ||
|
|
6f7008dd91 | ||
|
|
447589541f | ||
|
|
45f5f50262 | ||
|
|
f77a27ecc3 | ||
|
|
09de2eb194 | ||
|
|
7747a5665b | ||
|
|
aa617b5106 | ||
|
|
8038e2e01a | ||
|
|
212b068a8d | ||
|
|
2bcea0b566 | ||
|
|
512d4f2fb9 | ||
|
|
b524546e9c | ||
|
|
f91e287207 | ||
|
|
0fcf0a6a88 | ||
|
|
f9f3d74a3b | ||
|
|
2bfd0f2cc0 | ||
|
|
cdeb2eebe5 | ||
|
|
5134516afc | ||
|
|
e14b5d99eb | ||
|
|
a0375f52cf | ||
|
|
69dbcf3947 | ||
|
|
79387730bc | ||
|
|
3e6b019044 | ||
|
|
1886b90be7 | ||
|
|
85421f9b4b | ||
|
|
3749ef8433 | ||
|
|
dfb3e98fec | ||
|
|
a40442c8a9 | ||
|
|
a7396d6bee | ||
|
|
507c4c67ff | ||
|
|
cbdc04e929 | ||
|
|
a6582a1da3 | ||
|
|
3d8f3df8f1 | ||
|
|
7b8dbdedb5 | ||
|
|
53b13eacaa | ||
|
|
fcc76d99ef | ||
|
|
9a2141025a | ||
|
|
bfe3285375 | ||
|
|
5cf9c6e073 | ||
|
|
5e00d77e69 | ||
|
|
a4dfb05d0c | ||
|
|
97a798e357 | ||
|
|
47aafe88f8 | ||
|
|
bc356ab8e5 | ||
|
|
dd5cdfd848 | ||
|
|
de2cb08a6b | ||
|
|
9a2550ad48 | ||
|
|
2f6e4c0736 | ||
|
|
a9c5cbf11f | ||
|
|
facd0d398a | ||
|
|
1b2fc5d403 | ||
|
|
9d290aa533 | ||
|
|
9046291128 | ||
|
|
59131b6b51 | ||
|
|
3725a23c49 | ||
|
|
812c42c89a | ||
|
|
285d7d3265 | ||
|
|
134789602b | ||
|
|
55f49b5f78 | ||
|
|
cd8067285f | ||
|
|
10c09e9375 | ||
|
|
bb70c0733a | ||
|
|
3dad2b31bb | ||
|
|
7844acd70f | ||
|
|
f01b0b3404 | ||
|
|
10fee6e144 | ||
|
|
c4c8a8b703 | ||
|
|
7053a1e42a | ||
|
|
fd3c4261de | ||
|
|
d21e475d12 | ||
|
|
48bdf0b2a9 | ||
|
|
ac1c652854 | ||
|
|
3b286de9db | ||
|
|
cbcb696cfd | ||
|
|
13320ea8cc | ||
|
|
bdf45f6a0b | ||
|
|
667b1e9f99 | ||
|
|
e52e82fb78 | ||
|
|
78cb3f8ee2 | ||
|
|
a0f476fb24 | ||
|
|
13c32bfe53 | ||
|
|
a54da059ef | ||
|
|
76fe0def4f | ||
|
|
9a25b747ae | ||
|
|
aeefd3e873 | ||
|
|
f9efdcb654 | ||
|
|
be672cbcba | ||
|
|
c4ca7e471a | ||
|
|
bbce082ec2 | ||
|
|
781214a2f0 | ||
|
|
7942eaf64b | ||
|
|
36cd3c0c42 | ||
|
|
620bccb102 | ||
|
|
3ca79bebc7 | ||
|
|
a1add0cfdb | ||
|
|
dc22ad1ca1 | ||
|
|
010df5a081 | ||
|
|
71e8b22849 | ||
|
|
17dcc7ec80 | ||
|
|
138c17d4a3 | ||
|
|
565eed99ef | ||
|
|
1f13c47a46 | ||
|
|
ec5d12c940 | ||
|
|
bac19b2486 | ||
|
|
5fbfa1453c | ||
|
|
dab2001dcc | ||
|
|
5bff9eb4d8 | ||
|
|
e2102bdefa | ||
|
|
2a3e06610f | ||
|
|
d186240cfc | ||
|
|
0f0d4f06bb | ||
|
|
249af325c9 | ||
|
|
a7532f2154 | ||
|
|
1c0a00e9b2 | ||
|
|
b1b8066fe5 | ||
|
|
25c2f3adad | ||
|
|
68e47d70fd | ||
|
|
af3b3f4ee5 | ||
|
|
1b63d514ac | ||
|
|
c6453a6e10 | ||
|
|
3f3f5fdaa0 | ||
|
|
2f72721ee2 | ||
|
|
92d99c6d64 | ||
|
|
f3b26b1101 | ||
|
|
4f0a5bcf15 | ||
|
|
ffb1a8ad84 | ||
|
|
70c07cf731 | ||
|
|
b2d946794b | ||
|
|
90617c5433 | ||
|
|
278dc34b44 | ||
|
|
dcd5d7b534 | ||
|
|
2d48465e1d | ||
|
|
6bda493f6e | ||
|
|
5459b8bb7a | ||
|
|
e410939bde | ||
|
|
047de2d747 | ||
|
|
997f4d35c2 | ||
|
|
ca547f1239 | ||
|
|
c9665773e2 | ||
|
|
eeeea6b735 | ||
|
|
bbd6a2b5d5 | ||
|
|
d33db2a0fe | ||
|
|
1f2588d677 | ||
|
|
f30bad5c5a | ||
|
|
5a5bf77b1c | ||
|
|
22c6597005 | ||
|
|
9761d70f23 | ||
|
|
518135006c | ||
|
|
9327eb7e75 | ||
|
|
13080ade9e | ||
|
|
9c3947a7b1 | ||
|
|
f33cbcaa53 | ||
|
|
2c8fe7971f | ||
|
|
85e10330cb | ||
|
|
a02fd4b6f6 | ||
|
|
9395119749 | ||
|
|
2c0bbe9082 | ||
|
|
b1535864aa | ||
|
|
fd880da057 | ||
|
|
6c62b06e46 | ||
|
|
b44869ec49 | ||
|
|
b3a6251b04 | ||
|
|
80667bc38f | ||
|
|
cff35ea845 | ||
|
|
cb93397ae4 | ||
|
|
c805a8d624 | ||
|
|
3f775c081c | ||
|
|
864b892da0 | ||
|
|
f7773d2113 | ||
|
|
cf471d0f36 | ||
|
|
d14791679c | ||
|
|
f358d34e54 | ||
|
|
7ba3a7dd2f | ||
|
|
196af51e2c | ||
|
|
cbe959da66 | ||
|
|
9512fd4cca | ||
|
|
e2b6853c46 | ||
|
|
2578bfd0ff | ||
|
|
277fff5f2c | ||
|
|
4c72e9d206 | ||
|
|
7a44a303e5 | ||
|
|
e3796045eb | ||
|
|
85ad8d8b9f | ||
|
|
f737c92988 | ||
|
|
5d05ecaee3 | ||
|
|
8cc83a8df9 | ||
|
|
43b0f1bea9 | ||
|
|
a12ee4a61e | ||
|
|
d595a45f2b | ||
|
|
76a6d59837 | ||
|
|
bfe9bf2d5b | ||
|
|
59cac169e7 | ||
|
|
c24ee89b16 | ||
|
|
a73c2d7292 | ||
|
|
97671b3592 | ||
|
|
dd38586ead | ||
|
|
e11de68203 | ||
|
|
97ce286ff2 | ||
|
|
99e4e5a219 | ||
|
|
316b9aa68a | ||
|
|
7318d6615f | ||
|
|
6782b108b0 | ||
|
|
494af0ad23 | ||
|
|
55cff03747 | ||
|
|
599cc7c3af | ||
|
|
bfa7a7a6dc | ||
|
|
b243a5404b | ||
|
|
2e40a7377a | ||
|
|
62e86a0474 | ||
|
|
8c1ee9cf21 | ||
|
|
3afda882de | ||
|
|
69fd90ed3a | ||
|
|
554530dd60 | ||
|
|
2472e5546f | ||
|
|
a7ee4c09f5 | ||
|
|
7effac73b9 | ||
|
|
125924d125 | ||
|
|
00aaac866f | ||
|
|
170299c13c | ||
|
|
ac6f56dbf4 | ||
|
|
09c494c6c5 | ||
|
|
fdd685d20c | ||
|
|
fcff22981b | ||
|
|
7f82a41e66 | ||
|
|
17d12b41db | ||
|
|
2f7d68f7f1 | ||
|
|
dc1c65b418 | ||
|
|
23de013c86 | ||
|
|
a922b00716 | ||
|
|
babe21a3dc | ||
|
|
59ef0b05a1 | ||
|
|
3da7ed76c5 | ||
|
|
bbf0cd7578 | ||
|
|
25be97e65c | ||
|
|
175bb9206e | ||
|
|
68605ad409 | ||
|
|
4500687d47 | ||
|
|
fc38e6f270 | ||
|
|
f1936fea6b | ||
|
|
24bdcf66ed | ||
|
|
8688523ced | ||
|
|
856944e463 | ||
|
|
84f6894bc4 | ||
|
|
9bf33f89a9 | ||
|
|
c0fa7c42cd | ||
|
|
3281a85ae9 | ||
|
|
0db965a95f | ||
|
|
0732ea1162 | ||
|
|
c88497afba | ||
|
|
d4892c19b4 | ||
|
|
3ed25b069d | ||
|
|
e51b1f7643 | ||
|
|
7d07b27d4f | ||
|
|
57fdc90623 | ||
|
|
72bec2ef49 | ||
|
|
58a3805788 | ||
|
|
40f96dd2bd | ||
|
|
fca13d453e | ||
|
|
32e590f398 | ||
|
|
301b44dcae | ||
|
|
e45e91b0bf | ||
|
|
fe31dbca26 | ||
|
|
51fa754ec5 | ||
|
|
2ce10af051 | ||
|
|
c107422353 | ||
|
|
1e1fdee5a7 | ||
|
|
fffcd61cc4 | ||
|
|
2fd11cba15 | ||
|
|
f1ec85aef5 | ||
|
|
4c4b363035 | ||
|
|
8555e0c7e7 | ||
|
|
c07f7390ec | ||
|
|
34f6e15271 | ||
|
|
135f0677e4 | ||
|
|
63ad255f2b | ||
|
|
16ac8ea196 | ||
|
|
0e00773238 | ||
|
|
cf1f676268 | ||
|
|
d2f304b047 | ||
|
|
0a9bb138c5 | ||
|
|
6236391c86 | ||
|
|
78257cb1c0 | ||
|
|
c4cb75668c | ||
|
|
9880bcacd6 | ||
|
|
52aedd0a31 | ||
|
|
c7ce741857 | ||
|
|
bcbf012406 | ||
|
|
ec75b4418b | ||
|
|
716b84f507 | ||
|
|
e95b3a59ef | ||
|
|
9dc179b2cd | ||
|
|
efe1b01936 | ||
|
|
cd26b0c5a9 | ||
|
|
b075f71f11 | ||
|
|
44145ef265 | ||
|
|
82ef21b821 | ||
|
|
5655d7456c | ||
|
|
a7992102af | ||
|
|
ee2cd412ce | ||
|
|
1c34f48c39 | ||
|
|
0c2937936b | ||
|
|
b0c3f6c82a | ||
|
|
e047525be9 | ||
|
|
7f1ad590f6 | ||
|
|
fbf2d827c2 | ||
|
|
72619df02c | ||
|
|
c58d8992cf | ||
|
|
c98177ea20 | ||
|
|
766409e581 | ||
|
|
c076d61cc9 | ||
|
|
92e265ecc9 | ||
|
|
e223df64cf | ||
|
|
629ebf5ff2 | ||
|
|
0019eb70b5 | ||
|
|
e5f1be0b30 | ||
|
|
dd74934638 | ||
|
|
8d4973a9cc | ||
|
|
a49c091cd5 | ||
|
|
7d0268a4ce | ||
|
|
44e53e7225 | ||
|
|
1a1689da1f | ||
|
|
a28802e84e | ||
|
|
2798e71a52 | ||
|
|
e3647092b0 | ||
|
|
117cc13ed7 | ||
|
|
2d39a04575 | ||
|
|
d3e9457532 | ||
|
|
afc737b9bd | ||
|
|
32e597f6a4 |
21
.dockerignore
Normal file
21
.dockerignore
Normal file
@@ -0,0 +1,21 @@
|
||||
git/
|
||||
bundle/
|
||||
.idea/
|
||||
.yardoc/
|
||||
cache/
|
||||
coverage/
|
||||
spec/
|
||||
dev/
|
||||
.*
|
||||
**/*.md
|
||||
*.md
|
||||
Dockerfile
|
||||
**/*.orig
|
||||
*.orig
|
||||
CREDITS
|
||||
data.zip
|
||||
DISCLAIMER.txt
|
||||
example.conf.json
|
||||
bin/
|
||||
log.txt
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.ash_history
|
||||
cache
|
||||
coverage
|
||||
.bundle
|
||||
@@ -6,8 +7,10 @@ coverage
|
||||
*.sublime-*
|
||||
.idea
|
||||
.*.swp
|
||||
Gemfile.lock
|
||||
log.txt
|
||||
.yardoc
|
||||
debug.log
|
||||
wordlist.txt
|
||||
rspec_results.html
|
||||
data/
|
||||
vendor/
|
||||
|
||||
1
.ruby-gemset
Normal file
1
.ruby-gemset
Normal file
@@ -0,0 +1 @@
|
||||
wpscan
|
||||
1
.ruby-version
Normal file
1
.ruby-version
Normal file
@@ -0,0 +1 @@
|
||||
2.4.1
|
||||
33
.travis.yml
33
.travis.yml
@@ -1,6 +1,31 @@
|
||||
language: ruby
|
||||
sudo: false
|
||||
cache: bundler
|
||||
rvm:
|
||||
- "1.9.2"
|
||||
- "1.9.3"
|
||||
- "2.0.0"
|
||||
script: bundle exec rspec --format documentation
|
||||
- 2.1.9
|
||||
- 2.2.0
|
||||
- 2.2.1
|
||||
- 2.2.2
|
||||
- 2.2.3
|
||||
- 2.2.4
|
||||
- 2.3.0
|
||||
- 2.3.1
|
||||
- 2.3.2
|
||||
- 2.3.3
|
||||
- 2.4.1
|
||||
before_install:
|
||||
- "env"
|
||||
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
||||
- "gem install bundler"
|
||||
- "bundler --version"
|
||||
before_script:
|
||||
- "unzip -o $TRAVIS_BUILD_DIR/data.zip -d $TRAVIS_BUILD_DIR"
|
||||
script:
|
||||
- "bundle exec rspec"
|
||||
notifications:
|
||||
email:
|
||||
- team@wpscan.org
|
||||
# do not build gh-pages branch
|
||||
branches:
|
||||
except:
|
||||
- gh-pages
|
||||
|
||||
443
CHANGELOG.md
443
CHANGELOG.md
@@ -1,9 +1,435 @@
|
||||
# Changelog
|
||||
## Master
|
||||
[Work in progress](https://github.com/wpscanteam/wpscan/compare/2.9.3...master)
|
||||
|
||||
## Version 2.9.3
|
||||
Released: 2017-07-19
|
||||
|
||||
* Updated dependencies and required ruby version
|
||||
* Made some changes so wpscan works in ruby 2.4
|
||||
* Added a Gemfile.lock to lock all dependencies
|
||||
* You can now pass a wordlist from stdin via "--wordlist -"
|
||||
* Improved version detection regexes
|
||||
* Added an optional paramter to --log to specify a filename
|
||||
|
||||
WPScan Database Statistics:
|
||||
* Total tracked wordpresses: 251
|
||||
* Total tracked plugins: 68818
|
||||
* Total tracked themes: 15132
|
||||
* Total vulnerable wordpresses: 243
|
||||
* Total vulnerable plugins: 1527
|
||||
* Total vulnerable themes: 280
|
||||
* Total wordpress vulnerabilities: 5263
|
||||
* Total plugin vulnerabilities: 2406
|
||||
* Total theme vulnerabilities: 349
|
||||
|
||||
## Version 2.9.2
|
||||
Released: 2016-11-15
|
||||
|
||||
* Fixed error when detecting plugins with UTF-8 characters
|
||||
* Use all possible finders to verify a detected version
|
||||
* Fix error when detecting a WordPress version not in our database
|
||||
* Added some additional clarification on error messages
|
||||
* Upgrade terminal-table gem
|
||||
* Add --cache-dir option
|
||||
* Add --disable-tls-checks options
|
||||
* Improve/add additional plugin passive detections
|
||||
* Remove scripts when calculating page hashes
|
||||
* Many other small bug fixes.
|
||||
|
||||
WPScan Database Statistics:
|
||||
* Total tracked wordpresses: 194
|
||||
* Total tracked plugins: 63703
|
||||
* Total tracked themes: 13835
|
||||
* Total vulnerable wordpresses: 177
|
||||
* Total vulnerable plugins: 1382
|
||||
* Total vulnerable themes: 379
|
||||
* Total wordpress vulnerabilities: 2617
|
||||
* Total plugin vulnerabilities: 2190
|
||||
* Total theme vulnerabilities: 452
|
||||
|
||||
## Version 2.9.1
|
||||
Released: 2016-05-06
|
||||
|
||||
* Update to Ruby 2.3.1, drop older ruby support
|
||||
* New data file location
|
||||
* Added experimental Windows support
|
||||
* Display WordPress metadata on the detected version
|
||||
* Several small fixes
|
||||
|
||||
WPScan Database Statistics:
|
||||
* Total vulnerable versions: 156
|
||||
* Total vulnerable plugins: 1324
|
||||
* Total vulnerable themes: 376
|
||||
* Total version vulnerabilities: 1998
|
||||
* Total plugin vulnerabilities: 2057
|
||||
* Total theme vulnerabilities: 449
|
||||
|
||||
## Version 2.9
|
||||
Released: 2015-10-15
|
||||
|
||||
New
|
||||
* GZIP Encoding in updater
|
||||
* Adds --throttle option to throttle requests
|
||||
* Uses new API and local database file structure
|
||||
* Adds last updated and latest version to plugins and themes
|
||||
|
||||
Removed
|
||||
* ArchAssault from README
|
||||
* APIv1 local databases
|
||||
|
||||
General core
|
||||
* Update to Ruby 2.2.3
|
||||
* Use yajl-ruby as JSON parser
|
||||
* New dependancy for Ubuntu 14.04 (libgmp-dev)
|
||||
* Use Travis container based infra and caching
|
||||
|
||||
Fixed issues
|
||||
* Fix #835 - Readme requests to wp root dir
|
||||
* Fix #836 - Critical icon output twice when the site is not running WP
|
||||
* Fix #839 - Terminal-table dependency is broken
|
||||
* Fix #841 - error: undefined method `cells' for #<Array:0x000000029cc2f8>
|
||||
* Fix #852 - GZIP Encoding in updater
|
||||
* Fix #853 - APIv2 integration
|
||||
* Fix #858 - Detection FP
|
||||
* Fix #873 - false positive "site has Must Use Plugins"
|
||||
|
||||
WPScan Database Statistics:
|
||||
* Total vulnerable versions: 132
|
||||
* Total vulnerable plugins: 1170
|
||||
* Total vulnerable themes: 368
|
||||
* Total version vulnerabilities: 1476
|
||||
* Total plugin vulnerabilities: 1913
|
||||
* Total theme vulnerabilities: 450
|
||||
|
||||
## Version 2.8
|
||||
Released: 2015-06-22
|
||||
|
||||
New
|
||||
* Warn the user to update his DB files
|
||||
* Added last db update to --version option (see #815)
|
||||
* Add db checksum to verbose logging during update
|
||||
* Option to hide banner
|
||||
* Continue if user chooses not to update + db exists
|
||||
* Don't update if user chooses default + no DBs exist
|
||||
* Updates request timeout values to realistic ones (and in seconds)
|
||||
|
||||
Removed
|
||||
* Removed `Time.parse('2000-01-01')` expedient
|
||||
* Removed unnecessary 'return' and '()'
|
||||
* Removed debug output
|
||||
* Removed wpstools
|
||||
|
||||
General core
|
||||
* Update to Ruby 2.2.2
|
||||
* Switch to mitre
|
||||
* Install bundler gem README
|
||||
* Switch from gnutls to openssl
|
||||
|
||||
Fixed issues
|
||||
* Fix #789 - Add blackarch to readme
|
||||
* Fix #790 - Consider the target down after 30 requests timed out requests instead of 10
|
||||
* Fix #791 - Rogue character causing the scan of non-wordpress site to crash
|
||||
* Fix #792 - Adds the HttpError exception
|
||||
* Fix #795 - Remove GHOST warning
|
||||
* Fix #796 - Do not swallow exit code
|
||||
* Fix #797 - Increases the timeout values
|
||||
* Fix #801 - Forces UTF-8 encoding when enumerating usernames
|
||||
* Fix #803 - Increases default connect-timeout to 10s
|
||||
* Fix #804 - Updates the Theme detection pattern
|
||||
* Fix #816 - Ignores potential non version chars in theme version detection
|
||||
* Fix #819 - Removes potential spaces in robots.txt entries
|
||||
|
||||
WPScan Database Statistics:
|
||||
* Total vulnerable versions: 98
|
||||
* Total vulnerable plugins: 1076
|
||||
* Total vulnerable themes: 361
|
||||
* Total version vulnerabilities: 1104
|
||||
* Total plugin vulnerabilities: 1763
|
||||
* Total theme vulnerabilities: 443
|
||||
|
||||
## Version 2.7
|
||||
Released: 2015-03-16
|
||||
|
||||
New
|
||||
* Detects version in release date format
|
||||
* Copyrights updated
|
||||
* WP version detection from stylesheets
|
||||
* New license
|
||||
* Global HTTP request counter
|
||||
* Add security-protection plugin detection
|
||||
* Add GHOST warning if XMLRPC enabled
|
||||
* Update databases from wpvulndb.com
|
||||
* Enumerate usernames from WP <= 3.0 (thanks berotti3)
|
||||
|
||||
Removed
|
||||
* README.txt
|
||||
|
||||
General core
|
||||
* Update to Ruby 2.2.1
|
||||
* Update to Ruby 2.2.0
|
||||
* Add addressable gem
|
||||
* Update Typhoeus gem to 0.7.0
|
||||
* IDN support: encode non-ascii domain names (thanks dctabuyz)
|
||||
* Improve page hash calculation (thanks dctabuyz)
|
||||
* Version detection regex improved
|
||||
|
||||
Fixed issues
|
||||
* Fix #745 - Plugin version pattern in readme.txt file not detected
|
||||
* Fix #746 - Add a global counter for all active requests to server.
|
||||
* Fix #747 - Add 'security-protection' plugin to wp_login_protection module
|
||||
* Fix #753 - undefined method `round' for "10":String for request or connect timeouts
|
||||
* Fix #760 - typhoeus issue (infinite loop)
|
||||
|
||||
WPScan Database Statistics:
|
||||
* Total vulnerable versions: 89
|
||||
* Total vulnerable plugins: 953
|
||||
* Total vulnerable themes: 329
|
||||
* Total version vulnerabilities: 1070
|
||||
* Total plugin vulnerabilities: 1451
|
||||
* Total theme vulnerabilities: 378
|
||||
|
||||
## Version 2.6
|
||||
Released: 2014-12-19
|
||||
|
||||
New
|
||||
* Updates the readmes to reflect the new --usernames option
|
||||
* Improves plugin/theme version detection by looking at the "Version:"
|
||||
* Solution to avoid mandatory blank newline at the end of the wordlist
|
||||
* Add check for valid credentials
|
||||
* Add Sucuri sponsor to banner
|
||||
* Add protocol to sucuri url in banner
|
||||
* Add response code to proxy error output
|
||||
* Add a statement about mandatory newlines at the end of list
|
||||
* Give warning if default username 'admin' is still used
|
||||
* License amendment to make it more clear about value added usage
|
||||
|
||||
Removed
|
||||
* remove malwares
|
||||
* remove malware folder
|
||||
* Removes the theme version check from the readme, unrealistic scenario
|
||||
|
||||
General core
|
||||
* Update to Ruby 2.1.5 and travis
|
||||
* Prevent parent theme infinite loop
|
||||
* Fixes the progressbar being overriden by next brute forcing attempts
|
||||
|
||||
Fixed issues
|
||||
* Fix UTF-8 encode on security db file download
|
||||
* Fix #703 - Disable logging by default. Implement log option.
|
||||
* Fix #705 - Installation instructions for Ubuntu < 14.04 apparently incomplete
|
||||
* Fix #717 - Expand on readme.html finding output
|
||||
* Fix #716 - Adds the --version in the help
|
||||
* Fix #715 - Add new updating info to docs
|
||||
* Fix #727 - WpItems detection: Perform the passive check and filter only vulnerable results at the end if required
|
||||
* Fix #737 - Adds some readme files to check for plugin versions
|
||||
* Fix #739 - Adds the --usernames option
|
||||
|
||||
WPScan Database Statistics:
|
||||
* Total vulnerable versions: 88
|
||||
* Total vulnerable plugins: 901
|
||||
* Total vulnerable themes: 313
|
||||
* Total version vulnerabilities: 1050
|
||||
* Total plugin vulnerabilities: 1355
|
||||
* Total theme vulnerabilities: 349
|
||||
|
||||
## Version 2.5.1
|
||||
Released: 2014-09-29
|
||||
|
||||
Fixes reference URL to WPVDB
|
||||
|
||||
## Version 2.5
|
||||
Released: 2014-09-26 (@ BruCON 2014)
|
||||
|
||||
New
|
||||
* Exit program after --update
|
||||
* Detect directory listing in upload folder
|
||||
* Be more verbose when no version can be detected
|
||||
* Added detection for Yoast Wordpress SEO plugin
|
||||
* Also ensure to not process empty Location headers
|
||||
* Ensures a nil location is not processed when enumerating usernames
|
||||
* Fix #626 - Detect 'Must_Use_Plugins'
|
||||
* better username extraction
|
||||
* Add a --cookie option. Ref #485
|
||||
* Add a --no-color option
|
||||
* Output: Give 'Fixed in' an informational tag
|
||||
* Added ArchAssault distro - WPScan comes pre-installed with this distro
|
||||
* Layout changes with new colors
|
||||
|
||||
Removed
|
||||
* Removes the source code updaters
|
||||
* Removes the ListGenerator plugin from WPStools
|
||||
* Removes all files from data/
|
||||
|
||||
General core
|
||||
* Update docs to reflect new updating logic
|
||||
* Little output change and coloring
|
||||
* Adds a missing verbose output
|
||||
* Re-build redirection url if begin with slash '/'
|
||||
* Fixes the remove_conditional_comments function
|
||||
* Ensures to give a string to Typhoeus
|
||||
* Fix wpstools check-vuln-ref-urls
|
||||
* Fix rspecs for new json
|
||||
* Only output if different from style_url
|
||||
* Add exception so 'ruby wpscan.rb http://domain.com' is detected
|
||||
* Added make to Debian installation, which is needed in minimal installation.
|
||||
* Add build-essentials requirement to Ubuntu > 14.04
|
||||
* Updated installation instr. for GNU/Linux Debian.
|
||||
* Changes VersionCompare#is_newer_or_same? by lesser_or_equal?
|
||||
* Fixes the location of the robots.txt check
|
||||
* Updates the recommended ruby version
|
||||
* Rspec 3.0 support
|
||||
* Adds ruby 2.1.2 to Travis
|
||||
* Updated ruby-progressbar to 1.5.0
|
||||
|
||||
WordPress Fingerprints
|
||||
* Adds WP 4.0 fingerprints
|
||||
* Adds WP 3.9.2, 3.8.4 & 3.7.4 fingerprints - Ref #652
|
||||
* Adds 3.9.1 fingerprints
|
||||
|
||||
Fixed issues
|
||||
* Fix #689 - Adds config file to check
|
||||
* Fix #694 - Output Arrays
|
||||
* Fix #693 - Adds pathname require statement
|
||||
* Fix #657 - generate method
|
||||
* Fix #685 - Potenial fix for 'marshal data too short' error
|
||||
* Fix #686 - Adds specs for relative URI in Location headers
|
||||
* Fix #435 - Update license
|
||||
* Fix #674 - Improves the Plugins & Themes passive detection
|
||||
* Fix #673 - Problem with the output
|
||||
* Fix #661 - Don't hash directories named like a file
|
||||
* Fix #653 - Fix for infinite loop in wpstools
|
||||
* Fix #625 - Only parse styles when needed
|
||||
* Fix #481 - Fix for Jetpack plugin false positive
|
||||
* Fix #480 - Properly removes the colour sequence from log
|
||||
* Fix #472 - WPScan stops after redirection if not WordPress website
|
||||
* Fix #464 - Readmes updated to reflect recent changes about the config file & batch mode
|
||||
|
||||
Vulnerabilities
|
||||
* geoplaces4 also uses name GeoPlaces4beta
|
||||
* Added metasploit module's
|
||||
* Added some timthumb detections
|
||||
|
||||
WPScan Database Statistics:
|
||||
* Total vulnerable versions: 87
|
||||
* Total vulnerable plugins: 854
|
||||
* Total vulnerable themes: 303
|
||||
* Total version vulnerabilities: 752
|
||||
* Total plugin vulnerabilities: 1351
|
||||
* Total theme vulnerabilities: 345
|
||||
|
||||
## Version 2.4
|
||||
Released: 2014-04-17
|
||||
|
||||
New
|
||||
* '--batch' switch option added - Fix #454
|
||||
* Add random-agent
|
||||
* Added more CLI options
|
||||
* Switch over to nist - Fix #301
|
||||
* New choice added when a redirection is detected - Fix #438
|
||||
|
||||
Removed
|
||||
* Removed 'Total WordPress Sites in the World' counter from stats
|
||||
* Old wpscan repo links removed - Fix #440
|
||||
* Fingerprinting Dev script removed
|
||||
* Useless code removed
|
||||
|
||||
General core
|
||||
* Rspecs update
|
||||
* Forcing Travis notify the team
|
||||
* Ruby 2.1.1 added to Travis
|
||||
* Equal output layout for interaction questions
|
||||
* Only output error trace if verbose if enabled
|
||||
* Memory improvements during wp-items enumerations
|
||||
* Fixed broken link checker, fixed some broken links
|
||||
* Couple more 404s fixed
|
||||
* Themes & Plugins list updated
|
||||
|
||||
WordPress Fingerprints
|
||||
* WP 3.8.2 & 3.7.2 Fingerprints added - Fix #448
|
||||
* WP 3.8.3 & 3.7.3 fingerprints
|
||||
* WP 3.9 fingerprints
|
||||
|
||||
Fixed issues
|
||||
* Fix #380 - Redirects in WP 3.6-3.0
|
||||
* Fix #413 - Check the version of the Timthumbs files found
|
||||
* Fix #429 - Error WpScan Cache Browser
|
||||
* Fix #431 - Version number comparison between '2.3.3' and '0.42b'
|
||||
* Fix #439 - Detect if the target goes down during the scan
|
||||
* Fix #451 - Do not rely only on files in wp-content for fingerprinting
|
||||
* Fix #453 - Documentation or inplemention of option parameters
|
||||
* Fix #455 - Fails with a message if the target returns a 403 during the wordpress check
|
||||
|
||||
Vulnerabilities
|
||||
* Update WordPress Vulnerabilities
|
||||
* Fixed some duplicate vulnerabilities
|
||||
|
||||
WPScan Database Statistics:
|
||||
* Total vulnerable versions: 79; 1 is new
|
||||
* Total vulnerable plugins: 748; 55 are new
|
||||
* Total vulnerable themes: 292; 41 are new
|
||||
* Total version vulnerabilities: 617; 326 are new
|
||||
* Total plugin vulnerabilities: 1162; 146 are new
|
||||
* Total theme vulnerabilities: 330; 47 are new
|
||||
|
||||
## Version 2.3
|
||||
Released: 2014-02-11
|
||||
|
||||
New
|
||||
* Brute forcing over https!
|
||||
* Detect and output parent theme!
|
||||
* Complete fingerprint script & hash search
|
||||
* New spell checker!
|
||||
* Added database modification dates in status report
|
||||
* Added 'Total WordPress Sites in the World' statistics
|
||||
* Added separator between Name and Version in Item
|
||||
* Added a "Work in progress" URL in the CHANGELOG
|
||||
|
||||
Removed
|
||||
* Removed "Exiting!" sentence
|
||||
* Removed Backtrack Linux. Not maintained anymore.
|
||||
|
||||
General core
|
||||
* Ruby 2.1.0 added to Travis
|
||||
* Updated the version of WebMock required
|
||||
* Better string concatenation in code (improves speed)
|
||||
* Some modifications in the output of an item
|
||||
* Output cosmetics
|
||||
* rspec-mocks version constraint released
|
||||
* Tabs replaced by spaces
|
||||
* Rspecs update
|
||||
* Indent code cleanup
|
||||
* Themes & Plugins lists regenerated
|
||||
|
||||
Vulnerabilities
|
||||
* Update WordPress Vulnerabilities
|
||||
* Disabled some fake reported vulnerabilities
|
||||
* Fixed some duplicate vulnerabilities
|
||||
|
||||
WPScan Database Statistics:
|
||||
* Total vulnerable versions: 78; 2 are new
|
||||
* Total vulnerable plugins: 693; 83 are new
|
||||
* Total vulnerable themes: 251; 55 are new
|
||||
* Total version vulnerabilities: 291 17 are new
|
||||
* Total plugin vulnerabilities: 1016; 236 are new
|
||||
* Total theme vulnerabilities: 283; 79 are new
|
||||
|
||||
WordPress Fingerprints
|
||||
* Better fingerprints
|
||||
* WP 3.8.1 Fingerprinting
|
||||
* WP 3.8 Fingerprinting
|
||||
|
||||
Fixed issues
|
||||
* Fix #404 - Brute forcing issue over https
|
||||
* Fix #398 - Removed a fake vuln in WP Super Cache
|
||||
* Fix #393 - sudo added to the bundle install cmd for Mac OSX
|
||||
* Fix #228, #327 - Infinite loop when self-redirect
|
||||
* Fix #201 - Incorrect Paramter Parsing when no url was supplied
|
||||
|
||||
## Version 2.2
|
||||
Released: 2013-11-12
|
||||
|
||||
Added
|
||||
New
|
||||
* Output the vulnerability fix if available
|
||||
* Added 'WordPress Version Vulnerability' statistics
|
||||
* Added Kali Linux on the list of pre-installed Linux distributions
|
||||
@@ -82,13 +508,13 @@ Vulnerabilities
|
||||
* Update timthumb due to Secunia #54801
|
||||
* Added WP vuln: 3.4 - 3.5.1 wp-admin/users.php FPD
|
||||
|
||||
WPScan Databse Statistics:
|
||||
* Total vulnerable versions: 76, 4 are new
|
||||
* Total vulnerable plugins: 606, 197 are new
|
||||
* Total vulnerable themes: 194, 45 are new
|
||||
* Total version vulnerabilities: 274, 53 are new
|
||||
* Total plugin vulnerabilities: 764, 270 are new
|
||||
* Total theme vulnerabilities: 198, 46 are new
|
||||
WPScan Database Statistics:
|
||||
* Total vulnerable versions: 76; 4 are new
|
||||
* Total vulnerable plugins: 610; 201 are new
|
||||
* Total vulnerable themes: 196; 47 are new
|
||||
* Total version vulnerabilities: 274; 53 are new
|
||||
* Total plugin vulnerabilities: 780; 286 are new
|
||||
* Total theme vulnerabilities: 204; 52 are new
|
||||
|
||||
Add WP Fingerprints
|
||||
* WP 3.7.1 Fingerprinting
|
||||
@@ -130,4 +556,3 @@ Fixed issues
|
||||
|
||||
## Version 2.1
|
||||
Released 2013-3-4
|
||||
|
||||
|
||||
11
CREDITS
11
CREDITS
@@ -1,20 +1,21 @@
|
||||
**CREDITS**
|
||||
|
||||
This file is to give credit to WPScan's contributors. If you feel your name should be in here, email ryandewhurst at gmail.
|
||||
This file is used to state the individual WPScan Team members (core developers) and give credit to WPScan's other contributors. If you feel your name should be in here email team@wpscan.org.
|
||||
|
||||
*WPScan Team*
|
||||
|
||||
Erwan.LR - @erwan_lr - (Project Developer)
|
||||
Christian Mehlmauer - @_FireFart_ - (Project Developer)
|
||||
Gianluca Brindisi - @gbrindisi (Project Developer)
|
||||
Peter van der Laan - pvdl - (Project Developer)
|
||||
Ryan Dewhurst - @ethicalhack3r (Project Lead)
|
||||
|
||||
*Other Contributors*
|
||||
|
||||
Henri Salo AKA fgeek - Reported lots of vulnerabilities
|
||||
Alip AKA Undead - alip.aswalid at gmail.com
|
||||
michee08 - Reported and gave potential solutions to bugs.
|
||||
michee08 - Reported and gave potential solutions to bugs
|
||||
Callum Pember - Implemented proxy support - callumpember at gmail.com
|
||||
g0tmi1k - Additional timthumb checks + bug reports.
|
||||
g0tmi1k - Additional timthumb checks + bug reports
|
||||
Melvin Lammerts - Reported a couple of fake vulnerabilities - melvin at 12k.nl
|
||||
Paolo Perego - @thesp0nge - Basic authentication
|
||||
Peter van der Laan - The Vuln Hunter and Code Cleaner
|
||||
Gianluca Brindisi - @gbrindisi - Ex Project Developer
|
||||
|
||||
2
DISCLAIMER.txt
Normal file
2
DISCLAIMER.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
WPScan is not responsible for misuse or for any damage that you may cause!
|
||||
You agree that you use this software at your own risk.
|
||||
29
Dockerfile
Normal file
29
Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
||||
FROM ruby:2.4-alpine
|
||||
MAINTAINER WPScan Team <team@wpscan.org>
|
||||
|
||||
ARG BUNDLER_ARGS="--jobs=8 --without test"
|
||||
|
||||
RUN adduser -h /wpscan -g WPScan -D wpscan
|
||||
RUN echo "gem: --no-ri --no-rdoc" > /etc/gemrc
|
||||
|
||||
COPY Gemfile /wpscan
|
||||
COPY Gemfile.lock /wpscan
|
||||
|
||||
# runtime dependencies
|
||||
RUN apk add --no-cache libcurl procps && \
|
||||
# build dependencies
|
||||
apk add --no-cache --virtual build-deps alpine-sdk ruby-dev libffi-dev zlib-dev && \
|
||||
bundle install --system --gemfile=/wpscan/Gemfile $BUNDLER_ARGS && \
|
||||
apk del --no-cache build-deps
|
||||
|
||||
COPY . /wpscan
|
||||
RUN chown -R wpscan:wpscan /wpscan
|
||||
|
||||
USER wpscan
|
||||
|
||||
RUN /wpscan/wpscan.rb --update --verbose --no-color
|
||||
|
||||
WORKDIR /wpscan
|
||||
|
||||
ENTRYPOINT ["/wpscan/wpscan.rb"]
|
||||
CMD ["--help"]
|
||||
22
Gemfile
22
Gemfile
@@ -1,15 +1,15 @@
|
||||
source "https://rubygems.org"
|
||||
source 'https://rubygems.org'
|
||||
|
||||
# Seg fault in Typhoeus 0.6.3 (and ethon > 0.5.11) with rspec
|
||||
gem "typhoeus", ">=0.6.3"
|
||||
gem "nokogiri"
|
||||
gem "json"
|
||||
gem "terminal-table"
|
||||
gem "ruby-progressbar", ">=1.2.0"
|
||||
gem 'typhoeus', '>=1.1.2'
|
||||
gem 'nokogiri', '>=1.7.0.1'
|
||||
gem 'addressable', '>=2.5.0'
|
||||
gem 'yajl-ruby', '>=1.3.0' # Better JSON parser regarding memory usage
|
||||
gem 'terminal-table', '>=1.6.0'
|
||||
gem 'ruby-progressbar', '>=1.8.1'
|
||||
|
||||
group :test do
|
||||
gem "webmock", ">=1.9.3"
|
||||
gem "simplecov"
|
||||
gem "rspec", :require => "spec"
|
||||
gem "rspec-mocks", "<=2.14.2" # 2.14.3 just messed around :/
|
||||
gem 'webmock', '>=2.3.2'
|
||||
gem 'simplecov', '>=0.13.0'
|
||||
gem 'rspec', '>=3.5.0'
|
||||
gem 'rspec-its', '>=1.2.0'
|
||||
end
|
||||
|
||||
69
Gemfile.lock
Normal file
69
Gemfile.lock
Normal file
@@ -0,0 +1,69 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
addressable (2.5.1)
|
||||
public_suffix (~> 2.0, >= 2.0.2)
|
||||
crack (0.4.3)
|
||||
safe_yaml (~> 1.0.0)
|
||||
diff-lcs (1.3)
|
||||
docile (1.1.5)
|
||||
ethon (0.10.1)
|
||||
ffi (>= 1.3.0)
|
||||
ffi (1.9.18)
|
||||
hashdiff (0.3.4)
|
||||
json (2.1.0)
|
||||
mini_portile2 (2.2.0)
|
||||
nokogiri (1.8.0)
|
||||
mini_portile2 (~> 2.2.0)
|
||||
public_suffix (2.0.5)
|
||||
rspec (3.6.0)
|
||||
rspec-core (~> 3.6.0)
|
||||
rspec-expectations (~> 3.6.0)
|
||||
rspec-mocks (~> 3.6.0)
|
||||
rspec-core (3.6.0)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-expectations (3.6.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-its (1.2.0)
|
||||
rspec-core (>= 3.0.0)
|
||||
rspec-expectations (>= 3.0.0)
|
||||
rspec-mocks (3.6.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-support (3.6.0)
|
||||
ruby-progressbar (1.8.1)
|
||||
safe_yaml (1.0.4)
|
||||
simplecov (0.14.1)
|
||||
docile (~> 1.1.0)
|
||||
json (>= 1.8, < 3)
|
||||
simplecov-html (~> 0.10.0)
|
||||
simplecov-html (0.10.1)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
typhoeus (1.1.2)
|
||||
ethon (>= 0.9.0)
|
||||
unicode-display_width (1.3.0)
|
||||
webmock (3.0.1)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff
|
||||
yajl-ruby (1.3.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
addressable (>= 2.5.0)
|
||||
nokogiri (>= 1.7.0.1)
|
||||
rspec (>= 3.5.0)
|
||||
rspec-its (>= 1.2.0)
|
||||
ruby-progressbar (>= 1.8.1)
|
||||
simplecov (>= 0.13.0)
|
||||
terminal-table (>= 1.6.0)
|
||||
typhoeus (>= 1.1.2)
|
||||
webmock (>= 2.3.2)
|
||||
yajl-ruby (>= 1.3.0)
|
||||
|
||||
BUNDLED WITH
|
||||
1.14.6
|
||||
83
LICENSE
83
LICENSE
@@ -1,15 +1,74 @@
|
||||
WPScan - WordPress Security Scanner
|
||||
Copyright (C) 2012-2013
|
||||
WPScan Public Source License
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
The WPScan software (henceforth referred to simply as "WPScan") is dual-licensed - Copyright 2011-2016 WPScan Team.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Cases that include commercialization of WPScan require a commercial, non-free license. Otherwise, WPScan can be used without charge under the terms set out below.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
1. Definitions
|
||||
|
||||
1.1 “License” means this document.
|
||||
1.2 “Contributor” means each individual or legal entity that creates, contributes to the creation of, or owns WPScan.
|
||||
1.3 “WPScan Team” means WPScan’s core developers, an updated list of whom can be found within the CREDITS file.
|
||||
|
||||
2. Commercialization
|
||||
|
||||
A commercial use is one intended for commercial advantage or monetary compensation.
|
||||
|
||||
Example cases of commercialization are:
|
||||
|
||||
- Using WPScan to provide commercial managed/Software-as-a-Service services.
|
||||
- Distributing WPScan as a commercial product or as part of one.
|
||||
- Using WPScan as a value added service/product.
|
||||
|
||||
Example cases which do not require a commercial license, and thus fall under the terms set out below, include (but are not limited to):
|
||||
|
||||
- Penetration testers (or penetration testing organizations) using WPScan as part of their assessment toolkit.
|
||||
- Penetration Testing Linux Distributions including but not limited to Kali Linux, SamuraiWTF, BackBox Linux.
|
||||
- Using WPScan to test your own systems.
|
||||
- Any non-commercial use of WPScan.
|
||||
|
||||
If you need to purchase a commercial license or are unsure whether you need to purchase a commercial license contact us - team@wpscan.org.
|
||||
|
||||
We may grant commercial licenses at no monetary cost at our own discretion if the commercial usage is deemed by the WPScan Team to significantly benefit WPScan.
|
||||
|
||||
Free-use Terms and Conditions;
|
||||
|
||||
3. Redistribution
|
||||
|
||||
Redistribution is permitted under the following conditions:
|
||||
|
||||
- Unmodified License is provided with WPScan.
|
||||
- Unmodified Copyright notices are provided with WPScan.
|
||||
- Does not conflict with the commercialization clause.
|
||||
|
||||
4. Copying
|
||||
|
||||
Copying is permitted so long as it does not conflict with the Redistribution clause.
|
||||
|
||||
5. Modification
|
||||
|
||||
Modification is permitted so long as it does not conflict with the Redistribution clause.
|
||||
|
||||
6. Contributions
|
||||
|
||||
Any Contributions assume the Contributor grants the WPScan Team the unlimited, non-exclusive right to reuse, modify and relicense the Contributor's content.
|
||||
|
||||
7. Support
|
||||
|
||||
WPScan is provided under an AS-IS basis and without any support, updates or maintenance. Support, updates and maintenance may be given according to the sole discretion of the WPScan Team.
|
||||
|
||||
8. Disclaimer of Warranty
|
||||
|
||||
WPScan is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the WPScan is free of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||
|
||||
9. Limitation of Liability
|
||||
|
||||
To the extent permitted under Law, WPScan is provided under an AS-IS basis. The WPScan Team shall never, and without any limit, be liable for any damage, cost, expense or any other payment incurred as a result of WPScan's actions, failure, bugs and/or any other interaction between WPScan and end-equipment, computers, other software or any 3rd party, end-equipment, computer or services.
|
||||
|
||||
10. Disclaimer
|
||||
|
||||
Running WPScan against websites without prior mutual consent may be illegal in your country. The WPScan Team accept no liability and are not responsible for any misuse or damage caused by WPScan.
|
||||
|
||||
11. Trademark
|
||||
|
||||
The "wpscan" term is a registered trademark. This License does not grant the use of the "wpscan" trademark or the use of the WPScan logo.
|
||||
|
||||
239
README
239
README
@@ -1,239 +0,0 @@
|
||||
__________________________________________________
|
||||
__ _______ _____
|
||||
\ \ / / __ \ / ____|
|
||||
\ \ /\ / /| |__) | (___ ___ __ _ _ __
|
||||
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
|
||||
\ /\ / | | ____) | (__| (_| | | | |
|
||||
\/ \/ |_| |_____/ \___|\__,_|_| |_|
|
||||
__________________________________________________
|
||||
|
||||
==LICENSE==
|
||||
|
||||
WPScan - WordPress Security Scanner
|
||||
Copyright (C) 2011-2013 The WPScan Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ryandewhurst at gmail
|
||||
|
||||
==INSTALL==
|
||||
|
||||
WPScan comes pre-installed on the following Linux distributions:
|
||||
|
||||
* BackBox Linux
|
||||
* BackTrack Linux
|
||||
* Pentoo
|
||||
* SamuraiWTF
|
||||
|
||||
Prerequisites:
|
||||
|
||||
* Windows not supported
|
||||
* Ruby >= 1.9.2 - Recommended: 1.9.3
|
||||
* Curl >= 7.21 - Recommended: latest - FYI the 7.29 has a segfault
|
||||
* RubyGems - Recommended: latest
|
||||
* Git
|
||||
|
||||
-> Installing on Debian/Ubuntu:
|
||||
|
||||
sudo apt-get install libcurl4-gnutls-dev libopenssl-ruby libxml2 libxml2-dev libxslt1-dev ruby-dev
|
||||
git clone https://github.com/wpscanteam/wpscan.git
|
||||
cd wpscan
|
||||
sudo gem install bundler && bundle install --without test
|
||||
|
||||
-> Installing on Fedora:
|
||||
|
||||
sudo yum install gcc ruby-devel libxml2 libxml2-devel libxslt libxslt-devel libcurl-devel
|
||||
git clone https://github.com/wpscanteam/wpscan.git
|
||||
cd wpscan
|
||||
sudo gem install bundler && bundle install --without test
|
||||
|
||||
-> Installing on Archlinux:
|
||||
|
||||
pacman -Syu ruby
|
||||
pacman -Syu libyaml
|
||||
|
||||
git clone https://github.com/wpscanteam/wpscan.git
|
||||
cd wpscan
|
||||
sudo gem install bundler && bundle install --without test
|
||||
|
||||
gem install typhoeus
|
||||
gem install nokogiri
|
||||
|
||||
-> Installing on Mac OS X:
|
||||
|
||||
Apple Xcode, Command Line Tools and the libffi are needed (to be able to install the FFI gem), See http://stackoverflow.com/questions/17775115/cant-setup-ruby-environment-installing-fii-gem-error
|
||||
|
||||
git clone https://github.com/wpscanteam/wpscan.git
|
||||
cd wpscan
|
||||
sudo gem install bundler && bundle install --without test
|
||||
|
||||
==KNOWN ISSUES==
|
||||
|
||||
- Typhoeus segmentation fault:
|
||||
Update cURL to version => 7.21 (may have to install from source)
|
||||
See http://code.google.com/p/wpscan/issues/detail?id=81
|
||||
|
||||
- Proxy not working:
|
||||
Update cURL to version => 7.21.7 (may have to install from source).
|
||||
|
||||
Installation from sources :
|
||||
- Grab the sources from http://curl.haxx.se/download.html
|
||||
- Decompress the archive
|
||||
- Open the folder with the extracted files
|
||||
- Run ./configure
|
||||
- Run make
|
||||
- Run sudo make install
|
||||
- Run sudo ldconfig
|
||||
|
||||
- cannot load such file -- readline:
|
||||
Run sudo aptitude install libreadline5-dev libncurses5-dev
|
||||
|
||||
Then, open the directory of the readline gem (you have to locate it)
|
||||
|
||||
cd ~/.rvm/src/ruby-1.9.2-p180/ext/readline
|
||||
ruby extconf.rb
|
||||
make
|
||||
make install
|
||||
|
||||
See http://vvv.tobiassjosten.net/ruby-on-rails/fixing-readline-for-the-ruby-on-rails-console/ for more details
|
||||
|
||||
- no such file to load -- rubygems
|
||||
Run update-alternatives --config ruby
|
||||
And select your ruby version
|
||||
|
||||
See https://github.com/wpscanteam/wpscan/issues/148
|
||||
|
||||
|
||||
==WPSCAN ARGUMENTS==
|
||||
|
||||
--update Update to the latest revision
|
||||
|
||||
--url | -u <target url> The WordPress URL/domain to scan.
|
||||
|
||||
--force | -f Forces WPScan to not check if the remote site is running WordPress.
|
||||
|
||||
--enumerate | -e [option(s)] Enumeration.
|
||||
option :
|
||||
u usernames from id 1 to 10
|
||||
u[10-20] usernames from id 10 to 20 (you must write [] chars)
|
||||
p plugins
|
||||
vp only vulnerable plugins
|
||||
ap all plugins (can take a long time)
|
||||
tt timthumbs
|
||||
t themes
|
||||
vp only vulnerable themes
|
||||
at all themes (can take a long time)
|
||||
Multiple values are allowed : '-e tt,p' will enumerate timthumbs and plugins
|
||||
If no option is supplied, the default is 'vt,tt,u,vp'
|
||||
|
||||
--exclude-content-based '<regexp or string>' Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied
|
||||
You do not need to provide the regexp delimiters, but you must write the quotes (simple or double)
|
||||
|
||||
--config-file | -c <config file> Use the specified config file
|
||||
|
||||
--follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not
|
||||
|
||||
--wp-content-dir <wp content dir> WPScan try to find the content directory (ie wp-content) by scanning the index page, however you can specified it. Subdirectories are allowed
|
||||
|
||||
--wp-plugins-dir <wp plugins dir> Same thing than --wp-content-dir but for the plugins directory. If not supplied, WPScan will use wp-content-dir/plugins. Subdirectories are allowed
|
||||
|
||||
--proxy <[protocol://]host:port> Supply a proxy (will override the one from conf/browser.conf.json).
|
||||
HTTP, SOCKS4 SOCKS4A and SOCKS5 are supported. If no protocol is given (format host:port), HTTP will be used
|
||||
|
||||
--proxy-auth <username:password> Supply the proxy login credentials (will override the one from conf/browser.conf.json).
|
||||
|
||||
--basic-auth <username:password> Set the HTTP Basic authentication
|
||||
|
||||
--wordlist | -w <wordlist> Supply a wordlist for the password bruter and do the brute.
|
||||
|
||||
--threads | -t <number of threads> The number of threads to use when multi-threading requests. (will override the value from conf/browser.conf.json)
|
||||
|
||||
--username | -U <username> Only brute force the supplied username.
|
||||
|
||||
--help | -h This help screen.
|
||||
|
||||
--verbose | -v Verbose output.
|
||||
|
||||
==WPSCAN EXAMPLES==
|
||||
|
||||
Do 'non-intrusive' checks...
|
||||
|
||||
ruby wpscan.rb --url www.example.com
|
||||
|
||||
Do wordlist password brute force on enumerated users using 50 threads...
|
||||
|
||||
ruby wpscan.rb --url www.example.com --wordlist darkc0de.lst --threads 50
|
||||
|
||||
Do wordlist password brute force on the 'admin' username only...
|
||||
|
||||
ruby wpscan.rb --url www.example.com --wordlist darkc0de.lst --username admin
|
||||
|
||||
Enumerate installed plugins...
|
||||
|
||||
ruby wpscan.rb --url www.example.com --enumerate p
|
||||
|
||||
Run all enumeration tools...
|
||||
|
||||
ruby wpscan.rb --url www.example.com --enumerate
|
||||
|
||||
Use custom content directory...
|
||||
|
||||
ruby wpscan.rb -u www.example.com --wp-content-dir custom-content
|
||||
|
||||
Update WPScan...
|
||||
|
||||
ruby wpscan.rb --update
|
||||
|
||||
Debug output...
|
||||
|
||||
ruby wpscan.rb --url www.example.com --debug-output 2>debug.log
|
||||
|
||||
==WPSTOOLS ARGUMENTS==
|
||||
|
||||
--help | -h This help screen.
|
||||
--Verbose | -v Verbose output.
|
||||
--update | -u Update to the latest revision.
|
||||
--generate_plugin_list [number of pages] Generate a new data/plugins.txt file. (supply number of *pages* to parse, default : 150)
|
||||
--gpl Alias for --generate_plugin_list
|
||||
--check-local-vulnerable-files | --clvf <local directory> Perform a recursive scan in the <local directory> to find vulnerable files or shells
|
||||
|
||||
==WPSTOOLS EXAMPLES==
|
||||
|
||||
- Generate a new 'most popular' plugin list, up to 150 pages ...
|
||||
ruby wpstools.rb --generate_plugin_list 150
|
||||
|
||||
- Locally scan a wordpress installation for vulnerable files or shells :
|
||||
ruby wpstools.rb --check-local-vulnerable-files /var/www/wordpress/
|
||||
|
||||
===PROJECT HOME===
|
||||
|
||||
www.wpscan.org
|
||||
|
||||
===REPOSITORY===
|
||||
|
||||
https://github.com/wpscanteam/wpscan
|
||||
|
||||
===ISSUES===
|
||||
|
||||
https://github.com/wpscanteam/wpscan/issues
|
||||
|
||||
===DEVELOPER DOCUMENTATION===
|
||||
|
||||
http://rdoc.info/github/wpscanteam/wpscan/frames
|
||||
|
||||
===SPONSOR===
|
||||
|
||||
WPScan is sponsored by the RandomStorm Open Source Initiative.
|
||||
|
||||
Visit RandomStorm at http://www.randomstorm.com
|
||||
339
README.md
339
README.md
@@ -1,104 +1,205 @@
|
||||

|
||||

|
||||
|
||||
[](https://travis-ci.org/wpscanteam/wpscan)
|
||||
|
||||
#### LICENSE
|
||||
[](https://travis-ci.org/wpscanteam/wpscan)
|
||||
[](https://codeclimate.com/github/wpscanteam/wpscan)
|
||||
[](https://gemnasium.com/wpscanteam/wpscan)
|
||||
[](https://hub.docker.com/r/wpscanteam/wpscan/)
|
||||
|
||||
WPScan - WordPress Security Scanner
|
||||
Copyright (C), 2011-2013 The WPScan Team
|
||||
# LICENSE
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
## WPScan Public Source License
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
The WPScan software (henceforth referred to simply as "WPScan") is dual-licensed - Copyright 2011-2016 WPScan Team.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
Cases that include commercialization of WPScan require a commercial, non-free license. Otherwise, WPScan can be used without charge under the terms set out below.
|
||||
|
||||
ryandewhurst at gmail
|
||||
### 1. Definitions
|
||||
|
||||
#### INSTALL
|
||||
1.1 "License" means this document.
|
||||
|
||||
1.2 "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns WPScan.
|
||||
|
||||
1.3 "WPScan Team" means WPScan’s core developers, an updated list of whom can be found within the CREDITS file.
|
||||
|
||||
### 2. Commercialization
|
||||
|
||||
A commercial use is one intended for commercial advantage or monetary compensation.
|
||||
|
||||
Example cases of commercialization are:
|
||||
|
||||
- Using WPScan to provide commercial managed/Software-as-a-Service services.
|
||||
- Distributing WPScan as a commercial product or as part of one.
|
||||
- Using WPScan as a value added service/product.
|
||||
|
||||
Example cases which do not require a commercial license, and thus fall under the terms set out below, include (but are not limited to):
|
||||
|
||||
- Penetration testers (or penetration testing organizations) using WPScan as part of their assessment toolkit.
|
||||
- Penetration Testing Linux Distributions including but not limited to Kali Linux, SamuraiWTF, BackBox Linux.
|
||||
- Using WPScan to test your own systems.
|
||||
- Any non-commercial use of WPScan.
|
||||
|
||||
If you need to purchase a commercial license or are unsure whether you need to purchase a commercial license contact us - team@wpscan.org.
|
||||
|
||||
We may grant commercial licenses at no monetary cost at our own discretion if the commercial usage is deemed by the WPScan Team to significantly benefit WPScan.
|
||||
|
||||
Free-use Terms and Conditions;
|
||||
|
||||
### 3. Redistribution
|
||||
|
||||
Redistribution is permitted under the following conditions:
|
||||
|
||||
- Unmodified License is provided with WPScan.
|
||||
- Unmodified Copyright notices are provided with WPScan.
|
||||
- Does not conflict with the commercialization clause.
|
||||
|
||||
### 4. Copying
|
||||
|
||||
Copying is permitted so long as it does not conflict with the Redistribution clause.
|
||||
|
||||
### 5. Modification
|
||||
|
||||
Modification is permitted so long as it does not conflict with the Redistribution clause.
|
||||
|
||||
### 6. Contributions
|
||||
|
||||
Any Contributions assume the Contributor grants the WPScan Team the unlimited, non-exclusive right to reuse, modify and relicense the Contributor's content.
|
||||
|
||||
### 7. Support
|
||||
|
||||
WPScan is provided under an AS-IS basis and without any support, updates or maintenance. Support, updates and maintenance may be given according to the sole discretion of the WPScan Team.
|
||||
|
||||
### 8. Disclaimer of Warranty
|
||||
|
||||
WPScan is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the WPScan is free of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||
|
||||
### 9. Limitation of Liability
|
||||
|
||||
To the extent permitted under Law, WPScan is provided under an AS-IS basis. The WPScan Team shall never, and without any limit, be liable for any damage, cost, expense or any other payment incurred as a result of WPScan's actions, failure, bugs and/or any other interaction between WPScan and end-equipment, computers, other software or any 3rd party, end-equipment, computer or services.
|
||||
|
||||
### 10. Disclaimer
|
||||
|
||||
Running WPScan against websites without prior mutual consent may be illegal in your country. The WPScan Team accept no liability and are not responsible for any misuse or damage caused by WPScan.
|
||||
|
||||
### 11. Trademark
|
||||
|
||||
The "wpscan" term is a registered trademark. This License does not grant the use of the "wpscan" trademark or the use of the WPScan logo.
|
||||
|
||||
# INSTALL
|
||||
|
||||
WPScan comes pre-installed on the following Linux distributions:
|
||||
|
||||
- [BackBox Linux](http://www.backbox.org/)
|
||||
- [BackTrack Linux](http://www.backtrack-linux.org/)
|
||||
- [Kali Linux](http://www.kali.org/)
|
||||
- [Pentoo](http://www.pentoo.ch/)
|
||||
- [SamuraiWTF](http://samurai.inguardians.com/)
|
||||
- [BlackArch](http://blackarch.org/)
|
||||
|
||||
Prerequisites:
|
||||
On macOS WPScan is packaged by [Homebrew](https://brew.sh/) as [`wpscan`](http://braumeister.org/formula/wpscan).
|
||||
|
||||
- Windows not supported
|
||||
- Ruby >= 1.9.2 - Recommended: 1.9.3
|
||||
Windows is not supported
|
||||
|
||||
We suggest you use our official Docker image from https://hub.docker.com/r/wpscanteam/wpscan/ to avoid installation problems.
|
||||
|
||||
# DOCKER
|
||||
Pull the repo with `docker pull wpscanteam/wpscan`
|
||||
|
||||
## Start WPScan
|
||||
|
||||
```
|
||||
docker run -it --rm wpscanteam/wpscan -u https://yourblog.com [options]
|
||||
```
|
||||
|
||||
For the available Options, please see https://github.com/wpscanteam/wpscan#wpscan-arguments
|
||||
|
||||
If you run the git version of wpscan we included some binstubs in ./bin for easier start of wpscan.
|
||||
|
||||
## Examples
|
||||
|
||||
Mount a local wordlist to the docker container and start a bruteforce attack for user admin
|
||||
|
||||
```
|
||||
docker run -it --rm -v ~/wordlists:/wordlists wpscanteam/wpscan --url https://yourblog.com --wordlist /wordlists/crackstation.txt --username admin
|
||||
```
|
||||
|
||||
Use logfile option
|
||||
```
|
||||
# the file must exist prior to starting the container, otherwise docker will create a directory with the filename
|
||||
touch ~/FILENAME
|
||||
docker run -it --rm -v ~/FILENAME:/wpscan/output.txt wpscanteam/wpscan --url https://yourblog.com --log /wpscan/output.txt
|
||||
```
|
||||
|
||||
(This mounts the host directory `~/wordlists` to the container in the path `/wordlists`)
|
||||
|
||||
Published on https://hub.docker.com/r/wpscanteam/wpscan/
|
||||
|
||||
# Manual install
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Ruby >= 2.1.9 - Recommended: 2.4.1
|
||||
- Curl >= 7.21 - Recommended: latest - FYI the 7.29 has a segfault
|
||||
- RubyGems - Recommended: latest
|
||||
- Git
|
||||
|
||||
*Installing on Debian/Ubuntu:*
|
||||
### Installing dependencies on Ubuntu
|
||||
|
||||
```sudo apt-get install libcurl4-gnutls-dev libopenssl-ruby libxml2 libxml2-dev libxslt1-dev ruby-dev```
|
||||
sudo apt-get install libcurl4-openssl-dev libxml2 libxml2-dev libxslt1-dev ruby-dev build-essential libgmp-dev zlib1g-dev
|
||||
|
||||
```git clone https://github.com/wpscanteam/wpscan.git```
|
||||
### Installing dependencies on Debian
|
||||
|
||||
```cd wpscan```
|
||||
sudo apt-get install gcc git ruby ruby-dev libcurl4-openssl-dev make zlib1g-dev
|
||||
|
||||
```sudo gem install bundler && bundle install --without test```
|
||||
### Installing dependencies on Fedora
|
||||
|
||||
*Installing on Fedora:*
|
||||
sudo dnf install gcc ruby-devel libxml2 libxml2-devel libxslt libxslt-devel libcurl-devel patch rpm-build
|
||||
|
||||
```sudo yum install gcc ruby-devel libxml2 libxml2-devel libxslt libxslt-devel libcurl-devel```
|
||||
### Installing dependencies on Arch Linux
|
||||
|
||||
```git clone https://github.com/wpscanteam/wpscan.git```
|
||||
pacman -Syu ruby
|
||||
pacman -Syu libyaml
|
||||
|
||||
```cd wpscan```
|
||||
### Installing dependencies on macOS
|
||||
|
||||
```sudo gem install bundler && bundle install --without test```
|
||||
Apple Xcode, Command Line Tools and the libffi are needed (to be able to install the FFI gem), See [http://stackoverflow.com/questions/17775115/cant-setup-ruby-environment-installing-fii-gem-error](http://stackoverflow.com/questions/17775115/cant-setup-ruby-environment-installing-fii-gem-error)
|
||||
|
||||
*Installing on Archlinux:*
|
||||
## Installing with RVM (recommended when doing a manual install)
|
||||
|
||||
```pacman -Syu ruby```
|
||||
If you are using GNOME Terminal, there are some steps required before executing the commands. See here for more information:
|
||||
https://rvm.io/integration/gnome-terminal#integrating-rvm-with-gnome-terminal
|
||||
|
||||
```pacman -Syu libyaml```
|
||||
# Install all prerequisites for your OS (look above)
|
||||
cd ~
|
||||
curl -sSL https://rvm.io/mpapis.asc | gpg --import -
|
||||
curl -sSL https://get.rvm.io | bash -s stable
|
||||
source ~/.rvm/scripts/rvm
|
||||
echo "source ~/.rvm/scripts/rvm" >> ~/.bashrc
|
||||
rvm install 2.4.1
|
||||
rvm use 2.4.1 --default
|
||||
echo "gem: --no-ri --no-rdoc" > ~/.gemrc
|
||||
git clone https://github.com/wpscanteam/wpscan.git
|
||||
cd wpscan
|
||||
gem install bundler
|
||||
bundle install --without test
|
||||
|
||||
```git clone https://github.com/wpscanteam/wpscan.git```
|
||||
## Installing manually (not recommended)
|
||||
|
||||
```cd wpscan```
|
||||
git clone https://github.com/wpscanteam/wpscan.git
|
||||
cd wpscan
|
||||
sudo gem install bundler && bundle install --without test
|
||||
|
||||
```sudo gem install bundler && bundle install --without test```
|
||||
|
||||
```gem install typhoeus```
|
||||
|
||||
```gem install nokogiri```
|
||||
|
||||
*Installing on Mac OSX:*
|
||||
|
||||
Apple Xcode, Command Line Tools and the libffi are needed (to be able to install the FFI gem), See http://stackoverflow.com/questions/17775115/cant-setup-ruby-environment-installing-fii-gem-error
|
||||
|
||||
```git clone https://github.com/wpscanteam/wpscan.git```
|
||||
|
||||
```cd wpscan```
|
||||
|
||||
```sudo gem install bundler && bundle install --without test```
|
||||
|
||||
#### KNOWN ISSUES
|
||||
# KNOWN ISSUES
|
||||
|
||||
- Typhoeus segmentation fault
|
||||
|
||||
Update cURL to version => 7.21 (may have to install from source)
|
||||
See http://code.google.com/p/wpscan/issues/detail?id=81
|
||||
|
||||
- Proxy not working
|
||||
|
||||
Update cURL to version => 7.21.7 (may have to install from source).
|
||||
|
||||
Installation from sources :
|
||||
```
|
||||
|
||||
Grab the sources from http://curl.haxx.se/download.html
|
||||
Decompress the archive
|
||||
Open the folder with the extracted files
|
||||
@@ -106,21 +207,21 @@ Apple Xcode, Command Line Tools and the libffi are needed (to be able to install
|
||||
Run make
|
||||
Run sudo make install
|
||||
Run sudo ldconfig
|
||||
```
|
||||
|
||||
|
||||
- cannot load such file -- readline:
|
||||
|
||||
```sudo aptitude install libreadline5-dev libncurses5-dev```
|
||||
sudo aptitude install libreadline5-dev libncurses5-dev
|
||||
|
||||
Then, open the directory of the readline gem (you have to locate it)
|
||||
```
|
||||
cd ~/.rvm/src/ruby-1.9.2-p180/ext/readline
|
||||
|
||||
cd ~/.rvm/src/ruby-XXXX/ext/readline
|
||||
ruby extconf.rb
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
See http://vvv.tobiassjosten.net/ruby-on-rails/fixing-readline-for-the-ruby-on-rails-console/ for more details
|
||||
|
||||
See [http://vvv.tobiassjosten.net/ruby-on-rails/fixing-readline-for-the-ruby-on-rails-console/](http://vvv.tobiassjosten.net/ruby-on-rails/fixing-readline-for-the-ruby-on-rails-console/) for more details
|
||||
|
||||
- no such file to load -- rubygems
|
||||
|
||||
@@ -128,16 +229,13 @@ Apple Xcode, Command Line Tools and the libffi are needed (to be able to install
|
||||
|
||||
And select your ruby version
|
||||
|
||||
See https://github.com/wpscanteam/wpscan/issues/148
|
||||
See [https://github.com/wpscanteam/wpscan/issues/148](https://github.com/wpscanteam/wpscan/issues/148)
|
||||
|
||||
#### WPSCAN ARGUMENTS
|
||||
|
||||
--update Update to the latest revision
|
||||
# WPSCAN ARGUMENTS
|
||||
|
||||
--update Update the database to the latest version.
|
||||
--url | -u <target url> The WordPress URL/domain to scan.
|
||||
|
||||
--force | -f Forces WPScan to not check if the remote site is running WordPress.
|
||||
|
||||
--enumerate | -e [option(s)] Enumeration.
|
||||
option :
|
||||
u usernames from id 1 to 10
|
||||
@@ -149,38 +247,48 @@ Apple Xcode, Command Line Tools and the libffi are needed (to be able to install
|
||||
t themes
|
||||
vt only vulnerable themes
|
||||
at all themes (can take a long time)
|
||||
Multiple values are allowed : '-e tt,p' will enumerate timthumbs and plugins
|
||||
If no option is supplied, the default is 'vt,tt,u,vp'
|
||||
|
||||
--exclude-content-based '<regexp or string>' Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied
|
||||
You do not need to provide the regexp delimiters, but you must write the quotes (simple or double)
|
||||
|
||||
--config-file | -c <config file> Use the specified config file
|
||||
Multiple values are allowed : "-e tt,p" will enumerate timthumbs and plugins
|
||||
If no option is supplied, the default is "vt,tt,u,vp"
|
||||
|
||||
--exclude-content-based "<regexp or string>"
|
||||
Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied.
|
||||
You do not need to provide the regexp delimiters, but you must write the quotes (simple or double).
|
||||
--config-file | -c <config file> Use the specified config file, see the example.conf.json.
|
||||
--user-agent | -a <User-Agent> Use the specified User-Agent.
|
||||
--cookie <string> String to read cookies from.
|
||||
--random-agent | -r Use a random User-Agent.
|
||||
--follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not
|
||||
|
||||
--wp-content-dir <wp content dir> WPScan try to find the content directory (ie wp-content) by scanning the index page, however you can specified it. Subdirectories are allowed
|
||||
|
||||
--wp-plugins-dir <wp plugins dir> Same thing than --wp-content-dir but for the plugins directory. If not supplied, WPScan will use wp-content-dir/plugins. Subdirectories are allowed
|
||||
|
||||
--proxy <[protocol://]host:port> Supply a proxy (will override the one from conf/browser.conf.json).
|
||||
HTTP, SOCKS4 SOCKS4A and SOCKS5 are supported. If no protocol is given (format host:port), HTTP will be used
|
||||
|
||||
--proxy-auth <username:password> Supply the proxy login credentials (will override the one from conf/browser.conf.json).
|
||||
|
||||
--basic-auth <username:password> Set the HTTP Basic authentication
|
||||
|
||||
--wordlist | -w <wordlist> Supply a wordlist for the password bruter and do the brute.
|
||||
|
||||
--threads | -t <number of threads> The number of threads to use when multi-threading requests. (will override the value from conf/browser.conf.json)
|
||||
|
||||
--batch Never ask for user input, use the default behaviour.
|
||||
--no-color Do not use colors in the output.
|
||||
--log [filename] Creates a log.txt file with WPScan's output if no filename is supplied. Otherwise the filename is used for logging.
|
||||
--no-banner Prevents the WPScan banner from being displayed.
|
||||
--disable-accept-header Prevents WPScan sending the Accept HTTP header.
|
||||
--disable-referer Prevents setting the Referer header.
|
||||
--disable-tls-checks Disables SSL/TLS certificate verification.
|
||||
--wp-content-dir <wp content dir> WPScan try to find the content directory (ie wp-content) by scanning the index page, however you can specify it.
|
||||
Subdirectories are allowed.
|
||||
--wp-plugins-dir <wp plugins dir> Same thing than --wp-content-dir but for the plugins directory.
|
||||
If not supplied, WPScan will use wp-content-dir/plugins. Subdirectories are allowed
|
||||
--proxy <[protocol://]host:port> Supply a proxy. HTTP, SOCKS4 SOCKS4A and SOCKS5 are supported.
|
||||
If no protocol is given (format host:port), HTTP will be used.
|
||||
--proxy-auth <username:password> Supply the proxy login credentials.
|
||||
--basic-auth <username:password> Set the HTTP Basic authentication.
|
||||
--wordlist | -w <wordlist> Supply a wordlist for the password brute forcer.
|
||||
If the "-" option is supplied, the wordlist is expected via STDIN.
|
||||
--username | -U <username> Only brute force the supplied username.
|
||||
|
||||
--usernames <path-to-file> Only brute force the usernames from the file.
|
||||
--cache-dir <cache-directory> Set the cache directory.
|
||||
--cache-ttl <cache-ttl> Typhoeus cache TTL.
|
||||
--request-timeout <request-timeout> Request Timeout.
|
||||
--connect-timeout <connect-timeout> Connect Timeout.
|
||||
--threads | -t <number of threads> The number of threads to use when multi-threading requests.
|
||||
--max-threads <max-threads> Maximum Threads.
|
||||
--throttle <milliseconds> Milliseconds to wait before doing another web request. If used, the --threads should be set to 1.
|
||||
--help | -h This help screen.
|
||||
|
||||
--verbose | -v Verbose output.
|
||||
--version Output the current version and exit.
|
||||
|
||||
#### WPSCAN EXAMPLES
|
||||
# WPSCAN EXAMPLES
|
||||
|
||||
Do 'non-intrusive' checks...
|
||||
|
||||
@@ -190,6 +298,10 @@ Do wordlist password brute force on enumerated users using 50 threads...
|
||||
|
||||
```ruby wpscan.rb --url www.example.com --wordlist darkc0de.lst --threads 50```
|
||||
|
||||
Do wordlist password brute force on enumerated users using STDIN as the wordlist...
|
||||
|
||||
```crunch 5 13 -f charset.lst mixalpha | ruby wpscan.rb --url www.example.com --wordlist -```
|
||||
|
||||
Do wordlist password brute force on the 'admin' username only...
|
||||
|
||||
```ruby wpscan.rb --url www.example.com --wordlist darkc0de.lst --username admin```
|
||||
@@ -206,7 +318,7 @@ Use custom content directory...
|
||||
|
||||
```ruby wpscan.rb -u www.example.com --wp-content-dir custom-content```
|
||||
|
||||
Update WPScan...
|
||||
Update WPScan's databases...
|
||||
|
||||
```ruby wpscan.rb --update```
|
||||
|
||||
@@ -214,41 +326,22 @@ Debug output...
|
||||
|
||||
```ruby wpscan.rb --url www.example.com --debug-output 2>debug.log```
|
||||
|
||||
#### WPSTOOLS ARGUMENTS
|
||||
# PROJECT HOME
|
||||
|
||||
--help | -h This help screen.
|
||||
--Verbose | -v Verbose output.
|
||||
--update | -u Update to the latest revision.
|
||||
--generate_plugin_list [number of pages] Generate a new data/plugins.txt file. (supply number of *pages* to parse, default : 150)
|
||||
--gpl Alias for --generate_plugin_list
|
||||
--check-local-vulnerable-files | --clvf <local directory> Perform a recursive scan in the <local directory> to find vulnerable files or shells
|
||||
[http://www.wpscan.org](http://www.wpscan.org)
|
||||
|
||||
#### WPSTOOLS EXAMPLES
|
||||
# VULNERABILITY DATABASE
|
||||
|
||||
Generate a new 'most popular' plugin list, up to 150 pages...
|
||||
[https://wpvulndb.com](https://wpvulndb.com)
|
||||
|
||||
```ruby wpstools.rb --generate_plugin_list 150```
|
||||
# GIT REPOSITORY
|
||||
|
||||
Locally scan a wordpress installation for vulnerable files or shells :
|
||||
```ruby wpstools.rb --check-local-vulnerable-files /var/www/wordpress/```
|
||||
[https://github.com/wpscanteam/wpscan](https://github.com/wpscanteam/wpscan)
|
||||
|
||||
# ISSUES
|
||||
|
||||
#### PROJECT HOME
|
||||
[https://github.com/wpscanteam/wpscan/issues](https://github.com/wpscanteam/wpscan/issues)
|
||||
|
||||
www.wpscan.org
|
||||
# DEVELOPER DOCUMENTATION
|
||||
|
||||
#### GIT REPOSITORY
|
||||
|
||||
https://github.com/wpscanteam/wpscan
|
||||
|
||||
#### ISSUES
|
||||
|
||||
https://github.com/wpscanteam/wpscan/issues
|
||||
|
||||
#### DEVELOPER DOCUMENTATION
|
||||
|
||||
http://rdoc.info/github/wpscanteam/wpscan/frames
|
||||
|
||||
#### SPONSOR
|
||||
|
||||
WPScan is sponsored by the [RandomStorm](http://www.randomstorm.com) Open Source Initiative.
|
||||
[http://rdoc.info/github/wpscanteam/wpscan/frames](http://rdoc.info/github/wpscanteam/wpscan/frames)
|
||||
|
||||
21
bin/rspec
Executable file
21
bin/rspec
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
|
||||
cd $DIR/../
|
||||
# always rebuild and include all GEMs
|
||||
docker build --build-arg "BUNDLER_ARGS=--jobs=8" -t wpscan:rspec .
|
||||
# update all gems (this updates Gemfile.lock on the host)
|
||||
# this also needs some build dependencies
|
||||
docker run --rm -u root -v $DIR/../Gemfile.lock:/wpscan/Gemfile.lock --entrypoint "" wpscan:rspec sh -c 'apk add --no-cache alpine-sdk ruby-dev libffi-dev zlib-dev && bundle update'
|
||||
# rebuild image with latest GEMs
|
||||
docker build --build-arg "BUNDLER_ARGS=--jobs=8" -t wpscan:rspec .
|
||||
# run spec
|
||||
docker run --rm -v $DIR/../:/wpscan --entrypoint "" wpscan:rspec rspec
|
||||
|
||||
12
bin/update_gems
Executable file
12
bin/update_gems
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
|
||||
cd $DIR/../
|
||||
docker run -it --rm -v "$DIR/../":/wpscan -w /wpscan ruby:2.4 bundle update
|
||||
14
bin/wpscan
Executable file
14
bin/wpscan
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
|
||||
cd $DIR/../
|
||||
docker build -q -t wpscan:git .
|
||||
docker run -it --rm wpscan:git "$@"
|
||||
|
||||
16
bin/wpscan-dev
Executable file
16
bin/wpscan-dev
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
|
||||
cd $DIR/../
|
||||
if [[ -n "$WPSCAN_BUILD" ]]; then
|
||||
docker build -q -t wpscan:git .
|
||||
fi
|
||||
docker run -it --rm -v $DIR/../:/wpscan wpscan:git "$@"
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
{
|
||||
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0",
|
||||
/* Modes :
|
||||
static : will use the defined user_agent for each request
|
||||
semi-static : will randomly choose a user agent into available_user_agents before each scan
|
||||
random : each request will choose a random user agent in available_user_agents
|
||||
*/
|
||||
"user_agent_mode": "static",
|
||||
|
||||
/* Uncomment the "proxy" line to use the proxy
|
||||
SOCKS proxies (4, 4A, 5) are supported, ie : "proxy": "socks5://127.0.0.1:9000"
|
||||
If you do not specify the protocol, http will be used
|
||||
*/
|
||||
//"proxy": "127.0.0.1:3128",
|
||||
//"proxy_auth": "username:password",
|
||||
|
||||
"cache_ttl": 600, // 10 minutes, at this time the cache is cleaned before each scan. If this value is set to 0, the cache will be disabled
|
||||
|
||||
"request_timeout": 2000, // 2s
|
||||
|
||||
"connect_timeout": 1000, // 1s
|
||||
|
||||
"max_threads": 20,
|
||||
|
||||
// Some user_agents can be found there http://techpatterns.com/downloads/firefox/useragentswitcher.xml (thx to Gianluca Brindisi)
|
||||
"available_user_agents":
|
||||
[
|
||||
// Windows
|
||||
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5",
|
||||
"Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.601.0 Safari/534.14",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1",
|
||||
"Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0E)",
|
||||
"Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1",
|
||||
"Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20120403211507 Firefox/12.0",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20120427 Firefox/15.0a1",
|
||||
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)",
|
||||
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)",
|
||||
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/6.0)",
|
||||
"Opera/9.80 (Windows NT 6.1; U; es-ES) Presto/2.9.181 Version/12.00",
|
||||
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5",
|
||||
|
||||
// MAC
|
||||
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.15 Safari/534.13",
|
||||
"Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
|
||||
"Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.8 (KHTML, like Gecko) Safari/419.3",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2; rv:10.0.1) Gecko/20100101 Firefox/10.0.1",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10",
|
||||
|
||||
// Linux
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.20 Safari/535.1",
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Ubuntu/10.10 Chromium/12.0.703.0 Chrome/12.0.703.0 Safari/534.24",
|
||||
"Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.9) Gecko/20100915 Gentoo Firefox/3.6.9",
|
||||
"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.16) Gecko/20120421 Gecko Firefox/11.0",
|
||||
"Mozilla/5.0 (X11; Linux i686; rv:12.0) Gecko/20100101 Firefox/12.0",
|
||||
"Opera/9.80 (X11; Linux x86_64; U; pl) Presto/2.7.62 Version/11.00",
|
||||
"Mozilla/5.0 (X11; U; Linux x86_64; us; rv:1.9.1.19) Gecko/20110430 shadowfox/7.0 (like Firefox/7.0"
|
||||
]
|
||||
}
|
||||
2
data/.gitignore
vendored
Normal file
2
data/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Only he following extensions are scanned : js, php, swf, html, htm
|
||||
If you want to add one, modify the variable file_extension_to_scan, line 191 in wpstools.rb
|
||||
-->
|
||||
|
||||
<hashes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="local_vulnerable_files.xsd">
|
||||
|
||||
<hash sha1="17c372678aafb3bc1a7b37320b5cc1d8af433527">
|
||||
<title>XSS in swfupload.swf</title>
|
||||
<file>swfupload.swf</file>
|
||||
<reference>http://brindi.si/g/blog/vulnerable-swf-bundled-in-wordpress-plugins.html</reference>
|
||||
</hash>
|
||||
|
||||
<hash sha1="775dc1089829ef07838406def28a4d8bfef69d66">
|
||||
<title>Arbitrary File Upload Vulnerability</title>
|
||||
<file>php.php</file>
|
||||
<reference>http://packetstormsecurity.com/files/119241/wpvalums-shell.txt</reference>
|
||||
</hash>
|
||||
|
||||
<!-- This one a is the same as above, but the postSize verification has been removed -->
|
||||
<hash sha1="5e8f0d5a917d2937318a9bafd0529135bd473e70">
|
||||
<title>Arbitrary File Upload Vulnerability</title>
|
||||
<file>php.php</file>
|
||||
<reference>http://packetstormsecurity.com/files/119218/wpreflexgallery-shell.txt</reference>
|
||||
</hash>
|
||||
|
||||
<hash sha1="3f9ad05b05b65ee2b6efa1373f708293dd2005c7">
|
||||
<title>Arbitrary File Upload Vulnerability</title>
|
||||
<file>uploadify.php</file>
|
||||
<reference>http://packetstormsecurity.com/files/119219/wpuploader104-shell.txt</reference>
|
||||
</hash>
|
||||
|
||||
<hash sha1="ac638cc38f011b74a8d9a4e7d3d60358e472166c">
|
||||
<title>Inline phpinfo()</title>
|
||||
<file>phpinfo.php</file>
|
||||
<reference>http://php.net/manual/en/function.phpinfo.php</reference>
|
||||
</hash>
|
||||
|
||||
<hash sha1="012ee25cceff745e681fbb3697a06f3712f55554">
|
||||
<title>phpinfo()</title>
|
||||
<file>phpinfo.php</file>
|
||||
<reference>http://php.net/manual/en/function.phpinfo.php</reference>
|
||||
</hash>
|
||||
|
||||
</hashes>
|
||||
@@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<xs:simpleType name="stringtype">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="uritype">
|
||||
<xs:restriction base="xs:anyURI">
|
||||
<xs:minLength value="1" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="sha1type">
|
||||
<xs:restriction base="stringtype">
|
||||
<xs:pattern value="[0-9a-f]{40}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="hashtype">
|
||||
<xs:sequence minOccurs="1" maxOccurs="1">
|
||||
<xs:element name="title" type="stringtype"/>
|
||||
<xs:element name="file" type="stringtype"/>
|
||||
<xs:element name="reference" type="uritype"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute type="sha1type" name="sha1" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="hashes">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="hash" type="hashtype" maxOccurs="unbounded" minOccurs="1"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
</xs:schema>
|
||||
@@ -1,3 +0,0 @@
|
||||
http://.*\.rr\.nu
|
||||
http://www\.thesea\.org/media\.php
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
2205
data/plugins.txt
2205
data/plugins.txt
File diff suppressed because it is too large
Load Diff
38946
data/plugins_full.txt
38946
data/plugins_full.txt
File diff suppressed because it is too large
Load Diff
2067
data/theme_vulns.xml
2067
data/theme_vulns.xml
File diff suppressed because it is too large
Load Diff
300
data/themes.txt
300
data/themes.txt
@@ -1,300 +0,0 @@
|
||||
2013-black-and-white
|
||||
academica
|
||||
accessible-zen
|
||||
adamos
|
||||
adelle
|
||||
admired
|
||||
adventure
|
||||
adventure-journal
|
||||
aldehyde
|
||||
alexandria
|
||||
alhena-lite
|
||||
analytical-lite
|
||||
andrina-lite
|
||||
annotum-base
|
||||
ascetica
|
||||
aspen
|
||||
atahualpa
|
||||
atheros
|
||||
attitude
|
||||
attorney
|
||||
autofocus
|
||||
beach
|
||||
birdsite
|
||||
birdtips
|
||||
biznez-lite
|
||||
bizstudio-lite
|
||||
bizway
|
||||
black-rider
|
||||
blackbird
|
||||
blain
|
||||
blankslate
|
||||
blogbox
|
||||
blogolife
|
||||
bold-headline
|
||||
boldr-lite
|
||||
book-lite
|
||||
boot-store
|
||||
bota
|
||||
bouquet
|
||||
bresponzive
|
||||
bueno
|
||||
business-lite
|
||||
busiprof
|
||||
buzz
|
||||
careta
|
||||
carton
|
||||
catch-box
|
||||
catch-everest
|
||||
catch-evolution
|
||||
cazuela
|
||||
celebrate
|
||||
celestial-lite
|
||||
central
|
||||
chaostheory
|
||||
cherry-blossom
|
||||
childishly-simple
|
||||
church
|
||||
clean-black
|
||||
clean-retina
|
||||
coller
|
||||
colorway
|
||||
contango
|
||||
coraline
|
||||
corpo
|
||||
custom-community
|
||||
customizr
|
||||
cyberchimps
|
||||
cycnus
|
||||
d5-business-line
|
||||
d5-design
|
||||
d5-socialia
|
||||
dailypost
|
||||
decode
|
||||
delicate
|
||||
delighted
|
||||
designfolio
|
||||
destro
|
||||
deux-milles-douze
|
||||
discover
|
||||
dms
|
||||
duena
|
||||
dusk-to-dawn
|
||||
duster
|
||||
dw-minion
|
||||
easel
|
||||
eclipse
|
||||
elegantwhite
|
||||
emphaino
|
||||
encounters-lite
|
||||
engrave-lite
|
||||
epic
|
||||
esplanade
|
||||
espressionista
|
||||
esquire
|
||||
estate
|
||||
evolve
|
||||
expound
|
||||
fashionistas
|
||||
fine
|
||||
firmasite
|
||||
fluxipress
|
||||
focus
|
||||
forever
|
||||
frisco-for-buddypress
|
||||
frontier
|
||||
fruitful
|
||||
futuristica
|
||||
gamepress
|
||||
golden-eagle-lite
|
||||
graphene
|
||||
greenpage
|
||||
gridiculous
|
||||
gridster-lite
|
||||
hannari
|
||||
hatch
|
||||
hazen
|
||||
heatmap-adaptive
|
||||
hero
|
||||
hiero
|
||||
highwind
|
||||
hostmarks
|
||||
houston
|
||||
hro
|
||||
hybrid
|
||||
iconic-one
|
||||
icy
|
||||
ifeature
|
||||
imag-mag
|
||||
impressio-lite
|
||||
impulse
|
||||
infoway
|
||||
innovative
|
||||
intuition
|
||||
irex-lite
|
||||
iribbon
|
||||
kabbo
|
||||
klasik
|
||||
koenda
|
||||
lamya
|
||||
landscape
|
||||
leaf
|
||||
litesta
|
||||
lobster
|
||||
local-business
|
||||
lugada
|
||||
luminescence-lite
|
||||
magazine
|
||||
magazine-basic
|
||||
magazine-style
|
||||
magazino
|
||||
manchester
|
||||
mantra
|
||||
marla
|
||||
max-magazine
|
||||
melany
|
||||
mh-magazine-lite
|
||||
minimatica
|
||||
minimize
|
||||
mixfolio
|
||||
modern-estate
|
||||
mon-cahier
|
||||
montezuma
|
||||
multipurpose
|
||||
my-depressive
|
||||
my-world-with-grass-and-dew
|
||||
mystique
|
||||
narga
|
||||
neuro
|
||||
newp
|
||||
next-saturday
|
||||
omega
|
||||
openstrap
|
||||
opulus-sombre
|
||||
origami
|
||||
origin
|
||||
oxygen
|
||||
p2
|
||||
p2-categories
|
||||
pagelines
|
||||
parabola
|
||||
parament
|
||||
path
|
||||
phonix
|
||||
photographic
|
||||
photolistic
|
||||
photologger
|
||||
pilcrow
|
||||
pilot-fish
|
||||
pinbin
|
||||
pinboard
|
||||
pink-touch-2
|
||||
pitch
|
||||
platform
|
||||
point
|
||||
portfolio-press
|
||||
pr-news
|
||||
prana
|
||||
preference-lite
|
||||
quark
|
||||
r2d2
|
||||
raindrops
|
||||
raptor
|
||||
raven
|
||||
response
|
||||
responsive
|
||||
restaurateur
|
||||
retro
|
||||
road-fighter
|
||||
ryu
|
||||
sampression-lite
|
||||
sensitive
|
||||
serene
|
||||
shprink-one
|
||||
silverclean-lite
|
||||
simple-and-clean
|
||||
simple-catch
|
||||
simpleo
|
||||
simplicity-lite
|
||||
simplify
|
||||
sixteen
|
||||
sliding-door
|
||||
small-business
|
||||
snaps
|
||||
snapshot
|
||||
snowblind
|
||||
socially-awkward
|
||||
spartan
|
||||
spasalon
|
||||
spine
|
||||
spun
|
||||
squirrel
|
||||
startupwp
|
||||
steira
|
||||
strapvert
|
||||
striker
|
||||
suevafree
|
||||
suffusion
|
||||
suits
|
||||
sukelius-magazine
|
||||
sundance
|
||||
sunny-blue-sky
|
||||
sunspot
|
||||
supernova
|
||||
surfarama
|
||||
sweet-tech
|
||||
swift-basic
|
||||
tampa
|
||||
target
|
||||
teal
|
||||
terrifico
|
||||
tesla
|
||||
the-bootstrap
|
||||
thematic
|
||||
themia-lite
|
||||
theron-lite
|
||||
timeturner
|
||||
tiny-forge
|
||||
tonic
|
||||
toolbox
|
||||
travel-blogger
|
||||
travelify
|
||||
tribbiani
|
||||
twentyeleven
|
||||
twentyten
|
||||
twentythirteen
|
||||
twentytwelve
|
||||
unique
|
||||
untitled
|
||||
uptown
|
||||
vantage
|
||||
viper
|
||||
virtue
|
||||
visitpress
|
||||
visual
|
||||
vortex
|
||||
voyage
|
||||
ward
|
||||
weaver-ii
|
||||
wordpost
|
||||
wp-creativix
|
||||
wp-flatthirteen
|
||||
wp-knowledge-base
|
||||
wp-opulus
|
||||
xin-magazine
|
||||
yoko
|
||||
zalive
|
||||
zbench
|
||||
zeebizzcard
|
||||
zeebusiness
|
||||
zeedynamic
|
||||
zeeflow
|
||||
zeefocus
|
||||
zeemagazine
|
||||
zeeminty
|
||||
zeenews
|
||||
zeenoble
|
||||
zeestyle
|
||||
zeesynergie
|
||||
zeetasty
|
||||
zenon-lite
|
||||
7549
data/themes_full.txt
7549
data/themes_full.txt
File diff suppressed because it is too large
Load Diff
2459
data/timthumbs.txt
2459
data/timthumbs.txt
File diff suppressed because it is too large
Load Diff
106
data/vuln.xsd
106
data/vuln.xsd
@@ -1,106 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<xs:simpleType name="stringtype">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="inttype">
|
||||
<xs:restriction base="xs:positiveInteger" />
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="uritype">
|
||||
<xs:restriction base="xs:anyURI">
|
||||
<xs:minLength value="1" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="cvetype">
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:pattern value="[0-9]{4}-[0-9]{4,}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="typetype">
|
||||
<xs:restriction base="stringtype">
|
||||
<xs:enumeration value="SQLI"/>
|
||||
<xs:enumeration value="MULTI"/>
|
||||
<xs:enumeration value="REDIRECT"/>
|
||||
<xs:enumeration value="RCE"/>
|
||||
<xs:enumeration value="RFI"/>
|
||||
<xs:enumeration value="LFI"/>
|
||||
<xs:enumeration value="UPLOAD"/>
|
||||
<xs:enumeration value="UNKNOWN"/>
|
||||
<xs:enumeration value="XSS"/>
|
||||
<xs:enumeration value="CSRF"/>
|
||||
<xs:enumeration value="SSRF"/>
|
||||
<xs:enumeration value="AUTHBYPASS"/>
|
||||
<xs:enumeration value="FPD"/>
|
||||
<xs:enumeration value="XXE"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="itemtype">
|
||||
<xs:sequence minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:element name="vulnerability" type="vulntype" />
|
||||
</xs:sequence>
|
||||
<xs:attribute type="stringtype" name="name" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="wordpresstype">
|
||||
<xs:sequence minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:element name="vulnerability" type="vulntype"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute type="stringtype" name="version" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="vulntype">
|
||||
<xs:sequence minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:choice>
|
||||
<xs:element name="title" type="stringtype"/>
|
||||
<xs:element name="type" type="typetype"/>
|
||||
<xs:element name="fixed_in" type="stringtype"/>
|
||||
<xs:element name="references" type="referencetype"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="referencetype">
|
||||
<xs:sequence minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:choice>
|
||||
<xs:element name="url" type="uritype" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="cve" type="cvetype" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="secunia" type="inttype" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="osvdb" type="inttype" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="metasploit" type="stringtype" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="exploitdb" type="inttype" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="vulnerabilities">
|
||||
<xs:complexType>
|
||||
<xs:choice>
|
||||
<xs:element name="plugin" type="itemtype" maxOccurs="unbounded" minOccurs="0"/>
|
||||
<xs:element name="theme" type="itemtype" maxOccurs="unbounded" minOccurs="0"/>
|
||||
<xs:element name="wordpress" type="wordpresstype" maxOccurs="unbounded" minOccurs="0"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
<xs:unique name="uniquePlugin">
|
||||
<xs:selector xpath="plugin"/>
|
||||
<xs:field xpath="@name"/>
|
||||
</xs:unique>
|
||||
<xs:unique name="uniqueTheme">
|
||||
<xs:selector xpath="theme"/>
|
||||
<xs:field xpath="@name"/>
|
||||
</xs:unique>
|
||||
<xs:unique name="uniqueWordpress">
|
||||
<xs:selector xpath="wordpress"/>
|
||||
<xs:field xpath="@version"/>
|
||||
</xs:unique>
|
||||
</xs:element>
|
||||
|
||||
</xs:schema>
|
||||
@@ -1,223 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
This file contains identification data to identify WordPress versions.
|
||||
http://wordpress.org/download/release-archive/
|
||||
|
||||
Position is important, DO NOT change anything unless you know what you are doing :p
|
||||
-->
|
||||
|
||||
<wp-versions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="wp_versions.xsd">
|
||||
|
||||
<file src="wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin_src.js">
|
||||
<hash md5="5d01c0e812cdcd6356b78ee0cb4e5426">
|
||||
<version>3.7.1</version>
|
||||
</hash>
|
||||
</file>
|
||||
|
||||
<file src="wp-includes/js/jquery/jquery.form.js">
|
||||
<hash md5="e5afd8e41d2ec22c19932b068cd90a71">
|
||||
<version>3.7</version>
|
||||
</hash>
|
||||
</file>
|
||||
|
||||
<file src="wp-admin/js/common.js">
|
||||
<hash md5="03eaffeef39119f0523a49c7f9767f3b">
|
||||
<version>3.6.1</version>
|
||||
</hash>
|
||||
<hash md5="4516252d47a73630280869994d510180">
|
||||
<version>3.3</version>
|
||||
</hash>
|
||||
</file>
|
||||
|
||||
<file src="wp-includes/js/jquery/jquery.js">
|
||||
<hash md5="9dcde2d5e8aeda556a0c52239fa2f44c">
|
||||
<version>3.6</version>
|
||||
</hash>
|
||||
</file>
|
||||
|
||||
<file src="wp-includes/js/tinymce/tiny_mce.js">
|
||||
<hash md5="eddb5fda74d41dbdac018167536d8d53">
|
||||
<version>3.5.2</version>
|
||||
</hash>
|
||||
|
||||
<hash md5="6e79ab6d786c5c95920064add33ee599">
|
||||
<version>3.5.1</version>
|
||||
</hash>
|
||||
|
||||
<hash md5="55cd8e5ceca9c1763b1401164d70df50">
|
||||
<version>3.5</version>
|
||||
</hash>
|
||||
</file>
|
||||
|
||||
<file src="wp-includes/js/wp-lists.js">
|
||||
<hash md5="46e1341cd4ea49f31046f7d7962adc7f">
|
||||
<version>3.4.2</version>
|
||||
</hash>
|
||||
</file>
|
||||
|
||||
<file src="wp-includes/js/customize-preview.js">
|
||||
<hash md5="617d9fd858e117c7d1d087be168b5643">
|
||||
<version>3.4.1</version>
|
||||
</hash>
|
||||
|
||||
<hash md5="da36bc2dfcb13350c799b62de68dfa4b">
|
||||
<version>3.4</version>
|
||||
</hash>
|
||||
|
||||
<hash md5="a8a259fc5197a78ffe62d6be38dc52f8">
|
||||
<version>3.4-beta4</version>
|
||||
</hash>
|
||||
</file>
|
||||
|
||||
<file src="wp-includes/js/plupload/plupload.js">
|
||||
<hash md5="85199c05db63fcb5880de4af8be7b571">
|
||||
<version>3.3.2</version>
|
||||
</hash>
|
||||
</file>
|
||||
|
||||
|
||||
<file src="$wp-content$/themes/twentyeleven/style.css">
|
||||
|
||||
<!-- same md5 for 3.3.2 -->
|
||||
<hash md5="030d3bac906ba69e9fbc99c5bac54a8e">
|
||||
<version>3.3.1</version>
|
||||
</hash>
|
||||
|
||||
</file>
|
||||
|
||||
|
||||
<file src="wp-admin/js/wp-fullscreen.js">
|
||||
|
||||
<hash md5="5675f7793f171b6424bf72f9d7bf4d9a">
|
||||
<version>3.2.1</version>
|
||||
</hash>
|
||||
|
||||
<hash md5="7b423e0b7c9221092737ad5271d09863">
|
||||
<version>3.2</version>
|
||||
</hash>
|
||||
|
||||
</file>
|
||||
|
||||
<file src="wp-includes/css/admin-bar.css">
|
||||
<hash md5="181250fab3a7e2549a7e7fa21c2e6079">
|
||||
<version>3.1</version>
|
||||
</hash>
|
||||
</file>
|
||||
|
||||
|
||||
<file src="$wp-content$/themes/twentyten/style.css">
|
||||
|
||||
<hash md5="6211e2ac1463bf99e98f28ab63e47c54">
|
||||
<version>3.0</version>
|
||||
</hash>
|
||||
|
||||
</file>
|
||||
|
||||
|
||||
<file src="$wp-plugins$/akismet/readme.txt">
|
||||
|
||||
<hash md5="4d5e52da417aa0101054bd41e6243389">
|
||||
<version>2.8.6</version>
|
||||
</hash>
|
||||
|
||||
<hash md5="58e086dea9d24ed074fe84ba87386c69">
|
||||
<version>2.8.5</version>
|
||||
</hash>
|
||||
|
||||
<hash md5="48c52025b5f28731e9a0c864c189c2e7">
|
||||
<version>2.8.2</version>
|
||||
</hash>
|
||||
|
||||
</file>
|
||||
|
||||
|
||||
<file src="wp-includes/js/wp-ajax-response.js">
|
||||
|
||||
<hash md5="0289d1c13821599764774d55516ab81a">
|
||||
<version>2.7.1</version>
|
||||
</hash>
|
||||
|
||||
</file>
|
||||
|
||||
|
||||
<file src="wp-includes/js/thickbox/thickbox.css">
|
||||
|
||||
<hash md5="9c2bd2be0893adbe02a0f864526734c2">
|
||||
<version>2.7</version>
|
||||
</hash>
|
||||
|
||||
</file>
|
||||
|
||||
|
||||
<file src="wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin.js">
|
||||
|
||||
<hash md5="5b140ddf0f08034402ae78b31d8a1a28">
|
||||
<version>2.6</version>
|
||||
</hash>
|
||||
|
||||
</file>
|
||||
|
||||
|
||||
<file src="wp-includes/js/tinymce/themes/advanced/js/image.js">
|
||||
|
||||
<hash md5="088245408531c58bb52cc092294cc384">
|
||||
<version>2.5.1</version>
|
||||
</hash>
|
||||
|
||||
</file>
|
||||
|
||||
|
||||
<file src="wp-includes/js/tinymce/themes/advanced/js/link.js">
|
||||
|
||||
<hash md5="19c6f3118728c38eb7779aab4847d2d9">
|
||||
<version>2.5</version>
|
||||
</hash>
|
||||
|
||||
</file>
|
||||
|
||||
|
||||
<file src="wp-includes/js/wp-ajax.js">
|
||||
|
||||
<hash md5="c5dbce0c3232c477033e0ce486c62755">
|
||||
<version>2.2</version>
|
||||
</hash>
|
||||
|
||||
</file>
|
||||
|
||||
|
||||
<file src="$wp-content$/themes/default/style.css">
|
||||
|
||||
<hash md5="e44545f529a54de88209ce588676231c">
|
||||
<version>2.0.1</version>
|
||||
</hash>
|
||||
|
||||
<hash md5="f786f66d3a40846aa22dcdfeb44fa562">
|
||||
<version>2.0</version>
|
||||
</hash>
|
||||
|
||||
</file>
|
||||
|
||||
|
||||
<file src="wp-layout.css">
|
||||
|
||||
<hash md5="7140e06c00ed03d2bb3dad7672557510">
|
||||
<version>1.2.1</version>
|
||||
</hash>
|
||||
|
||||
<hash md5="1bcc9253506c067eb130c9fc4f211a2f">
|
||||
<version>1.2-delta</version>
|
||||
</hash>
|
||||
</file>
|
||||
|
||||
|
||||
<file src="layout2b.css">
|
||||
|
||||
<hash md5="baec6b6ccbf71d8dced9f1bf67c751e1">
|
||||
<version>0.71-gold</version>
|
||||
</hash>
|
||||
|
||||
</file>
|
||||
|
||||
</wp-versions>
|
||||
@@ -1,39 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<xs:simpleType name="stringtype">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="filetype">
|
||||
<xs:sequence>
|
||||
<xs:element name="hash" type="hashtype" maxOccurs="unbounded" minOccurs="1"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute type="stringtype" name="src" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:simpleType name="md5type">
|
||||
<xs:restriction base="stringtype">
|
||||
<xs:pattern value="[0-9a-f]{32}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="hashtype">
|
||||
<xs:sequence minOccurs="1" maxOccurs="1">
|
||||
<xs:element name="version" type="stringtype"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute type="md5type" name="md5" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="wp-versions">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="file" type="filetype" maxOccurs="unbounded" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
</xs:schema>
|
||||
2230
data/wp_vulns.xml
2230
data/wp_vulns.xml
File diff suppressed because it is too large
Load Diff
41
dev/pre-commit-hook.rb
Executable file
41
dev/pre-commit-hook.rb
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
# from the top level dir:
|
||||
# ln -sf ../../dev/pre-commit-hook.rb .git/hooks/pre-commit
|
||||
|
||||
require 'pty'
|
||||
html_path = 'rspec_results.html'
|
||||
|
||||
begin
|
||||
PTY.spawn( "rspec spec --format h > #{html_path}" ) do |stdin, stdout, pid|
|
||||
begin
|
||||
stdin.each { |line| print line }
|
||||
rescue Errno::EIO => e
|
||||
puts "Error: #{e.to.s}"
|
||||
return 1
|
||||
end
|
||||
end
|
||||
rescue PTY::ChildExited
|
||||
puts 'Child process exit!'
|
||||
end
|
||||
|
||||
# find out if there were any errors
|
||||
html = open(html_path).read
|
||||
examples = html.match(/(\d+) examples/)[0].to_i rescue 0
|
||||
errors = html.match(/(\d+) errors/)[0].to_i rescue 0
|
||||
if errors == 0
|
||||
errors = html.match(/(\d+) failure/)[0].to_i rescue 0
|
||||
end
|
||||
pending = html.match(/(\d+) pending/)[0].to_i rescue 0
|
||||
|
||||
if errors.zero?
|
||||
puts "0 failed! #{examples} run, #{pending} pending"
|
||||
sleep 1
|
||||
exit 0
|
||||
else
|
||||
puts "\aCOMMIT FAILED!!"
|
||||
puts "View your rspec results at #{File.expand_path(html_path)}"
|
||||
puts
|
||||
puts "#{errors} failed! #{examples} run, #{pending} pending"
|
||||
exit 1
|
||||
end
|
||||
19
dev/stats.rb
Executable file
19
dev/stats.rb
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env ruby
|
||||
# encoding: UTF-8
|
||||
|
||||
require File.expand_path(File.join(__dir__, '..', 'lib', 'wpscan', 'wpscan_helper'))
|
||||
|
||||
wordpress_json = json(WORDPRESSES_FILE)
|
||||
plugins_json = json(PLUGINS_FILE)
|
||||
themes_json = json(THEMES_FILE)
|
||||
|
||||
puts 'WPScan Database Statistics:'
|
||||
puts "* Total tracked wordpresses: #{wordpress_json.count}"
|
||||
puts "* Total tracked plugins: #{plugins_json.count}"
|
||||
puts "* Total tracked themes: #{themes_json.count}"
|
||||
puts "* Total vulnerable wordpresses: #{wordpress_json.select { |item| !wordpress_json[item]['vulnerabilities'].empty? }.count}"
|
||||
puts "* Total vulnerable plugins: #{plugins_json.select { |item| !plugins_json[item]['vulnerabilities'].empty? }.count}"
|
||||
puts "* Total vulnerable themes: #{themes_json.select { |item| !themes_json[item]['vulnerabilities'].empty? }.count}"
|
||||
puts "* Total wordpress vulnerabilities: #{wordpress_json.map {|k,v| v['vulnerabilities'].count}.inject(:+)}"
|
||||
puts "* Total plugin vulnerabilities: #{plugins_json.map {|k,v| v['vulnerabilities'].count}.inject(:+)}"
|
||||
puts "* Total theme vulnerabilities: #{themes_json.map {|k,v| v['vulnerabilities'].count}.inject(:+)}"
|
||||
18
example.conf.json
Normal file
18
example.conf.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0",
|
||||
|
||||
/* Uncomment the "proxy" line to use the proxy
|
||||
SOCKS proxies (4, 4A, 5) are supported, ie : "proxy": "socks5://127.0.0.1:9000"
|
||||
If you do not specify the protocol, http will be used
|
||||
*/
|
||||
//"proxy": "127.0.0.1:3128",
|
||||
//"proxy_auth": "username:password",
|
||||
|
||||
"cache_ttl": 600, // 10 minutes, at this time the cache is cleaned before each scan. If this value is set to 0, the cache will be disabled
|
||||
|
||||
"request_timeout": 60, // 1min
|
||||
|
||||
"connect_timeout": 10, // 10s
|
||||
|
||||
"max_threads": 20
|
||||
}
|
||||
@@ -9,30 +9,39 @@ class Browser
|
||||
include Browser::Options
|
||||
|
||||
OPTIONS = [
|
||||
:available_user_agents,
|
||||
:basic_auth,
|
||||
:cache_ttl,
|
||||
:max_threads,
|
||||
:user_agent,
|
||||
:user_agent_mode,
|
||||
:proxy,
|
||||
:proxy_auth,
|
||||
:request_timeout,
|
||||
:connect_timeout
|
||||
:connect_timeout,
|
||||
:cookie,
|
||||
:throttle,
|
||||
:disable_accept_header,
|
||||
:disable_referer,
|
||||
:disable_tls_checks
|
||||
]
|
||||
|
||||
@@instance = nil
|
||||
|
||||
attr_reader :hydra, :config_file, :cache_dir
|
||||
attr_reader :hydra, :cache_dir
|
||||
|
||||
attr_accessor :referer, :cookie, :vhost
|
||||
|
||||
# @param [ Hash ] options
|
||||
#
|
||||
# @return [ Browser ]
|
||||
def initialize(options = {})
|
||||
@config_file = options[:config_file] || CONF_DIR + '/browser.conf.json'
|
||||
@cache_dir = options[:cache_dir] || CACHE_DIR + '/browser'
|
||||
|
||||
load_config
|
||||
# sets browser defaults
|
||||
browser_defaults
|
||||
# load config file
|
||||
conf = options[:config_file]
|
||||
load_config(conf) if conf
|
||||
# overrides defaults with user supplied values (overwrite values from config)
|
||||
override_config(options)
|
||||
|
||||
unless @hydra
|
||||
@@ -61,6 +70,26 @@ class Browser
|
||||
@@instance = nil
|
||||
end
|
||||
|
||||
# Override for setting the User-Agent
|
||||
# @param [ String ] user_agent
|
||||
def user_agent=(user_agent)
|
||||
Typhoeus::Config.user_agent = user_agent
|
||||
end
|
||||
|
||||
#
|
||||
# sets browser default values
|
||||
#
|
||||
def browser_defaults
|
||||
Typhoeus::Config.user_agent = "WPScan v#{WPSCAN_VERSION} (http://wpscan.org)"
|
||||
@max_threads = 20
|
||||
# 10 minutes, at this time the cache is cleaned before each scan.
|
||||
# If this value is set to 0, the cache will be disabled
|
||||
@cache_ttl = 600
|
||||
@request_timeout = 60 # 60s
|
||||
@connect_timeout = 10 # 10s
|
||||
@throttle = 0
|
||||
end
|
||||
|
||||
#
|
||||
# If an option was set but is not in the new config_file
|
||||
# it's value is kept
|
||||
@@ -69,17 +98,14 @@ class Browser
|
||||
#
|
||||
# @return [ void ]
|
||||
def load_config(config_file = nil)
|
||||
@config_file = config_file || @config_file
|
||||
|
||||
if File.symlink?(@config_file)
|
||||
if File.symlink?(config_file)
|
||||
raise '[ERROR] Config file is a symlink.'
|
||||
else
|
||||
data = JSON.parse(File.read(@config_file))
|
||||
data = JSON.parse(File.read(config_file))
|
||||
end
|
||||
|
||||
OPTIONS.each do |option|
|
||||
option_name = option.to_s
|
||||
|
||||
unless data[option_name].nil?
|
||||
self.send(:"#{option_name}=", data[option_name])
|
||||
end
|
||||
@@ -98,18 +124,9 @@ class Browser
|
||||
#
|
||||
# @return [ Hash ]
|
||||
def merge_request_params(params = {})
|
||||
params = Browser.append_params_header_field(
|
||||
params,
|
||||
'User-Agent',
|
||||
self.user_agent
|
||||
)
|
||||
|
||||
if @proxy
|
||||
params = params.merge(proxy: @proxy)
|
||||
|
||||
if @proxy_auth
|
||||
params = params.merge(proxyauth: @proxy_auth)
|
||||
end
|
||||
params.merge!(proxy: @proxy)
|
||||
params.merge!(proxyauth: @proxy_auth) if @proxy_auth
|
||||
end
|
||||
|
||||
if @basic_auth
|
||||
@@ -120,25 +137,37 @@ class Browser
|
||||
)
|
||||
end
|
||||
|
||||
if @request_timeout
|
||||
params = params.merge(timeout: @request_timeout)
|
||||
if vhost
|
||||
params = Browser.append_params_header_field(
|
||||
params,
|
||||
'Host',
|
||||
vhost
|
||||
)
|
||||
end
|
||||
|
||||
if @connect_timeout
|
||||
params = params.merge(connecttimeout: @connect_timeout)
|
||||
end
|
||||
params.merge!(referer: referer)
|
||||
params.merge!(timeout: @request_timeout) if @request_timeout && !params.key?(:timeout)
|
||||
params.merge!(connecttimeout: @connect_timeout) if @connect_timeout && !params.key?(:connecttimeout)
|
||||
|
||||
# Used to enable the cache system if :cache_ttl > 0
|
||||
unless params.has_key?(:cache_ttl)
|
||||
params = params.merge(cache_ttl: @cache_ttl)
|
||||
end
|
||||
params.merge!(cache_ttl: @cache_ttl) unless params.key?(:cache_ttl)
|
||||
|
||||
# Prevent infinite self redirection
|
||||
params.merge!(maxredirs: 3) unless params.key?(:maxredirs)
|
||||
|
||||
# Disable SSL-Certificate checks
|
||||
params.merge!(ssl_verifypeer: false)
|
||||
params.merge!(ssl_verifyhost: 0)
|
||||
if @disable_tls_checks
|
||||
# Cert validity check
|
||||
params.merge!(ssl_verifypeer: 0) unless params.key?(:ssl_verifypeer)
|
||||
# Cert hostname check
|
||||
params.merge!(ssl_verifyhost: 0) unless params.key?(:ssl_verifyhost)
|
||||
end
|
||||
|
||||
params.merge!(cookiejar: @cache_dir + '/cookie-jar')
|
||||
params.merge!(cookiefile: @cache_dir + '/cookie-jar')
|
||||
params.merge!(cookie: @cookie) if @cookie
|
||||
params = Browser.remove_params_header_field(params, 'Accept') if @disable_accept_header
|
||||
params = Browser.remove_params_header_field(params, 'Referer') if @disable_referer
|
||||
|
||||
params
|
||||
end
|
||||
@@ -159,4 +188,17 @@ class Browser
|
||||
params
|
||||
end
|
||||
|
||||
# @param [ Hash ] params
|
||||
# @param [ String ] field
|
||||
# @param [ Mixed ] field_value
|
||||
#
|
||||
# @return [ Array ]
|
||||
def self.remove_params_header_field(params = {}, field)
|
||||
if !params.has_key?(:headers)
|
||||
params = params.merge(:headers => { field => nil })
|
||||
elsif !params[:headers].has_key?(field)
|
||||
params[:headers][field] = nil
|
||||
end
|
||||
params
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,11 +3,8 @@
|
||||
class Browser
|
||||
module Options
|
||||
|
||||
USER_AGENT_MODES = %w{ static semi-static random }
|
||||
|
||||
attr_accessor :available_user_agents, :cache_ttl, :request_timeout, :connect_timeout
|
||||
attr_reader :basic_auth, :user_agent_mode, :proxy, :proxy_auth
|
||||
attr_writer :user_agent
|
||||
attr_accessor :request_timeout, :connect_timeout, :user_agent, :disable_accept_header, :disable_referer, :disable_tls_checks
|
||||
attr_reader :basic_auth, :cache_ttl, :proxy, :proxy_auth, :throttle
|
||||
|
||||
# Sets the Basic Authentification credentials
|
||||
# Accepted format:
|
||||
@@ -23,10 +20,14 @@ class Browser
|
||||
elsif auth =~ /\ABasic [a-zA-Z0-9=]+\z/
|
||||
@basic_auth = auth
|
||||
else
|
||||
raise 'Invalid basic authentication format, "login:password" or "Basic base_64_encoded" expected'
|
||||
raise "Invalid basic authentication format, \"login:password\" or \"Basic base_64_encoded\" expected. Your input: #{auth}"
|
||||
end
|
||||
end
|
||||
|
||||
def cache_ttl=(ttl)
|
||||
@cache_ttl = ttl.to_i
|
||||
end
|
||||
|
||||
# @return [ Integer ]
|
||||
def max_threads
|
||||
@max_threads || 1
|
||||
@@ -41,42 +42,6 @@ class Browser
|
||||
end
|
||||
end
|
||||
|
||||
# Sets the user_agent_mode, which can be one of the following:
|
||||
# static: The UA is defined by the user, and will be the same in each requests
|
||||
# semi-static: The UA is randomly chosen at the first request, and will not change
|
||||
# random: UA randomly chosen each request
|
||||
#
|
||||
# UA are from @available_user_agents
|
||||
#
|
||||
# @param [ String ] ua_mode
|
||||
#
|
||||
# @return [ void ]
|
||||
def user_agent_mode=(ua_mode)
|
||||
ua_mode ||= 'static'
|
||||
|
||||
if USER_AGENT_MODES.include?(ua_mode)
|
||||
@user_agent_mode = ua_mode
|
||||
# For semi-static user agent mode, the user agent has to
|
||||
# be nil the first time (it will be set with the getter)
|
||||
@user_agent = nil if ua_mode === 'semi-static'
|
||||
else
|
||||
raise "Unknow user agent mode : '#{ua_mode}'"
|
||||
end
|
||||
end
|
||||
|
||||
# @return [ String ] The user agent, according to the user_agent_mode
|
||||
def user_agent
|
||||
case @user_agent_mode
|
||||
when 'semi-static'
|
||||
unless @user_agent
|
||||
@user_agent = @available_user_agents.sample
|
||||
end
|
||||
when 'random'
|
||||
@user_agent = @available_user_agents.sample
|
||||
end
|
||||
@user_agent
|
||||
end
|
||||
|
||||
# Sets the proxy
|
||||
# Accepted format:
|
||||
# [protocol://]host:post
|
||||
@@ -120,7 +85,7 @@ class Browser
|
||||
#
|
||||
# @return [ void ]
|
||||
def request_timeout=(timeout)
|
||||
@request_timeout = timeout
|
||||
@request_timeout = timeout.to_i
|
||||
end
|
||||
|
||||
# Sets the connect timeout
|
||||
@@ -128,7 +93,12 @@ class Browser
|
||||
#
|
||||
# @return [ void ]
|
||||
def connect_timeout=(timeout)
|
||||
@connect_timeout = timeout
|
||||
@connect_timeout = timeout.to_i
|
||||
end
|
||||
|
||||
# @param [ String, Integer ] throttle
|
||||
def throttle=(throttle)
|
||||
@throttle = throttle.to_i.abs / 1000.0
|
||||
end
|
||||
|
||||
protected
|
||||
@@ -148,6 +118,5 @@ class Browser
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,41 +9,47 @@
|
||||
#
|
||||
|
||||
require 'yaml'
|
||||
require 'fileutils'
|
||||
|
||||
class CacheFileStore
|
||||
attr_reader :storage_path, :serializer
|
||||
attr_reader :storage_path, :cache_dir, :serializer
|
||||
|
||||
# The serializer must have the 2 methods .load and .dump
|
||||
# (Marshal and YAML have them)
|
||||
# YAML is Human Readable, contrary to Marshal which store in a binary format
|
||||
# Marshal does not need any "require"
|
||||
def initialize(storage_path, serializer = Marshal)
|
||||
@storage_path = File.expand_path(storage_path)
|
||||
@cache_dir = File.expand_path(storage_path)
|
||||
@storage_path = File.expand_path(File.join(storage_path, storage_dir))
|
||||
@serializer = serializer
|
||||
|
||||
# File.directory? for ruby <= 1.9 otherwise,
|
||||
# it makes more sense to do Dir.exist? :/
|
||||
unless File.directory?(@storage_path)
|
||||
unless Dir.exist?(@storage_path)
|
||||
FileUtils.mkdir_p(@storage_path)
|
||||
end
|
||||
end
|
||||
|
||||
def clean
|
||||
Dir[File.join(@storage_path, '*')].each do |f|
|
||||
# clean old directories
|
||||
Dir[File.join(@cache_dir, '*')].each do |f|
|
||||
if File.directory?(f)
|
||||
# delete directory if create time is older than 4 hours
|
||||
FileUtils.rm_rf(f) if File.mtime(f) < (Time.now - (60*240))
|
||||
else
|
||||
File.delete(f) unless File.symlink?(f)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def read_entry(key)
|
||||
entry_file_path = get_entry_file_path(key)
|
||||
|
||||
if File.exists?(entry_file_path)
|
||||
return @serializer.load(File.read(entry_file_path))
|
||||
begin
|
||||
@serializer.load(File.read(get_entry_file_path(key)))
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def write_entry(key, data_to_store, cache_ttl)
|
||||
if cache_ttl > 0
|
||||
if cache_ttl && cache_ttl > 0
|
||||
File.open(get_entry_file_path(key), 'w') do |f|
|
||||
begin
|
||||
f.write(@serializer.dump(data_to_store))
|
||||
@@ -58,4 +64,11 @@ class CacheFileStore
|
||||
File::join(@storage_path, key)
|
||||
end
|
||||
|
||||
def storage_dir
|
||||
time = Time.now
|
||||
random = (0...8).map { (65 + rand(26)).chr }.join
|
||||
|
||||
Digest::MD5.hexdigest("#{time}#{random}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
class Vulnerabilities < Array
|
||||
module Output
|
||||
|
||||
def output
|
||||
def output(verbose = false)
|
||||
self.each do |v|
|
||||
v.output
|
||||
v.output(verbose)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
3
lib/common/collections/wp_items.rb
Executable file → Normal file
3
lib/common/collections/wp_items.rb
Executable file → Normal file
@@ -14,7 +14,7 @@ class WpItems < Array
|
||||
self.wp_target = wp_target
|
||||
end
|
||||
|
||||
# @param [String,] argv
|
||||
# @param [String] args
|
||||
#
|
||||
# @return [ void ]
|
||||
def add(*args)
|
||||
@@ -67,6 +67,7 @@ class WpItems < Array
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# @return [ Class ]
|
||||
def item_class
|
||||
Object.const_get(self.class.to_s.gsub(/.$/, ''))
|
||||
|
||||
115
lib/common/collections/wp_items/detectable.rb
Executable file → Normal file
115
lib/common/collections/wp_items/detectable.rb
Executable file → Normal file
@@ -17,15 +17,13 @@ class WpItems < Array
|
||||
hydra = browser.hydra
|
||||
targets = targets_items(wp_target, options)
|
||||
progress_bar = progress_bar(targets.size, options)
|
||||
queue_count = 0
|
||||
exist_options = {
|
||||
error_404_hash: wp_target.error_404_hash,
|
||||
homepage_hash: wp_target.homepage_hash,
|
||||
exclude_content: options[:exclude_content] ? %r{#{options[:exclude_content]}} : nil
|
||||
}
|
||||
|
||||
# If we only want the vulnerable ones, the passive detection is ignored
|
||||
# Otherwise, a passive detection is performed, and results will be merged
|
||||
results = options[:only_vulnerable] ? new : passive_detection(wp_target, options)
|
||||
results = passive_detection(wp_target, options)
|
||||
|
||||
targets.each do |target_item|
|
||||
request = browser.forge_request(target_item.url, request_params)
|
||||
@@ -34,20 +32,27 @@ class WpItems < Array
|
||||
progress_bar.progress += 1 if options[:show_progression]
|
||||
|
||||
if target_item.exists?(exist_options, response)
|
||||
if !results.include?(target_item)
|
||||
if !options[:only_vulnerable] || options[:only_vulnerable] && target_item.vulnerable?
|
||||
results << target_item
|
||||
end
|
||||
end
|
||||
results << target_item unless results.include?(target_item)
|
||||
end
|
||||
end
|
||||
|
||||
hydra.queue(request)
|
||||
queue_count += 1
|
||||
|
||||
if queue_count >= browser.max_threads
|
||||
hydra.run
|
||||
queue_count = 0
|
||||
puts "Sent #{browser.max_threads} requests ..." if options[:verbose]
|
||||
end
|
||||
end
|
||||
|
||||
# run the remaining requests
|
||||
hydra.run
|
||||
|
||||
results.select!(&:vulnerable?) if options[:type] == :vulnerable
|
||||
results.sort!
|
||||
results # can't just return results.sort because the #sort returns an array, and we want a WpItems
|
||||
|
||||
results # can't just return results.sort as it would return an array, and we want a WpItems
|
||||
end
|
||||
|
||||
# @param [ Integer ] targets_size
|
||||
@@ -72,12 +77,34 @@ class WpItems < Array
|
||||
# @return [ WpItems ]
|
||||
def passive_detection(wp_target, options = {})
|
||||
results = new(wp_target)
|
||||
body = Browser.get(wp_target.url).body
|
||||
# improves speed
|
||||
body = remove_base64_images_from_html(body)
|
||||
names = body.scan(passive_detection_pattern(wp_target))
|
||||
body = remove_base64_images_from_html(Browser.get(wp_target.url).body)
|
||||
page = Nokogiri::HTML(body)
|
||||
names = []
|
||||
|
||||
names.flatten.uniq.each { |name| results.add(name) }
|
||||
page.css('link,script,style').each do |tag|
|
||||
%w(href src).each do |attribute|
|
||||
attr_value = tag.attribute(attribute).to_s
|
||||
next unless attr_value
|
||||
|
||||
names << Regexp.last_match[1] if attr_value.match(attribute_pattern(wp_target))
|
||||
end
|
||||
|
||||
next unless tag.name == 'script' || tag.name == 'style'
|
||||
|
||||
code = tag.text.to_s
|
||||
next if code.empty?
|
||||
|
||||
if ! code.valid_encoding?
|
||||
code = code.encode('UTF-16be', :invalid => :replace, :replace => '?').encode('UTF-8')
|
||||
end
|
||||
|
||||
code.scan(code_pattern(wp_target)).flatten.uniq.each do |item_name|
|
||||
names << item_name
|
||||
end
|
||||
end
|
||||
|
||||
names.uniq.each { |name| results.add(name) }
|
||||
|
||||
results.sort!
|
||||
results
|
||||
@@ -88,13 +115,29 @@ class WpItems < Array
|
||||
# @param [ WpTarget ] wp_target
|
||||
#
|
||||
# @return [ Regex ]
|
||||
def passive_detection_pattern(wp_target)
|
||||
type = self.to_s.gsub(/Wp/, '').downcase
|
||||
regex1 = %r{(?:[^=:\(]+)\s?(?:=|:|\()\s?(?:"|')[^"']+\\?/}
|
||||
regex2 = %r{\\?/}
|
||||
regex3 = %r{\\?/([^/\\"']+)\\?(?:/|"|')}
|
||||
def item_pattern(wp_target)
|
||||
type = to_s.gsub(/Wp/, '').downcase
|
||||
wp_content_dir = wp_target.wp_content_dir
|
||||
wp_content_url = wp_target.uri.merge(wp_content_dir).to_s
|
||||
|
||||
/#{regex1}#{Regexp.escape(wp_target.wp_content_dir)}#{regex2}#{Regexp.escape(type)}#{regex3}/i
|
||||
url = wp_content_url.gsub(%r{\A(?:http|https)://}, '(?:https?:)?//').gsub('/', '\\\\\?\/')
|
||||
content_dir = %r{(?:#{url}|\\?\/\\?\/?#{wp_content_dir})}i
|
||||
|
||||
%r{#{content_dir}\\?/#{type}\\?/}
|
||||
end
|
||||
|
||||
# @param [ WpTarget ] wp_target
|
||||
#
|
||||
# @return [ Regex ]
|
||||
def attribute_pattern(wp_target)
|
||||
/\A#{item_pattern(wp_target)}([^\/]+)/i
|
||||
end
|
||||
|
||||
# @param [ WpTarget ] wp_target
|
||||
#
|
||||
# @return [ Regex ]
|
||||
def code_pattern(wp_target)
|
||||
/["'\(]#{item_pattern(wp_target)}([^\\\/\)"']+)/i
|
||||
end
|
||||
|
||||
# The default request parameters
|
||||
@@ -112,15 +155,7 @@ class WpItems < Array
|
||||
item_class = self.item_class
|
||||
vulns_file = self.vulns_file
|
||||
|
||||
targets = vulnerable_targets_items(wp_target, item_class, vulns_file)
|
||||
|
||||
unless options[:only_vulnerable]
|
||||
unless options[:file]
|
||||
raise 'A file must be supplied'
|
||||
end
|
||||
|
||||
targets += targets_items_from_file(options[:file], wp_target, item_class, vulns_file)
|
||||
end
|
||||
targets = target_items_from_type(wp_target, item_class, vulns_file, options[:type])
|
||||
|
||||
targets.uniq! { |t| t.name }
|
||||
targets.sort_by { rand }
|
||||
@@ -131,18 +166,30 @@ class WpItems < Array
|
||||
# @param [ String ] vulns_file
|
||||
#
|
||||
# @return [ Array<WpItem> ]
|
||||
def vulnerable_targets_items(wp_target, item_class, vulns_file)
|
||||
def target_items_from_type(wp_target, item_class, vulns_file, type)
|
||||
targets = []
|
||||
xml = xml(vulns_file)
|
||||
json = json(vulns_file)
|
||||
|
||||
xml.xpath(item_xpath).each do |node|
|
||||
case type
|
||||
when :vulnerable
|
||||
items = json.select { |item| !json[item]['vulnerabilities'].empty? }.keys
|
||||
when :popular
|
||||
items = json.select { |item| json[item]['popular'] == true }.keys
|
||||
when :all
|
||||
items = json.keys
|
||||
else
|
||||
raise "Unknown type #{type}"
|
||||
end
|
||||
|
||||
items.each do |item|
|
||||
targets << create_item(
|
||||
item_class,
|
||||
node.attribute('name').text,
|
||||
item,
|
||||
wp_target,
|
||||
vulns_file
|
||||
)
|
||||
end
|
||||
|
||||
targets
|
||||
end
|
||||
|
||||
@@ -181,6 +228,7 @@ class WpItems < Array
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
targets
|
||||
end
|
||||
|
||||
@@ -188,6 +236,5 @@ class WpItems < Array
|
||||
def item_class
|
||||
Object.const_get(self.to_s.gsub(/.$/, ''))
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
class WpItems < Array
|
||||
module Output
|
||||
|
||||
def output
|
||||
self.each { |item| item.output }
|
||||
def output(verbose = false)
|
||||
self.each { |item| item.output(verbose) }
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
0
lib/common/collections/wp_plugins.rb
Executable file → Normal file
0
lib/common/collections/wp_plugins.rb
Executable file → Normal file
@@ -2,15 +2,9 @@
|
||||
|
||||
class WpPlugins < WpItems
|
||||
module Detectable
|
||||
|
||||
# @return [ String ]
|
||||
def vulns_file
|
||||
PLUGINS_VULNS_FILE
|
||||
end
|
||||
|
||||
# @return [ String ]
|
||||
def item_xpath
|
||||
'//plugin'
|
||||
PLUGINS_FILE
|
||||
end
|
||||
|
||||
# @param [ WpTarget ] wp_target
|
||||
@@ -68,6 +62,14 @@ class WpPlugins < WpItems
|
||||
wp_plugins.add('all-in-one-seo-pack', version: $1)
|
||||
end
|
||||
|
||||
if body =~ /<!-- This site is optimized with the Yoast (?:WordPress )?SEO plugin v([^\s]+) -/i
|
||||
wp_plugins.add('wordpress-seo', version: $1)
|
||||
end
|
||||
|
||||
if body =~ /<!-- Google Universal Analytics for WordPress v([^\s]+) -/i
|
||||
wp_plugins.add('google-universal-analytics', version: $1)
|
||||
end
|
||||
|
||||
wp_plugins
|
||||
end
|
||||
|
||||
|
||||
0
lib/common/collections/wp_themes.rb
Executable file → Normal file
0
lib/common/collections/wp_themes.rb
Executable file → Normal file
@@ -5,13 +5,7 @@ class WpThemes < WpItems
|
||||
|
||||
# @return [ String ]
|
||||
def vulns_file
|
||||
THEMES_VULNS_FILE
|
||||
end
|
||||
|
||||
# @return [ String ]
|
||||
def item_xpath
|
||||
'//theme'
|
||||
end
|
||||
|
||||
THEMES_FILE
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
0
lib/common/collections/wp_timthumbs.rb
Executable file → Normal file
0
lib/common/collections/wp_timthumbs.rb
Executable file → Normal file
@@ -41,7 +41,7 @@ class WpTimthumbs < WpItems
|
||||
|
||||
%w{
|
||||
timthumb.php lib/timthumb.php inc/timthumb.php includes/timthumb.php
|
||||
scripts/timthumb.php tools/timthumb.php functions/timthumb.php
|
||||
scripts/timthumb.php tools/timthumb.php functions/timthumb.php thumb.php
|
||||
}.each do |path|
|
||||
wp_timthumb.path = "$wp-content$/themes/#{theme_name}/#{path}"
|
||||
|
||||
|
||||
0
lib/common/collections/wp_users.rb
Executable file → Normal file
0
lib/common/collections/wp_users.rb
Executable file → Normal file
0
lib/common/collections/wp_users/detectable.rb
Executable file → Normal file
0
lib/common/collections/wp_users/detectable.rb
Executable file → Normal file
@@ -38,6 +38,7 @@ class WpUsers < WpItems
|
||||
junk = get_equal_string_end(display_names)
|
||||
unless junk.nil? or junk.empty?
|
||||
self.each do |u|
|
||||
u.display_name ||= ''
|
||||
u.display_name = u.display_name.sub(/#{Regexp.escape(junk)}$/, '')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,39 +1,36 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
LIB_DIR = File.expand_path(File.dirname(__FILE__) + '/..')
|
||||
ROOT_DIR = File.expand_path(LIB_DIR + '/..') # expand_path is used to get "wpscan/" instead of "wpscan/lib/../"
|
||||
DATA_DIR = ROOT_DIR + '/data'
|
||||
CONF_DIR = ROOT_DIR + '/conf'
|
||||
CACHE_DIR = ROOT_DIR + '/cache'
|
||||
WPSCAN_LIB_DIR = LIB_DIR + '/wpscan'
|
||||
WPSTOOLS_LIB_DIR = LIB_DIR + '/wpstools'
|
||||
UPDATER_LIB_DIR = LIB_DIR + '/updater'
|
||||
COMMON_LIB_DIR = LIB_DIR + '/common'
|
||||
MODELS_LIB_DIR = COMMON_LIB_DIR + '/models'
|
||||
COLLECTIONS_LIB_DIR = COMMON_LIB_DIR + '/collections'
|
||||
LIB_DIR = File.expand_path(File.join(__dir__, '..'))
|
||||
ROOT_DIR = File.expand_path(File.join(LIB_DIR, '..')) # expand_path is used to get "wpscan/" instead of "wpscan/lib/../"
|
||||
DATA_DIR = File.join(ROOT_DIR, 'data')
|
||||
CONF_DIR = File.join(ROOT_DIR, 'conf')
|
||||
CACHE_DIR = File.join(ROOT_DIR, 'cache')
|
||||
WPSCAN_LIB_DIR = File.join(LIB_DIR, 'wpscan')
|
||||
UPDATER_LIB_DIR = File.join(LIB_DIR, 'updater')
|
||||
COMMON_LIB_DIR = File.join(LIB_DIR, 'common')
|
||||
MODELS_LIB_DIR = File.join(COMMON_LIB_DIR, 'models')
|
||||
COLLECTIONS_LIB_DIR = File.join(COMMON_LIB_DIR, 'collections')
|
||||
|
||||
LOG_FILE = ROOT_DIR + '/log.txt'
|
||||
DEFAULT_LOG_FILE = File.join(ROOT_DIR, 'log.txt')
|
||||
|
||||
# Plugins directories
|
||||
COMMON_PLUGINS_DIR = COMMON_LIB_DIR + '/plugins'
|
||||
WPSCAN_PLUGINS_DIR = WPSCAN_LIB_DIR + '/plugins' # Not used ATM
|
||||
WPSTOOLS_PLUGINS_DIR = WPSTOOLS_LIB_DIR + '/plugins'
|
||||
COMMON_PLUGINS_DIR = File.join(COMMON_LIB_DIR, 'plugins')
|
||||
WPSCAN_PLUGINS_DIR = File.join(WPSCAN_LIB_DIR, 'plugins') # Not used ATM
|
||||
|
||||
# Data files
|
||||
PLUGINS_FILE = DATA_DIR + '/plugins.txt'
|
||||
PLUGINS_FULL_FILE = DATA_DIR + '/plugins_full.txt'
|
||||
PLUGINS_VULNS_FILE = DATA_DIR + '/plugin_vulns.xml'
|
||||
THEMES_FILE = DATA_DIR + '/themes.txt'
|
||||
THEMES_FULL_FILE = DATA_DIR + '/themes_full.txt'
|
||||
THEMES_VULNS_FILE = DATA_DIR + '/theme_vulns.xml'
|
||||
WP_VULNS_FILE = DATA_DIR + '/wp_vulns.xml'
|
||||
WP_VERSIONS_FILE = DATA_DIR + '/wp_versions.xml'
|
||||
LOCAL_FILES_FILE = DATA_DIR + '/local_vulnerable_files.xml'
|
||||
VULNS_XSD = DATA_DIR + '/vuln.xsd'
|
||||
WP_VERSIONS_XSD = DATA_DIR + '/wp_versions.xsd'
|
||||
LOCAL_FILES_XSD = DATA_DIR + '/local_vulnerable_files.xsd'
|
||||
WORDPRESSES_FILE = File.join(DATA_DIR, 'wordpresses.json')
|
||||
PLUGINS_FILE = File.join(DATA_DIR, 'plugins.json')
|
||||
THEMES_FILE = File.join(DATA_DIR, 'themes.json')
|
||||
WP_VERSIONS_FILE = File.join(DATA_DIR, 'wp_versions.xml')
|
||||
LOCAL_FILES_FILE = File.join(DATA_DIR, 'local_vulnerable_files.xml')
|
||||
WP_VERSIONS_XSD = File.join(DATA_DIR, 'wp_versions.xsd')
|
||||
LOCAL_FILES_XSD = File.join(DATA_DIR, 'local_vulnerable_files.xsd')
|
||||
USER_AGENTS_FILE = File.join(DATA_DIR, 'user-agents.txt')
|
||||
LAST_UPDATE_FILE = File.join(DATA_DIR, '.last_update')
|
||||
|
||||
WPSCAN_VERSION = '2.2'
|
||||
MIN_RUBY_VERSION = '2.1.9'
|
||||
|
||||
WPSCAN_VERSION = '2.9.3'
|
||||
|
||||
$LOAD_PATH.unshift(LIB_DIR)
|
||||
$LOAD_PATH.unshift(WPSCAN_LIB_DIR)
|
||||
@@ -41,20 +38,29 @@ $LOAD_PATH.unshift(MODELS_LIB_DIR)
|
||||
|
||||
def kali_linux?
|
||||
begin
|
||||
File.readlines("/etc/debian_version").grep(/^kali/i).any?
|
||||
File.readlines('/etc/debian_version').grep(/^kali/i).any?
|
||||
rescue
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# Determins if installed on Windows OS
|
||||
def windows?
|
||||
Gem.win_platform?
|
||||
end
|
||||
|
||||
require 'environment'
|
||||
|
||||
def escape_glob(s)
|
||||
s.gsub(/[\\\{\}\[\]\*\?]/) { |x| '\\' + x }
|
||||
end
|
||||
|
||||
# TODO : add an exclude pattern ?
|
||||
def require_files_from_directory(absolute_dir_path, files_pattern = '*.rb')
|
||||
files = Dir[File.join(absolute_dir_path, files_pattern)]
|
||||
files = Dir[File.join(escape_glob(absolute_dir_path), files_pattern)]
|
||||
|
||||
# Files in the root dir are loaded first, then thoses in the subdirectories
|
||||
files.sort_by { |file| [file.count("/"), file] }.each do |f|
|
||||
# Files in the root dir are loaded first, then those in the subdirectories
|
||||
files.sort_by { |file| [file.count('/'), file] }.each do |f|
|
||||
f = File.expand_path(f)
|
||||
# puts "require #{f}" # Used for debug
|
||||
require f
|
||||
@@ -72,45 +78,41 @@ def add_trailing_slash(url)
|
||||
url =~ /\/$/ ? url : "#{url}/"
|
||||
end
|
||||
|
||||
# loading the updater
|
||||
require_files_from_directory(UPDATER_LIB_DIR)
|
||||
@updater = UpdaterFactory.get_updater(ROOT_DIR)
|
||||
|
||||
if @updater
|
||||
REVISION = @updater.local_revision_number()
|
||||
else
|
||||
REVISION = nil
|
||||
def missing_db_file?
|
||||
DbUpdater::FILES.each do |db_file|
|
||||
return true unless File.exist?(File.join(DATA_DIR, db_file))
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
def version
|
||||
REVISION ? "v#{WPSCAN_VERSION}r#{REVISION}" : "v#{WPSCAN_VERSION}"
|
||||
def last_update
|
||||
date = nil
|
||||
if File.exists?(LAST_UPDATE_FILE)
|
||||
content = File.read(LAST_UPDATE_FILE)
|
||||
date = Time.parse(content) rescue nil
|
||||
end
|
||||
date
|
||||
end
|
||||
|
||||
# our 1337 banner
|
||||
def banner
|
||||
puts '_______________________________________________________________'
|
||||
puts ' __ _______ _____ '
|
||||
puts ' \\ \\ / / __ \\ / ____| '
|
||||
puts ' \\ \\ /\\ / /| |__) | (___ ___ __ _ _ __ '
|
||||
puts ' \\ \\/ \\/ / | ___/ \\___ \\ / __|/ _` | \'_ \\ '
|
||||
puts ' \\ /\\ / | | ____) | (__| (_| | | | |'
|
||||
puts ' \\/ \\/ |_| |_____/ \\___|\\__,_|_| |_|'
|
||||
puts
|
||||
puts ' WordPress Security Scanner by the WPScan Team '
|
||||
if REVISION
|
||||
puts " Version #{version}"
|
||||
else
|
||||
puts " Version #{version}"
|
||||
end
|
||||
puts ' Sponsored by the RandomStorm Open Source Initiative'
|
||||
puts ' @_WPScan_, @ethicalhack3r, @erwan_lr, @gbrindisi, @_FireFart_'
|
||||
puts '_______________________________________________________________'
|
||||
puts
|
||||
def update_required?
|
||||
date = last_update
|
||||
day_seconds = 24 * 60 * 60
|
||||
five_days_ago = Time.now - (5 * day_seconds)
|
||||
(true if date.nil?) or (date < five_days_ago)
|
||||
end
|
||||
|
||||
# Define colors
|
||||
def colorize(text, color_code)
|
||||
if $COLORSWITCH
|
||||
"#{text}"
|
||||
else
|
||||
"\e[#{color_code}m#{text}\e[0m"
|
||||
end
|
||||
end
|
||||
|
||||
def bold(text)
|
||||
colorize(text, 1)
|
||||
end
|
||||
|
||||
def red(text)
|
||||
colorize(text, 31)
|
||||
@@ -120,12 +122,67 @@ def green(text)
|
||||
colorize(text, 32)
|
||||
end
|
||||
|
||||
def amber(text)
|
||||
colorize(text, 33)
|
||||
end
|
||||
|
||||
def blue(text)
|
||||
colorize(text, 34)
|
||||
end
|
||||
|
||||
def critical(text)
|
||||
$exit_code += 1 if defined?($exit_code) # hack for undefined var via rspec
|
||||
"#{red('[!]')} #{text}"
|
||||
end
|
||||
|
||||
def warning(text)
|
||||
$exit_code += 1 if defined?($exit_code) # hack for undefined var via rspec
|
||||
"#{amber('[!]')} #{text}"
|
||||
end
|
||||
|
||||
def info(text)
|
||||
"#{green('[+]')} #{text}"
|
||||
end
|
||||
|
||||
def notice(text)
|
||||
"#{blue('[i]')} #{text}"
|
||||
end
|
||||
|
||||
# our 1337 banner
|
||||
def banner
|
||||
puts '_______________________________________________________________'
|
||||
puts ' __ _______ _____ '
|
||||
puts ' \\ \\ / / __ \\ / ____| '
|
||||
puts ' \\ \\ /\\ / /| |__) | (___ ___ __ _ _ __ ®'
|
||||
puts ' \\ \\/ \\/ / | ___/ \\___ \\ / __|/ _` | \'_ \\ '
|
||||
puts ' \\ /\\ / | | ____) | (__| (_| | | | |'
|
||||
puts ' \\/ \\/ |_| |_____/ \\___|\\__,_|_| |_|'
|
||||
puts
|
||||
puts ' WordPress Security Scanner by the WPScan Team '
|
||||
puts " Version #{WPSCAN_VERSION}"
|
||||
puts ' Sponsored by Sucuri - https://sucuri.net'
|
||||
puts ' @_WPScan_, @ethicalhack3r, @erwan_lr, pvdl, @_FireFart_'
|
||||
puts '_______________________________________________________________'
|
||||
puts
|
||||
end
|
||||
|
||||
def xml(file)
|
||||
Nokogiri::XML(File.open(file)) do |config|
|
||||
config.noblanks
|
||||
end
|
||||
end
|
||||
|
||||
def json(file)
|
||||
content = File.open(file).read
|
||||
|
||||
begin
|
||||
JSON.parse(content)
|
||||
rescue => e
|
||||
puts "[ERROR] In JSON file parsing #{file} #{e}"
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
||||
def redefine_constant(constant, value)
|
||||
Object.send(:remove_const, constant)
|
||||
Object.const_set(constant, value)
|
||||
@@ -175,5 +232,45 @@ end
|
||||
#
|
||||
# @return [ Integer ] The number of lines in the given file
|
||||
def count_file_lines(file)
|
||||
if windows?
|
||||
`findstr /R /N "^" #{file.shellescape} | find /C ":"`.split[0].to_i
|
||||
else
|
||||
`wc -l #{file.shellescape}`.split[0].to_i
|
||||
end
|
||||
end
|
||||
|
||||
# Truncates a string to a specific length and adds ... at the end
|
||||
def truncate(input, size, trailing = '...')
|
||||
size = size.to_i
|
||||
trailing ||= ''
|
||||
return input if input.nil? or size <= 0 or input.length <= size or
|
||||
trailing.length >= input.length or size-trailing.length-1 >= input.length
|
||||
return "#{input[0..size-trailing.length-1]}#{trailing}"
|
||||
end
|
||||
|
||||
# Gets a random User-Agent
|
||||
#
|
||||
# @return [ String ] A random user-agent from data/user-agents.txt
|
||||
def get_random_user_agent
|
||||
user_agents = []
|
||||
f = File.open(USER_AGENTS_FILE, 'r')
|
||||
f.each_line do |line|
|
||||
# ignore comments
|
||||
next if line.empty? or line =~ /^\s*(#|\/\/)/
|
||||
user_agents << line.strip
|
||||
end
|
||||
f.close
|
||||
# return ransom user-agent
|
||||
user_agents.sample
|
||||
end
|
||||
|
||||
# Directory listing enabled on url?
|
||||
#
|
||||
# @return [ Boolean ]
|
||||
def directory_listing_enabled?(url)
|
||||
Browser.get(url.to_s).body[%r{<title>Index of}] ? true : false
|
||||
end
|
||||
|
||||
def url_encode(str)
|
||||
CGI.escape(str).gsub("+", "%20")
|
||||
end
|
||||
|
||||
121
lib/common/db_updater.rb
Normal file
121
lib/common/db_updater.rb
Normal file
@@ -0,0 +1,121 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
# DB Updater
|
||||
class DbUpdater
|
||||
FILES = %w(
|
||||
local_vulnerable_files.xml local_vulnerable_files.xsd
|
||||
timthumbs.txt user-agents.txt wp_versions.xml wp_versions.xsd
|
||||
wordpresses.json plugins.json themes.json LICENSE
|
||||
)
|
||||
|
||||
attr_reader :repo_directory
|
||||
|
||||
def initialize(repo_directory)
|
||||
@repo_directory = repo_directory
|
||||
|
||||
fail "#{repo_directory} is not writable" unless \
|
||||
Pathname.new(repo_directory).writable?
|
||||
end
|
||||
|
||||
# @return [ Hash ] The params for Typhoeus::Request
|
||||
def request_params
|
||||
{
|
||||
ssl_verifyhost: 2,
|
||||
ssl_verifypeer: true,
|
||||
accept_encoding: 'gzip, deflate',
|
||||
timeout: 300,
|
||||
connecttimeout: 20
|
||||
}
|
||||
end
|
||||
|
||||
# @return [ String ] The raw file URL associated with the given filename
|
||||
def remote_file_url(filename)
|
||||
"https://data.wpscan.org/#{filename}"
|
||||
end
|
||||
|
||||
# @return [ String ] The checksum of the associated remote filename
|
||||
def remote_file_checksum(filename)
|
||||
url = "#{remote_file_url(filename)}.sha512"
|
||||
|
||||
res = Browser.get(url, request_params)
|
||||
fail DownloadError, res if res.timed_out? || res.code != 200
|
||||
res.body.chomp
|
||||
end
|
||||
|
||||
def local_file_path(filename)
|
||||
File.join(repo_directory, "#{filename}")
|
||||
end
|
||||
|
||||
def local_file_checksum(filename)
|
||||
Digest::SHA512.file(local_file_path(filename)).hexdigest
|
||||
end
|
||||
|
||||
def backup_file_path(filename)
|
||||
File.join(repo_directory, "#{filename}.back")
|
||||
end
|
||||
|
||||
def create_backup(filename)
|
||||
return unless File.exist?(local_file_path(filename))
|
||||
FileUtils.cp(local_file_path(filename), backup_file_path(filename))
|
||||
end
|
||||
|
||||
def restore_backup(filename)
|
||||
return unless File.exist?(backup_file_path(filename))
|
||||
FileUtils.cp(backup_file_path(filename), local_file_path(filename))
|
||||
end
|
||||
|
||||
def delete_backup(filename)
|
||||
FileUtils.rm(backup_file_path(filename))
|
||||
end
|
||||
|
||||
# @return [ String ] The checksum of the downloaded file
|
||||
def download(filename)
|
||||
file_path = local_file_path(filename)
|
||||
file_url = remote_file_url(filename)
|
||||
|
||||
res = Browser.get(file_url, request_params)
|
||||
fail DownloadError, res if res.timed_out? || res.code != 200
|
||||
File.open(file_path, 'wb') { |f| f.write(res.body) }
|
||||
|
||||
local_file_checksum(filename)
|
||||
end
|
||||
|
||||
def update(verbose = false)
|
||||
FILES.each do |filename|
|
||||
begin
|
||||
puts "[+] Checking #{filename}" if verbose
|
||||
db_checksum = remote_file_checksum(filename)
|
||||
|
||||
# Checking if the file needs to be updated
|
||||
if File.exist?(local_file_path(filename)) && db_checksum == local_file_checksum(filename)
|
||||
puts ' [i] Already Up-To-Date' if verbose
|
||||
next
|
||||
end
|
||||
|
||||
puts ' [i] Needs to be updated' if verbose
|
||||
create_backup(filename)
|
||||
puts ' [i] Backup Created' if verbose
|
||||
puts ' [i] Downloading new file' if verbose
|
||||
dl_checksum = download(filename)
|
||||
puts " [i] Downloaded File Checksum: #{dl_checksum}" if verbose
|
||||
puts " [i] Database File Checksum : #{db_checksum}" if verbose
|
||||
|
||||
unless dl_checksum == db_checksum
|
||||
raise ChecksumError.new(File.read(local_file_path(filename))), "#{filename}: checksums do not match (local: #{dl_checksum} remote: #{db_checksum})"
|
||||
end
|
||||
rescue => e
|
||||
puts ' [i] Restoring Backup due to error' if verbose
|
||||
restore_backup(filename)
|
||||
raise e
|
||||
ensure
|
||||
if File.exist?(backup_file_path(filename))
|
||||
puts ' [i] Deleting Backup' if verbose
|
||||
delete_backup(filename)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# write last_update date to file
|
||||
File.write(LAST_UPDATE_FILE, Time.now)
|
||||
end
|
||||
end
|
||||
41
lib/common/errors.rb
Normal file
41
lib/common/errors.rb
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
# HTTP Error
|
||||
class HttpError < StandardError
|
||||
attr_reader :response
|
||||
|
||||
# @param [ Typhoeus::Response ] response
|
||||
def initialize(response)
|
||||
@response = response
|
||||
end
|
||||
|
||||
def failure_details
|
||||
msg = response.effective_url
|
||||
|
||||
if response.code == 0 || response.timed_out?
|
||||
msg += " (#{response.return_message})"
|
||||
else
|
||||
msg += " (status: #{response.code})"
|
||||
end
|
||||
|
||||
msg
|
||||
end
|
||||
|
||||
def message
|
||||
"HTTP Error: #{failure_details}"
|
||||
end
|
||||
end
|
||||
|
||||
# Used in the Updater
|
||||
class DownloadError < HttpError
|
||||
def message
|
||||
"Unable to get #{failure_details}"
|
||||
end
|
||||
end
|
||||
|
||||
class ChecksumError < StandardError
|
||||
attr_reader :file
|
||||
|
||||
def initialize(file)
|
||||
@file = file
|
||||
end
|
||||
end
|
||||
@@ -1,35 +1,5 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
# Since ruby 1.9.2, URI::escape is obsolete
|
||||
# See http://rosettacode.org/wiki/URL_encoding#Ruby and http://www.ruby-forum.com/topic/207489
|
||||
if RUBY_VERSION >= '1.9.2'
|
||||
module URI
|
||||
extend self
|
||||
|
||||
def escape(str)
|
||||
URI::Parser.new.escape(str)
|
||||
end
|
||||
alias :encode :escape
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
if RUBY_VERSION < '1.9'
|
||||
class Array
|
||||
# Fix for grep with symbols in ruby <= 1.8.7
|
||||
def _grep_(regexp)
|
||||
matches = []
|
||||
self.each do |value|
|
||||
value = value.to_s
|
||||
matches << value if value.match(regexp)
|
||||
end
|
||||
matches
|
||||
end
|
||||
|
||||
alias_method :grep, :_grep_
|
||||
end
|
||||
end
|
||||
|
||||
# This is used in WpItem::Existable
|
||||
module Typhoeus
|
||||
class Response
|
||||
@@ -49,60 +19,19 @@ end
|
||||
|
||||
# Override for puts to enable logging
|
||||
def puts(o = '')
|
||||
# remove color for logging
|
||||
if o.respond_to?(:gsub)
|
||||
temp = o.gsub(/\e\[\d+m(.*)?\e\[0m/, '\1')
|
||||
File.open(LOG_FILE, 'a+') { |f| f.puts(temp) }
|
||||
if $log && o.respond_to?(:gsub)
|
||||
temp = o.gsub(/\e\[\d+m/, '') # remove color for logging
|
||||
File.open($log, 'a+') { |f| f.puts(temp) }
|
||||
end
|
||||
|
||||
super(o)
|
||||
end
|
||||
|
||||
module Terminal
|
||||
class Table
|
||||
def render
|
||||
separator = Separator.new(self)
|
||||
buffer = [separator]
|
||||
unless @title.nil?
|
||||
buffer << Row.new(self, [title_cell_options])
|
||||
buffer << separator
|
||||
end
|
||||
unless @headings.cells.empty?
|
||||
buffer << @headings
|
||||
buffer << separator
|
||||
end
|
||||
buffer += @rows
|
||||
buffer << separator
|
||||
buffer.map { |r| style.margin_left + r.render }.join("\n")
|
||||
end
|
||||
alias :to_s :render
|
||||
|
||||
class Style
|
||||
@@defaults = {
|
||||
:border_x => "-", :border_y => "|", :border_i => "+",
|
||||
:padding_left => 1, :padding_right => 1,
|
||||
:margin_left => '',
|
||||
:width => nil, :alignment => nil
|
||||
}
|
||||
|
||||
attr_accessor :margin_left
|
||||
attr_accessor :border_x
|
||||
attr_accessor :border_y
|
||||
attr_accessor :border_i
|
||||
|
||||
attr_accessor :padding_left
|
||||
attr_accessor :padding_right
|
||||
|
||||
attr_accessor :width
|
||||
attr_accessor :alignment
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Numeric
|
||||
def bytes_to_human
|
||||
units = %w{B KB MB GB TB}
|
||||
e = (Math.log(self)/Math.log(1024)).floor
|
||||
s = "%.3f" % (to_f / 1024**e)
|
||||
e = (Math.log(abs)/Math.log(1024)).floor
|
||||
s = '%.3f' % (abs.to_f / 1024**e)
|
||||
s.sub(/\.?0*$/, ' ' + units[e])
|
||||
end
|
||||
end
|
||||
|
||||
28
lib/common/models/vulnerability.rb
Executable file → Normal file
28
lib/common/models/vulnerability.rb
Executable file → Normal file
@@ -35,27 +35,27 @@ class Vulnerability
|
||||
end
|
||||
# :nocov:
|
||||
|
||||
# Create the Vulnerability from the xml_node
|
||||
# Create the Vulnerability from the json_item
|
||||
#
|
||||
# @param [ Nokogiri::XML::Node ] xml_node
|
||||
# @param [ Hash ] json_item
|
||||
#
|
||||
# @return [ Vulnerability ]
|
||||
def self.load_from_xml_node(xml_node)
|
||||
def self.load_from_json_item(json_item)
|
||||
references = {}
|
||||
refs = xml_node.search('references')
|
||||
if refs
|
||||
references[:url] = refs.search('url').map(&:text)
|
||||
references[:cve] = refs.search('cve').map(&:text)
|
||||
references[:secunia] = refs.search('secunia').map(&:text)
|
||||
references[:osvdb] = refs.search('osvdb').map(&:text)
|
||||
references[:metasploit] = refs.search('metasploit').map(&:text)
|
||||
references[:exploitdb] = refs.search('exploitdb').map(&:text)
|
||||
references['id'] = [json_item['id']]
|
||||
|
||||
%w(url cve secunia osvdb metasploit exploitdb).each do |key|
|
||||
if json_item['references'][key]
|
||||
json_item['references'][key] = [json_item['references'][key]] if json_item['references'][key].class != Array
|
||||
references[key] = json_item['references'][key]
|
||||
end
|
||||
end
|
||||
|
||||
new(
|
||||
xml_node.search('title').text,
|
||||
xml_node.search('type').text,
|
||||
json_item['title'],
|
||||
json_item['type'],
|
||||
references,
|
||||
xml_node.search('fixed_in').text,
|
||||
json_item['fixed_in']
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -2,21 +2,22 @@
|
||||
|
||||
class Vulnerability
|
||||
module Output
|
||||
|
||||
# output the vulnerability
|
||||
def output
|
||||
puts ' |'
|
||||
puts ' | ' + red("* Title: #{title}")
|
||||
def output(verbose = false)
|
||||
puts
|
||||
puts critical("Title: #{title}")
|
||||
|
||||
references.each do |key, urls|
|
||||
methodname = "url_#{key}"
|
||||
|
||||
urls.each do |u|
|
||||
next unless respond_to?(methodname)
|
||||
url = send(methodname, u)
|
||||
puts ' | ' + red("* Reference: #{url}") if url
|
||||
puts " Reference: #{url}" if url
|
||||
end
|
||||
end
|
||||
if !fixed_in.empty?
|
||||
puts " | * Fixed in: #{fixed_in}"
|
||||
end
|
||||
|
||||
puts notice("Fixed in: #{fixed_in}") if fixed_in
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,28 +6,39 @@ class Vulnerability
|
||||
def url_metasploit(module_path)
|
||||
# remove leading slash
|
||||
module_path = module_path.sub(/^\//, '')
|
||||
"http://www.metasploit.com/modules/#{module_path}"
|
||||
"https://www.rapid7.com/db/modules/#{module_path}"
|
||||
end
|
||||
|
||||
def url_url(url)
|
||||
url
|
||||
end
|
||||
|
||||
def url_cve(cve)
|
||||
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-#{cve}"
|
||||
def url_cve(id)
|
||||
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-#{id}"
|
||||
end
|
||||
|
||||
def url_osvdb(id)
|
||||
"http://osvdb.org/#{id}"
|
||||
"http://osvdb.org/show/osvdb/#{id}"
|
||||
end
|
||||
|
||||
def url_secunia(id)
|
||||
"http://secunia.com/advisories/#{id}"
|
||||
"https://secunia.com/advisories/#{id}/"
|
||||
end
|
||||
|
||||
def url_exploitdb(id)
|
||||
"http://www.exploit-db.com/exploits/#{id}/"
|
||||
"https://www.exploit-db.com/exploits/#{id}/"
|
||||
end
|
||||
|
||||
def url_id(id)
|
||||
"https://wpvulndb.com/vulnerabilities/#{id}"
|
||||
end
|
||||
|
||||
def url_packetstorm(id)
|
||||
"http://packetstormsecurity.com/files/#{id}/"
|
||||
end
|
||||
|
||||
def url_securityfocus(id)
|
||||
"http://www.securityfocus.com/bid/#{id}/"
|
||||
end
|
||||
end
|
||||
end
|
||||
28
lib/common/models/wp_item.rb
Executable file → Normal file
28
lib/common/models/wp_item.rb
Executable file → Normal file
@@ -22,7 +22,7 @@ class WpItem
|
||||
# @return [ Array ]
|
||||
# Make it private ?
|
||||
def allowed_options
|
||||
[:name, :wp_content_dir, :wp_plugins_dir, :path, :version, :vulns_file]
|
||||
[:name, :wp_content_dir, :wp_plugins_dir, :path, :version, :db_file]
|
||||
end
|
||||
|
||||
# @param [ URI ] target_base_uri
|
||||
@@ -30,7 +30,6 @@ class WpItem
|
||||
#
|
||||
# @return [ WpItem ]
|
||||
def initialize(target_base_uri, options = {})
|
||||
|
||||
options[:wp_content_dir] ||= 'wp-content'
|
||||
options[:wp_plugins_dir] ||= options[:wp_content_dir] + '/plugins'
|
||||
|
||||
@@ -38,6 +37,27 @@ class WpItem
|
||||
forge_uri(target_base_uri)
|
||||
end
|
||||
|
||||
def identifier
|
||||
@identifier ||= name
|
||||
end
|
||||
|
||||
# @return [ Hash ]
|
||||
def db_data
|
||||
@db_data ||= json(db_file)[identifier] || {}
|
||||
end
|
||||
|
||||
def latest_version
|
||||
db_data['latest_version']
|
||||
end
|
||||
|
||||
def last_updated
|
||||
db_data['last_updated']
|
||||
end
|
||||
|
||||
def popular?
|
||||
db_data['popular']
|
||||
end
|
||||
|
||||
# @param [ Hash ] options
|
||||
#
|
||||
# @return [ void ]
|
||||
@@ -80,9 +100,7 @@ class WpItem
|
||||
#
|
||||
# @return [ void ]
|
||||
def path=(path)
|
||||
@path = URI.encode(
|
||||
path.gsub(/\$wp-plugins\$/i, wp_plugins_dir).gsub(/\$wp-content\$/i, wp_content_dir)
|
||||
)
|
||||
@path = path.gsub(/\$wp-plugins\$/i, wp_plugins_dir).gsub(/\$wp-content\$/i, wp_content_dir)
|
||||
end
|
||||
|
||||
# @param [ WpItem ] other
|
||||
|
||||
5
lib/common/models/wp_item/existable.rb
Executable file → Normal file
5
lib/common/models/wp_item/existable.rb
Executable file → Normal file
@@ -29,7 +29,10 @@ class WpItem
|
||||
#
|
||||
# @return [ Boolean ]
|
||||
def exists_from_response?(response, options = {})
|
||||
if [200, 401, 403].include?(response.code)
|
||||
# 301 included as some items do a self-redirect
|
||||
# Redirects to the 404 and homepage should be ignored (unless dynamic content is used)
|
||||
# by the page hashes (error_404_hash & homepage_hash)
|
||||
if [200, 401, 403, 301].include?(response.code)
|
||||
if response.has_valid_hash?(options[:error_404_hash], options[:homepage_hash])
|
||||
if options[:exclude_content]
|
||||
unless response.body.match(options[:exclude_content])
|
||||
|
||||
3
lib/common/models/wp_item/findable.rb
Executable file → Normal file
3
lib/common/models/wp_item/findable.rb
Executable file → Normal file
@@ -9,8 +9,7 @@ class WpItem
|
||||
#
|
||||
# @return [ void ]
|
||||
def found_from=(method)
|
||||
found = method[%r{find_from_(.*)}, 1]
|
||||
@found_from = found.gsub('_', ' ') if found
|
||||
@found_from = method.to_s.gsub(/find_from_/, '').gsub(/_/, ' ')
|
||||
end
|
||||
|
||||
module Findable
|
||||
|
||||
@@ -12,7 +12,9 @@ class WpItem
|
||||
|
||||
# @return [ String,nil ] The url to the readme file, nil if not found
|
||||
def readme_url
|
||||
%w{readme.txt README.txt}.each do |readme|
|
||||
# See https://github.com/wpscanteam/wpscan/pull/737#issuecomment-66375445
|
||||
# for any question about the order
|
||||
%w{readme.txt README.txt Readme.txt ReadMe.txt README.TXT readme.TXT}.each do |readme|
|
||||
url = @uri.merge(readme).to_s
|
||||
return url if url_is_200?(url)
|
||||
end
|
||||
@@ -40,7 +42,7 @@ class WpItem
|
||||
|
||||
# @return [ Boolean ]
|
||||
def has_directory_listing?
|
||||
Browser.get(@uri.to_s).body[%r{<title>Index of}] ? true : false
|
||||
directory_listing_enabled?(@uri)
|
||||
end
|
||||
|
||||
# Discover any error_log files created by WordPress
|
||||
|
||||
@@ -4,21 +4,29 @@ class WpItem
|
||||
module Output
|
||||
|
||||
# @return [ Void ]
|
||||
def output
|
||||
def output(verbose = false)
|
||||
outdated = VersionCompare.lesser?(version, latest_version) if latest_version
|
||||
|
||||
puts
|
||||
puts " | Name: #{self}" #this will also output the version number if detected
|
||||
puts info("Name: #{self}") #this will also output the version number if detected
|
||||
puts " | Latest version: #{latest_version} #{'(up to date)' if version}" if latest_version && !outdated
|
||||
puts " | Last updated: #{last_updated}" if last_updated
|
||||
puts " | Location: #{url}"
|
||||
#puts " | WordPress: #{wordpress_url}" if wordpress_org_item?
|
||||
puts ' | Directory listing enabled: Yes' if has_directory_listing?
|
||||
puts " | Readme: #{readme_url}" if has_readme?
|
||||
puts " | Changelog: #{changelog_url}" if has_changelog?
|
||||
puts warning("The version is out of date, the latest version is #{latest_version}") if latest_version && outdated
|
||||
|
||||
puts warning("Directory listing is enabled: #{url}") if has_directory_listing?
|
||||
puts warning("An error_log file has been found: #{error_log_url}") if has_error_log?
|
||||
|
||||
additional_output(verbose) if respond_to?(:additional_output)
|
||||
|
||||
if version.nil? && vulnerabilities.length > 0
|
||||
puts
|
||||
puts warning('We could not determine a version so all vulnerabilities are printed out')
|
||||
end
|
||||
|
||||
vulnerabilities.output
|
||||
|
||||
if has_error_log?
|
||||
puts ' | ' + red('[!]') + " An error_log file has been found : #{error_log_url}"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
28
lib/common/models/wp_item/versionable.rb
Executable file → Normal file
28
lib/common/models/wp_item/versionable.rb
Executable file → Normal file
@@ -13,7 +13,7 @@ class WpItem
|
||||
# This check is needed because readme_url can return nil
|
||||
if has_readme?
|
||||
response = Browser.get(readme_url)
|
||||
@version = response.body[%r{stable tag: #{WpVersion.version_pattern}}i, 1]
|
||||
@version = extract_version(response.body)
|
||||
end
|
||||
end
|
||||
@version
|
||||
@@ -22,7 +22,31 @@ class WpItem
|
||||
# @return [ String ]
|
||||
def to_s
|
||||
item_version = self.version
|
||||
"#@name#{' v' + item_version.strip if item_version}"
|
||||
"#{@name}#{' - v' + item_version.strip if item_version}"
|
||||
end
|
||||
|
||||
# Extracts the version number from a given string/body
|
||||
#
|
||||
# @return [ String ] detected version
|
||||
def extract_version(body)
|
||||
version = body[/\b(?:stable tag|version):\s*(?!trunk)([0-9a-z\.-]+)/i, 1]
|
||||
if version.nil? || version !~ /[0-9]+/
|
||||
extracted_versions = body.scan(/[=]+\s+(?:v(?:ersion)?\s*)?([0-9\.-]+)[ \ta-z0-9\(\)\.-]*[=]+/i)
|
||||
return if extracted_versions.nil? || extracted_versions.length == 0
|
||||
extracted_versions.flatten!
|
||||
# must contain at least one number
|
||||
extracted_versions = extracted_versions.select { |x| x =~ /[0-9]+/ }
|
||||
sorted = extracted_versions.sort { |x,y|
|
||||
begin
|
||||
Gem::Version.new(x) <=> Gem::Version.new(y)
|
||||
rescue
|
||||
0
|
||||
end
|
||||
}
|
||||
return sorted.last
|
||||
else
|
||||
return version
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
21
lib/common/models/wp_item/vulnerable.rb
Executable file → Normal file
21
lib/common/models/wp_item/vulnerable.rb
Executable file → Normal file
@@ -2,23 +2,23 @@
|
||||
|
||||
class WpItem
|
||||
module Vulnerable
|
||||
attr_accessor :vulns_file, :vulns_xpath
|
||||
attr_accessor :db_file, :identifier
|
||||
|
||||
# Get the vulnerabilities associated to the WpItem
|
||||
# Filters out already fixed vulnerabilities
|
||||
#
|
||||
# @return [ Vulnerabilities ]
|
||||
def vulnerabilities
|
||||
xml = xml(vulns_file)
|
||||
vulnerabilities = Vulnerabilities.new
|
||||
return @vulnerabilities if @vulnerabilities
|
||||
|
||||
xml.xpath(vulns_xpath).each do |node|
|
||||
vuln = Vulnerability.load_from_xml_node(node)
|
||||
if vulnerable_to?(vuln)
|
||||
vulnerabilities << vuln
|
||||
@vulnerabilities = Vulnerabilities.new
|
||||
|
||||
[*db_data['vulnerabilities']].each do |vulnerability|
|
||||
vulnerability = Vulnerability.load_from_json_item(vulnerability)
|
||||
@vulnerabilities << vulnerability if vulnerable_to?(vulnerability)
|
||||
end
|
||||
end
|
||||
vulnerabilities
|
||||
|
||||
@vulnerabilities
|
||||
end
|
||||
|
||||
def vulnerable?
|
||||
@@ -32,7 +32,7 @@ class WpItem
|
||||
# @return [ Boolean ]
|
||||
def vulnerable_to?(vuln)
|
||||
if version && vuln && vuln.fixed_in && !vuln.fixed_in.empty?
|
||||
unless VersionCompare::is_newer_or_same?(vuln.fixed_in, version)
|
||||
unless VersionCompare::lesser_or_equal?(vuln.fixed_in, version)
|
||||
return true
|
||||
end
|
||||
else
|
||||
@@ -41,5 +41,4 @@ class WpItem
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
9
lib/common/models/wp_plugin.rb
Executable file → Normal file
9
lib/common/models/wp_plugin.rb
Executable file → Normal file
@@ -1,17 +1,16 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
require 'wp_plugin/vulnerable'
|
||||
|
||||
class WpPlugin < WpItem
|
||||
include WpPlugin::Vulnerable
|
||||
|
||||
# Sets the @uri
|
||||
#
|
||||
# @param [ URI ] target_base_uri The URI of the wordpress blog
|
||||
#
|
||||
# @return [ void ]
|
||||
def forge_uri(target_base_uri)
|
||||
@uri = target_base_uri.merge(URI.encode(wp_plugins_dir + '/' + name + '/'))
|
||||
@uri = target_base_uri.merge("#{wp_plugins_dir}/#{url_encode(name)}/")
|
||||
end
|
||||
|
||||
def db_file
|
||||
@db_file ||= PLUGINS_FILE
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
class WpPlugin < WpItem
|
||||
module Vulnerable
|
||||
|
||||
# @return [ String ] The path to the file containing vulnerabilities
|
||||
def vulns_file
|
||||
unless @vulns_file
|
||||
@vulns_file = PLUGINS_VULNS_FILE
|
||||
end
|
||||
@vulns_file
|
||||
end
|
||||
|
||||
# @return [ String ]
|
||||
def vulns_xpath
|
||||
"//plugin[@name='#{@name}']/vulnerability"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
22
lib/common/models/wp_theme.rb
Executable file → Normal file
22
lib/common/models/wp_theme.rb
Executable file → Normal file
@@ -2,16 +2,20 @@
|
||||
|
||||
require 'wp_theme/findable'
|
||||
require 'wp_theme/versionable'
|
||||
require 'wp_theme/vulnerable'
|
||||
require 'wp_theme/info'
|
||||
require 'wp_theme/output'
|
||||
require 'wp_theme/childtheme'
|
||||
|
||||
class WpTheme < WpItem
|
||||
extend WpTheme::Findable
|
||||
include WpTheme::Versionable
|
||||
include WpTheme::Vulnerable
|
||||
include WpTheme::Info
|
||||
include WpTheme::Output
|
||||
include WpTheme::Childtheme
|
||||
|
||||
attr_writer :style_url
|
||||
attr_accessor :referenced_url
|
||||
|
||||
def allowed_options; super << :style_url end
|
||||
def allowed_options; super << :referenced_url end
|
||||
|
||||
# Sets the @uri
|
||||
#
|
||||
@@ -19,15 +23,15 @@ class WpTheme < WpItem
|
||||
#
|
||||
# @return [ void ]
|
||||
def forge_uri(target_base_uri)
|
||||
@uri = target_base_uri.merge(URI.encode(wp_content_dir + '/themes/' + name + '/'))
|
||||
@uri = target_base_uri.merge("#{wp_content_dir}/themes/#{url_encode(name)}/")
|
||||
end
|
||||
|
||||
# @return [ String ] The url to the theme stylesheet
|
||||
def style_url
|
||||
unless @style_url
|
||||
@style_url = uri.merge('style.css').to_s
|
||||
end
|
||||
@style_url
|
||||
@uri.merge('style.css').to_s
|
||||
end
|
||||
|
||||
def db_file
|
||||
@db_file ||= THEMES_FILE
|
||||
end
|
||||
end
|
||||
|
||||
37
lib/common/models/wp_theme/childtheme.rb
Normal file
37
lib/common/models/wp_theme/childtheme.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
class WpTheme < WpItem
|
||||
module Childtheme
|
||||
|
||||
def parent_theme_limit
|
||||
3
|
||||
end
|
||||
|
||||
def is_child_theme?
|
||||
return true unless @theme_template.nil?
|
||||
false
|
||||
end
|
||||
|
||||
def get_parent_theme_style_url
|
||||
if is_child_theme?
|
||||
return style_url.sub("/#{name}/style.css", "/#{@theme_template}/style.css")
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def get_parent_theme
|
||||
if is_child_theme?
|
||||
base_url = @uri.clone
|
||||
base_url.path = base_url.path.sub(/(?<url>.*\/)#{Regexp.escape(@wp_content_dir)}\/.+/, '\k<url>')
|
||||
return WpTheme.new(base_url,
|
||||
{
|
||||
name: @theme_template,
|
||||
style_url: get_parent_theme_style_url,
|
||||
wp_content_dir: @wp_content_dir
|
||||
})
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
22
lib/common/models/wp_theme/findable.rb
Executable file → Normal file
22
lib/common/models/wp_theme/findable.rb
Executable file → Normal file
@@ -11,7 +11,7 @@ class WpTheme < WpItem
|
||||
def find(target_uri)
|
||||
methods.grep(/^find_from_/).each do |method|
|
||||
if wp_theme = self.send(method, target_uri)
|
||||
wp_theme.found_from = method
|
||||
wp_theme.found_from = method.to_s
|
||||
|
||||
return wp_theme
|
||||
end
|
||||
@@ -30,21 +30,16 @@ class WpTheme < WpItem
|
||||
response = Browser.get_and_follow_location(target_uri.to_s)
|
||||
|
||||
# https + domain is optional because of relative links
|
||||
matches = %r{(?:https?://[^"']+)?/([^/]+)/themes/([^"']+)/style.css}i.match(response.body)
|
||||
if matches
|
||||
return new(
|
||||
return unless response.body =~ %r{(?:https?://[^"']+/)?([^/\s]+)/themes/([^"'/]+)[^"']*/style.css}i
|
||||
|
||||
new(
|
||||
target_uri,
|
||||
{
|
||||
name: matches[2],
|
||||
style_url: matches[0],
|
||||
wp_content_dir: matches[1]
|
||||
}
|
||||
name: Regexp.last_match[2],
|
||||
referenced_url: Regexp.last_match[0],
|
||||
wp_content_dir: Regexp.last_match[1]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# http://code.google.com/p/wpscan/issues/detail?id=141
|
||||
#
|
||||
# @param [ URI ] target_uri
|
||||
#
|
||||
# @return [ WpTheme ]
|
||||
@@ -52,7 +47,6 @@ class WpTheme < WpItem
|
||||
body = Browser.get(target_uri.to_s).body
|
||||
regexp = %r{<meta name="generator" content="([^\s"]+)\s?([^"]+)?" />\s+<meta name="generator" content="WooFramework\s?([^"]+)?" />}
|
||||
|
||||
|
||||
if matches = regexp.match(body)
|
||||
woo_theme_name = matches[1]
|
||||
woo_theme_version = matches[2]
|
||||
@@ -60,10 +54,8 @@ class WpTheme < WpItem
|
||||
|
||||
return new(
|
||||
target_uri,
|
||||
{
|
||||
name: woo_theme_name,
|
||||
version: woo_theme_version
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
34
lib/common/models/wp_theme/info.rb
Normal file
34
lib/common/models/wp_theme/info.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
class WpTheme < WpItem
|
||||
module Info
|
||||
|
||||
attr_reader :theme_name, :theme_uri, :theme_description,
|
||||
:theme_author, :theme_author_uri, :theme_template,
|
||||
:theme_license, :theme_license_uri, :theme_tags,
|
||||
:theme_text_domain
|
||||
|
||||
def parse_style
|
||||
style = Browser.get(style_url).body
|
||||
@theme_name = parse_style_tag(style, 'Theme Name')
|
||||
@theme_uri = parse_style_tag(style, 'Theme URI')
|
||||
@theme_description = parse_style_tag(style, 'Description')
|
||||
@theme_author = parse_style_tag(style, 'Author')
|
||||
@theme_author_uri = parse_style_tag(style, 'Author URI')
|
||||
@theme_template = parse_style_tag(style, 'Template')
|
||||
@theme_license = parse_style_tag(style, 'License')
|
||||
@theme_license_uri = parse_style_tag(style, 'License URI')
|
||||
@theme_tags = parse_style_tag(style, 'Tags')
|
||||
@theme_text_domain = parse_style_tag(style, 'Text Domain')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_style_tag(style, tag)
|
||||
value = style[/^\s*#{Regexp.escape(tag)}:\s*(.*)/i, 1]
|
||||
return value.strip if value
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
26
lib/common/models/wp_theme/output.rb
Normal file
26
lib/common/models/wp_theme/output.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
class WpTheme
|
||||
module Output
|
||||
|
||||
# @return [ Void ]
|
||||
def additional_output(verbose = false)
|
||||
parse_style
|
||||
|
||||
theme_desc = verbose ? @theme_description : truncate(@theme_description, 100)
|
||||
puts " | Style URL: #{style_url}"
|
||||
puts " | Referenced style.css: #{referenced_url}" if referenced_url && referenced_url != style_url
|
||||
puts " | Theme Name: #{@theme_name}" if @theme_name
|
||||
puts " | Theme URI: #{@theme_uri}" if @theme_uri
|
||||
puts " | Description: #{theme_desc}" if theme_desc
|
||||
puts " | Author: #{@theme_author}" if @theme_author
|
||||
puts " | Author URI: #{@theme_author_uri}" if @theme_author_uri
|
||||
puts " | Template: #{@theme_template}" if @theme_template and verbose
|
||||
puts " | License: #{@theme_license}" if @theme_license and verbose
|
||||
puts " | License URI: #{@theme_license_uri}" if @theme_license_uri and verbose
|
||||
puts " | Tags: #{@theme_tags}" if @theme_tags and verbose
|
||||
puts " | Text Domain: #{@theme_text_domain}" if @theme_text_domain and verbose
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
12
lib/common/models/wp_theme/versionable.rb
Executable file → Normal file
12
lib/common/models/wp_theme/versionable.rb
Executable file → Normal file
@@ -2,16 +2,8 @@
|
||||
|
||||
class WpTheme < WpItem
|
||||
module Versionable
|
||||
|
||||
def version
|
||||
unless @version
|
||||
@version = Browser.get(style_url).body[%r{Version:\s([^\s]+)}i, 1]
|
||||
|
||||
# Get Version from readme.txt
|
||||
@version ||= super
|
||||
end
|
||||
@version
|
||||
end
|
||||
|
||||
@version ||= Browser.get(style_url).body[%r{Version:\s*(?!trunk)([0-9a-z\.-]+)}i, 1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
class WpTheme < WpItem
|
||||
module Vulnerable
|
||||
|
||||
# @return [ String ] The path to the file containing vulnerabilities
|
||||
def vulns_file
|
||||
unless @vulns_file
|
||||
@vulns_file = THEMES_VULNS_FILE
|
||||
end
|
||||
@vulns_file
|
||||
end
|
||||
|
||||
# @return [ String ]
|
||||
def vulns_xpath
|
||||
"//theme[@name='#{@name}']/vulnerability"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
2
lib/common/models/wp_timthumb.rb
Executable file → Normal file
2
lib/common/models/wp_timthumb.rb
Executable file → Normal file
@@ -3,11 +3,13 @@
|
||||
require 'wp_timthumb/versionable'
|
||||
require 'wp_timthumb/existable'
|
||||
require 'wp_timthumb/output'
|
||||
require 'wp_timthumb/vulnerable'
|
||||
|
||||
class WpTimthumb < WpItem
|
||||
include WpTimthumb::Versionable
|
||||
include WpTimthumb::Existable
|
||||
include WpTimthumb::Output
|
||||
include WpTimthumb::Vulnerable
|
||||
|
||||
# @param [ WpTimthumb ] other
|
||||
#
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
class WpTimthumb < WpItem
|
||||
module Output
|
||||
|
||||
def output
|
||||
puts ' | ' + red('[!]') + " #{self}"
|
||||
def output(verbose = false)
|
||||
puts
|
||||
puts info("#{self}") #this will also output the version number if detected
|
||||
|
||||
vulnerabilities.output
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
0
lib/common/models/wp_timthumb/versionable.rb
Executable file → Normal file
0
lib/common/models/wp_timthumb/versionable.rb
Executable file → Normal file
55
lib/common/models/wp_timthumb/vulnerable.rb
Normal file
55
lib/common/models/wp_timthumb/vulnerable.rb
Normal file
@@ -0,0 +1,55 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
class WpTimthumb < WpItem
|
||||
module Vulnerable
|
||||
# @return [ Vulnerabilities ]
|
||||
def vulnerabilities
|
||||
vulns = Vulnerabilities.new
|
||||
|
||||
[:check_rce_132, :check_rce_webshot].each do |method|
|
||||
vuln = self.send(method)
|
||||
|
||||
vulns << vuln if vuln
|
||||
end
|
||||
vulns
|
||||
end
|
||||
|
||||
def check_rce_132
|
||||
rce_132_vuln unless VersionCompare.lesser_or_equal?('1.33', version)
|
||||
end
|
||||
|
||||
# Vulnerable versions : > 1.35 (or >= 2.0) and < 2.8.14
|
||||
def check_rce_webshot
|
||||
return if VersionCompare.lesser_or_equal?('2.8.14', version) || VersionCompare.lesser_or_equal?(version, '1.35')
|
||||
|
||||
response = Browser.get(uri.merge('?webshot=1&src=http://' + default_allowed_domains.sample))
|
||||
|
||||
rce_webshot_vuln unless response.body =~ /WEBSHOT_ENABLED == true/
|
||||
end
|
||||
|
||||
# @return [ Array<String> ] The default allowed domains (between the 2.0 and 2.8.13)
|
||||
def default_allowed_domains
|
||||
%w(flickr.com picasa.com img.youtube.com upload.wikimedia.org)
|
||||
end
|
||||
|
||||
# @return [ Vulnerability ] The RCE in the <= 1.32
|
||||
def rce_132_vuln
|
||||
Vulnerability.new(
|
||||
'Timthumb <= 1.32 Remote Code Execution',
|
||||
'RCE',
|
||||
{ exploitdb: ['17602'] },
|
||||
'1.33'
|
||||
)
|
||||
end
|
||||
|
||||
# @return [ Vulnerability ] The RCE due to the WebShot in the <= 2.8.13
|
||||
def rce_webshot_vuln
|
||||
Vulnerability.new(
|
||||
'Timthumb <= 2.8.13 WebShot Remote Code Execution',
|
||||
'RCE',
|
||||
{ url: ['http://seclists.org/fulldisclosure/2014/Jun/117'] },
|
||||
'2.8.14'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
35
lib/common/models/wp_user.rb
Executable file → Normal file
35
lib/common/models/wp_user.rb
Executable file → Normal file
@@ -12,10 +12,10 @@ class WpUser < WpItem
|
||||
# @return [ Array<Symbol> ]
|
||||
def allowed_options; [:id, :login, :display_name, :password] end
|
||||
|
||||
# @return [ URI ] The uri to the auhor page
|
||||
# @return [ URI ] The uri to the author page
|
||||
def uri
|
||||
if id
|
||||
return @uri.merge("?author=#{id}")
|
||||
@uri.merge("?author=#{id}")
|
||||
else
|
||||
raise 'The id is nil'
|
||||
end
|
||||
@@ -23,14 +23,39 @@ class WpUser < WpItem
|
||||
|
||||
# @return [ String ]
|
||||
def login_url
|
||||
@uri.merge('wp-login.php').to_s
|
||||
unless @login_url
|
||||
@login_url = @uri.merge('wp-login.php').to_s
|
||||
|
||||
# Let's check if the login url is redirected (to https url for example)
|
||||
if redirection = redirection(@login_url)
|
||||
@login_url = redirection
|
||||
end
|
||||
end
|
||||
|
||||
@login_url
|
||||
end
|
||||
|
||||
def redirection(url)
|
||||
redirection = nil
|
||||
response = Browser.get(url)
|
||||
|
||||
if response.code == 301 || response.code == 302
|
||||
redirection = response.headers_hash['location']
|
||||
|
||||
# Let's check if there is a redirection in the redirection
|
||||
if other_redirection = redirection(redirection)
|
||||
redirection = other_redirection
|
||||
end
|
||||
end
|
||||
|
||||
redirection
|
||||
end
|
||||
|
||||
# @return [ String ]
|
||||
def to_s
|
||||
s = "#{id}"
|
||||
s += " | #{login}" if login
|
||||
s += " | #{display_name}" if display_name
|
||||
s << " | #{login}" if login
|
||||
s << " | #{display_name}" if display_name
|
||||
s
|
||||
end
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
class WpUser < WpItem
|
||||
module BruteForcable
|
||||
|
||||
attr_reader :progress_bar
|
||||
|
||||
# Brute force the user with the wordlist supplied
|
||||
#
|
||||
# It can take a long time to queue 2 million requests,
|
||||
@@ -25,24 +27,40 @@ class WpUser < WpItem
|
||||
hydra = browser.hydra
|
||||
queue_count = 0
|
||||
found = false
|
||||
progress_bar = self.progress_bar(count_file_lines(wordlist), options)
|
||||
|
||||
File.open(wordlist).each do |password|
|
||||
password.chop!
|
||||
if wordlist == '-'
|
||||
words = ARGF
|
||||
passwords_size = 10
|
||||
options[:starting_at] = 0
|
||||
else
|
||||
words = File.open(wordlist)
|
||||
passwords_size = count_file_lines(wordlist)+1
|
||||
end
|
||||
|
||||
create_progress_bar(passwords_size, options)
|
||||
|
||||
words.each do |password|
|
||||
password.chomp!
|
||||
|
||||
# A successfull login will redirect us to the redirect_to parameter
|
||||
# Generate a random one on each request
|
||||
unless redirect_url
|
||||
random = (0...8).map { 65.+(rand(26)).chr }.join
|
||||
redirect_url = "#@uri#{random}/"
|
||||
redirect_url = "#{@uri}#{random}/"
|
||||
end
|
||||
|
||||
request = login_request(password, redirect_url)
|
||||
|
||||
request.on_complete do |response|
|
||||
progress_bar.progress += 1 if options[:show_progression] && !found
|
||||
if options[:show_progression] && !found
|
||||
progress_bar.progress += 1
|
||||
percentage = progress_bar.progress.fdiv(progress_bar.total)
|
||||
if options[:starting_at] && percentage >= 0.8
|
||||
progress_bar.total *= 2
|
||||
end
|
||||
end
|
||||
|
||||
puts "\n Trying Username : #{login} Password : #{password}" if options[:verbose]
|
||||
progress_bar.log(" Trying Username: #{login} Password: #{password}") if options[:verbose]
|
||||
|
||||
if valid_password?(response, password, redirect_url, options)
|
||||
found = true
|
||||
@@ -57,25 +75,27 @@ class WpUser < WpItem
|
||||
if queue_count >= browser.max_threads
|
||||
hydra.run
|
||||
queue_count = 0
|
||||
puts "Sent #{browser.max_threads} requests ..." if options[:verbose]
|
||||
progress_bar.log(" Sent #{browser.max_threads} request/s ...") if options[:verbose]
|
||||
end
|
||||
end
|
||||
|
||||
# run all of the remaining requests
|
||||
hydra.run
|
||||
puts if options[:show_progression] # mandatory to avoid the output of the progressbar to be overriden
|
||||
end
|
||||
|
||||
# @param [ Integer ] targets_size
|
||||
# @param [ Integer ] passwords_size
|
||||
# @param [ Hash ] options
|
||||
#
|
||||
# @return [ ProgressBar ]
|
||||
# :nocov:
|
||||
def progress_bar(passwords_size, options)
|
||||
def create_progress_bar(passwords_size, options)
|
||||
if options[:show_progression]
|
||||
ProgressBar.create(
|
||||
@progress_bar = ProgressBar.create(
|
||||
format: '%t %a <%B> (%c / %C) %P%% %e',
|
||||
title: " Brute Forcing '#{login}'",
|
||||
total: passwords_size
|
||||
total: passwords_size,
|
||||
starting_at: options[:starting_at]
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -103,23 +123,23 @@ class WpUser < WpItem
|
||||
# @return [ Boolean ]
|
||||
def valid_password?(response, password, redirect_url, options = {})
|
||||
if response.code == 302 && response.headers_hash && response.headers_hash['Location'] == redirect_url
|
||||
progression = "#{green('[SUCCESS]')} Login : #{login} Password : #{password}\n\n"
|
||||
progression = "#{info('[SUCCESS]')} Login : #{login} Password : #{password}\n\n"
|
||||
valid = true
|
||||
elsif response.body =~ /login_error/i
|
||||
verbose = "\n Incorrect login and/or password."
|
||||
verbose = "Incorrect login and/or password."
|
||||
elsif response.timed_out?
|
||||
progression = "#{red('ERROR:')} Request timed out."
|
||||
progression = critical('ERROR: Request timed out.')
|
||||
elsif response.code == 0
|
||||
progression = "#{red('ERROR:')} No response from remote server. WAF/IPS?"
|
||||
progression = critical("ERROR: No response from remote server. WAF/IPS? (#{response.return_message})")
|
||||
elsif response.code.to_s =~ /^50/
|
||||
progression = "#{red('ERROR:')} Server error, try reducing the number of threads."
|
||||
progression = critical('ERROR: Server error, try reducing the number of threads or use the --throttle option.')
|
||||
else
|
||||
progression = "#{red('ERROR:')} We received an unknown response for #{password}..."
|
||||
verbose = red(" Code: #{response.code}\n Body: #{response.body}\n")
|
||||
progression = critical("ERROR: We received an unknown response for login: #{login} and password: #{password}")
|
||||
verbose = critical(" Code: #{response.code}\n Body: #{response.body}\n")
|
||||
end
|
||||
|
||||
puts "\n " + progression if progression && options[:show_progression]
|
||||
puts verbose if verbose && options[:verbose]
|
||||
progress_bar.log(" #{progression}") if progression && options[:show_progression]
|
||||
progress_bar.log(" #{verbose}") if verbose && options[:verbose]
|
||||
|
||||
valid || false
|
||||
end
|
||||
|
||||
16
lib/common/models/wp_user/existable.rb
Executable file → Normal file
16
lib/common/models/wp_user/existable.rb
Executable file → Normal file
@@ -22,6 +22,8 @@ class WpUser < WpItem
|
||||
if response.code == 301 # login in location?
|
||||
location = response.headers_hash['Location']
|
||||
|
||||
return if location.nil? || location.empty?
|
||||
|
||||
@login = Existable.login_from_author_pattern(location)
|
||||
@display_name = Existable.display_name_from_body(
|
||||
Browser.get(location).body
|
||||
@@ -37,7 +39,9 @@ class WpUser < WpItem
|
||||
#
|
||||
# @return [ String ] The login
|
||||
def self.login_from_author_pattern(text)
|
||||
text[%r{/author/([^/\b]+)/?}i, 1]
|
||||
return unless text =~ %r{/author/([^/\b"']+)/?}i
|
||||
|
||||
Regexp.last_match[1].force_encoding('UTF-8')
|
||||
end
|
||||
|
||||
# @param [ String ] body
|
||||
@@ -49,7 +53,8 @@ class WpUser < WpItem
|
||||
|
||||
unless login
|
||||
# No Permalinks
|
||||
login = body[%r{<body class="archive author author-([^\s]+) author-(\d+)}i, 1]
|
||||
login = body[%r{<body class="archive author author-([^\s]+)[ "]}i, 1]
|
||||
login ? login.force_encoding('UTF-8') : nil
|
||||
end
|
||||
|
||||
login
|
||||
@@ -66,9 +71,12 @@ class WpUser < WpItem
|
||||
title_tag.force_encoding('UTF-8') if title_tag.encoding == Encoding::ASCII_8BIT
|
||||
title_tag = Nokogiri::HTML::DocumentFragment.parse(title_tag).to_s
|
||||
# & are not decoded with Nokogiri
|
||||
title_tag.sub!('&', '&')
|
||||
title_tag.gsub!('&', '&')
|
||||
|
||||
name = title_tag[%r{([^|«]+) }, 1]
|
||||
# replace UTF chars like » with dummy character
|
||||
title_tag.gsub!(/&#(\d+);/, '|')
|
||||
|
||||
name = title_tag[%r{([^|«»]+) }, 1]
|
||||
|
||||
return name.strip if name
|
||||
end
|
||||
|
||||
33
lib/common/models/wp_version.rb
Executable file → Normal file
33
lib/common/models/wp_version.rb
Executable file → Normal file
@@ -1,21 +1,27 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
require 'wp_version/findable'
|
||||
require 'wp_version/vulnerable'
|
||||
require 'wp_version/output'
|
||||
|
||||
class WpVersion < WpItem
|
||||
|
||||
extend WpVersion::Findable
|
||||
include WpVersion::Vulnerable
|
||||
include WpVersion::Output
|
||||
|
||||
# The version number
|
||||
attr_accessor :number
|
||||
attr_accessor :number, :metadata
|
||||
alias_method :version, :number # Needed to have the right behaviour in Vulnerable#vulnerable_to?
|
||||
|
||||
# @return [ Array ]
|
||||
def allowed_options; super << :number << :found_from end
|
||||
|
||||
def identifier
|
||||
@identifier ||= number
|
||||
end
|
||||
|
||||
def db_file
|
||||
@db_file ||= WORDPRESSES_FILE
|
||||
end
|
||||
|
||||
# @param [ WpVersion ] other
|
||||
#
|
||||
# @return [ Boolean ]
|
||||
@@ -23,4 +29,23 @@ class WpVersion < WpItem
|
||||
number == other.number
|
||||
end
|
||||
|
||||
# @return [ Array<String> ] All the stable versions from version_file
|
||||
def self.all(versions_file = WP_VERSIONS_FILE)
|
||||
Nokogiri.XML(File.open(versions_file)).css('version').reduce([]) do |a, node|
|
||||
a << node.text.to_s
|
||||
end
|
||||
end
|
||||
|
||||
# @return [ Hash ] Metadata for specific WP version from WORDPRESSES_FILE
|
||||
def metadata(version)
|
||||
json = json(db_file)
|
||||
|
||||
metadata = {}
|
||||
temp = json[version]
|
||||
if !temp.nil?
|
||||
metadata[:release_date] = temp['release_date']
|
||||
metadata[:changelog_url] = temp['changelog_url']
|
||||
end
|
||||
metadata
|
||||
end
|
||||
end
|
||||
|
||||
81
lib/common/models/wp_version/findable.rb
Executable file → Normal file
81
lib/common/models/wp_version/findable.rb
Executable file → Normal file
@@ -12,7 +12,8 @@ class WpVersion < WpItem
|
||||
#
|
||||
# @return [ WpVersion ]
|
||||
def find(target_uri, wp_content_dir, wp_plugins_dir, versions_xml)
|
||||
methods.grep(/find_from_/).each do |method|
|
||||
versions = {}
|
||||
methods.grep(/^find_from_/).each do |method|
|
||||
|
||||
if method === :find_from_advanced_fingerprinting
|
||||
version = send(method, target_uri, wp_content_dir, wp_plugins_dir, versions_xml)
|
||||
@@ -21,9 +22,21 @@ class WpVersion < WpItem
|
||||
end
|
||||
|
||||
if version
|
||||
return new(target_uri, number: version, found_from: method)
|
||||
if versions.key?(version)
|
||||
versions[version] << method.to_s
|
||||
else
|
||||
versions[version] = [ method.to_s ]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if versions.length > 0
|
||||
determined_version = versions.max_by { |k, v| v.length }
|
||||
if determined_version
|
||||
return new(target_uri, number: determined_version[0], found_from: determined_version[1].join(', '))
|
||||
end
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
@@ -31,7 +44,7 @@ class WpVersion < WpItem
|
||||
#
|
||||
# @return [ String ]
|
||||
def version_pattern
|
||||
'([^\r\n"\']+\.[^\r\n"\']+)'
|
||||
'([^\r\n"\',]+\.[^\r\n"\',]+)'
|
||||
end
|
||||
|
||||
protected
|
||||
@@ -68,7 +81,7 @@ class WpVersion < WpItem
|
||||
def find_from_meta_generator(target_uri)
|
||||
scan_url(
|
||||
target_uri,
|
||||
%r{name="generator" content="wordpress #{version_pattern}"}i
|
||||
%r{name="generator" content="wordpress #{version_pattern}.*"}i
|
||||
)
|
||||
end
|
||||
|
||||
@@ -100,18 +113,6 @@ class WpVersion < WpItem
|
||||
)
|
||||
end
|
||||
|
||||
# Attempts to find the WordPress version from,
|
||||
# the generator tag in the RSS2 feed source.
|
||||
#
|
||||
# Have not been able to find an example of this - Ryan
|
||||
#def find_from_rss2_generator(target_uri)
|
||||
# scan_url(
|
||||
# target_uri,
|
||||
# %r{<generator>http://wordpress.org/?v=(#{WpVersion.version_pattern})</generator>}i,
|
||||
# 'feed/rss/'
|
||||
# )
|
||||
#end
|
||||
|
||||
# Attempts to find the WordPress version from,
|
||||
# the generator tag in the Atom source.
|
||||
#
|
||||
@@ -126,18 +127,6 @@ class WpVersion < WpItem
|
||||
)
|
||||
end
|
||||
|
||||
# Attempts to find the WordPress version from,
|
||||
# the generator tag in the comment rss source.
|
||||
#
|
||||
# Have not been able to find an example of this - Ryan
|
||||
#def find_from_comments_rss_generator(target_uri)
|
||||
# scan_url(
|
||||
# target_uri,
|
||||
# %r{<!-- generator="WordPress/#{WpVersion.version_pattern}" -->}i,
|
||||
# 'comments/feed/'
|
||||
# )
|
||||
#end
|
||||
|
||||
# Uses data/wp_versions.xml to try to identify a
|
||||
# wordpress version.
|
||||
#
|
||||
@@ -154,8 +143,6 @@ class WpVersion < WpItem
|
||||
def find_from_advanced_fingerprinting(target_uri, wp_content_dir, wp_plugins_dir, versions_xml)
|
||||
xml = xml(versions_xml)
|
||||
|
||||
# This wp_item will take care of encoding the path
|
||||
# and replace variables like $wp-content$ & $wp-plugins$
|
||||
wp_item = WpItem.new(target_uri,
|
||||
wp_content_dir: wp_content_dir,
|
||||
wp_plugins_dir: wp_plugins_dir)
|
||||
@@ -190,8 +177,6 @@ class WpVersion < WpItem
|
||||
|
||||
# Attempts to find the WordPress version from the sitemap.xml file.
|
||||
#
|
||||
# See: http://code.google.com/p/wpscan/issues/detail?id=109
|
||||
#
|
||||
# @param [ URI ] target_uri
|
||||
#
|
||||
# @return [ String ] The version number
|
||||
@@ -216,5 +201,37 @@ class WpVersion < WpItem
|
||||
)
|
||||
end
|
||||
|
||||
def find_from_stylesheets_numbers(target_uri)
|
||||
wp_versions = WpVersion.all
|
||||
found = {}
|
||||
pattern = /\bver=([0-9\.]+)/i
|
||||
|
||||
Nokogiri::HTML(Browser.get(target_uri.to_s).body).css('link,script').each do |tag|
|
||||
%w(href src).each do |attribute|
|
||||
attr_value = tag.attribute(attribute).to_s
|
||||
|
||||
next if attr_value.nil? || attr_value.empty?
|
||||
|
||||
begin
|
||||
uri = Addressable::URI.parse(attr_value)
|
||||
rescue Addressable::URI::InvalidURIError
|
||||
next
|
||||
end
|
||||
|
||||
next unless uri.query && uri.query.match(pattern)
|
||||
|
||||
version = Regexp.last_match[1].to_s
|
||||
|
||||
found[version] ||= 0
|
||||
found[version] += 1
|
||||
end
|
||||
end
|
||||
|
||||
found.delete_if { |v, _| !wp_versions.include?(v) }
|
||||
|
||||
best_guess = found.sort_by(&:last).last
|
||||
# best_guess[0]: version number, [1] numbers of occurences
|
||||
best_guess && best_guess[1] > 1 ? best_guess[0] : nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,15 +3,26 @@
|
||||
class WpVersion < WpItem
|
||||
module Output
|
||||
|
||||
def output
|
||||
puts green('[+]') + " WordPress version #{self.number} identified from #{self.found_from}"
|
||||
def output(verbose = false)
|
||||
metadata = self.metadata(self.number)
|
||||
|
||||
puts
|
||||
if verbose
|
||||
puts info("WordPress version #{self.number} identified from #{self.found_from}")
|
||||
puts " | Released: #{metadata[:release_date]}"
|
||||
puts " | Changelog: #{metadata[:changelog_url]}"
|
||||
else
|
||||
puts info("WordPress version #{self.number} #{"(Released on #{metadata[:release_date]}) identified from #{self.found_from}" if metadata[:release_date]}")
|
||||
end
|
||||
|
||||
vulnerabilities = self.vulnerabilities
|
||||
|
||||
unless vulnerabilities.empty?
|
||||
puts
|
||||
puts red('[!]') + " #{vulnerabilities.size} vulnerabilities identified from the version number:"
|
||||
|
||||
if vulnerabilities.size == 1
|
||||
puts critical("#{vulnerabilities.size} vulnerability identified from the version number")
|
||||
else
|
||||
puts critical("#{vulnerabilities.size} vulnerabilities identified from the version number")
|
||||
end
|
||||
vulnerabilities.output
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
class WpVersion < WpItem
|
||||
module Vulnerable
|
||||
|
||||
# @return [ String ] The path to the file containing vulnerabilities
|
||||
def vulns_file
|
||||
unless @vulns_file
|
||||
@vulns_file = WP_VULNS_FILE
|
||||
end
|
||||
@vulns_file
|
||||
end
|
||||
|
||||
# @return [ String ]
|
||||
def vulns_xpath
|
||||
"//wordpress[@version='#{@number}']/vulnerability"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -2,25 +2,14 @@
|
||||
|
||||
require 'common/cache_file_store'
|
||||
|
||||
# Implementaion of a cache_key (Typhoeus::Request#hash has too many options)
|
||||
module Typhoeus
|
||||
class Request
|
||||
module Cacheable
|
||||
def cache_key
|
||||
Digest::SHA2.hexdigest("#{url}-#{options[:body]}-#{options[:method]}")[0..32]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class TyphoeusCache < CacheFileStore
|
||||
|
||||
def get(request)
|
||||
read_entry(request.cache_key)
|
||||
read_entry(request.hash.to_s)
|
||||
end
|
||||
|
||||
def set(request, response)
|
||||
write_entry(request.cache_key, response, request.cache_ttl)
|
||||
write_entry(request.hash.to_s, response, request.cache_ttl)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
require 'common/updater/updater'
|
||||
|
||||
class GitUpdater < Updater
|
||||
|
||||
def is_installed?
|
||||
%x[git #{repo_directory_arguments()} status 2>&1] =~ /On branch/ ? true : false
|
||||
end
|
||||
|
||||
# Git has not a revsion number like SVN,
|
||||
# so we will take the 7 first chars of the last commit hash
|
||||
def local_revision_number
|
||||
git_log = %x[git #{repo_directory_arguments()} log -1 2>&1]
|
||||
git_log[/commit ([0-9a-z]{7})/i, 1].to_s
|
||||
end
|
||||
|
||||
def update
|
||||
%x[git #{repo_directory_arguments()} pull]
|
||||
end
|
||||
|
||||
def has_local_changes?
|
||||
%x[git #{repo_directory_arguments()} diff --exit-code 2>&1] =~ /diff/ ? true : false
|
||||
end
|
||||
|
||||
def reset_head
|
||||
%x[git #{repo_directory_arguments()} reset --hard HEAD]
|
||||
end
|
||||
|
||||
protected
|
||||
def repo_directory_arguments
|
||||
if @repo_directory
|
||||
return "--git-dir=\"#{@repo_directory}/.git\" --work-tree=\"#{@repo_directory}\""
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,23 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
require 'common/updater/updater'
|
||||
|
||||
class SvnUpdater < Updater
|
||||
|
||||
REVISION_PATTERN = /revision="(\d+)"/i
|
||||
TRUNK_URL = 'https://github.com/wpscanteam/wpscan'
|
||||
|
||||
def is_installed?
|
||||
%x[svn info "#@repo_directory" --xml 2>&1] =~ /revision=/ ? true : false
|
||||
end
|
||||
|
||||
def local_revision_number
|
||||
local_revision = %x[svn info "#@repo_directory" --xml 2>&1]
|
||||
local_revision[REVISION_PATTERN, 1].to_s
|
||||
end
|
||||
|
||||
def update
|
||||
%x[svn up "#@repo_directory"]
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,25 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
# This class act as an absract one
|
||||
class Updater
|
||||
|
||||
attr_reader :repo_directory
|
||||
|
||||
# TODO : add a last '/ to repo_directory if it's not present
|
||||
def initialize(repo_directory = nil)
|
||||
@repo_directory = repo_directory
|
||||
end
|
||||
|
||||
def is_installed?
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def local_revision_number
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def update
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,23 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
class UpdaterFactory
|
||||
|
||||
def self.get_updater(repo_directory)
|
||||
self.available_updaters_classes().each do |updater_symbol|
|
||||
updater = Object.const_get(updater_symbol).new(repo_directory)
|
||||
|
||||
if updater.is_installed?
|
||||
return updater
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# return array of class symbols
|
||||
def self.available_updaters_classes
|
||||
Object.constants.grep(/^.+Updater$/)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -2,14 +2,18 @@
|
||||
|
||||
class VersionCompare
|
||||
|
||||
# Compares two version strings. Returns true if version1 is equal to version2
|
||||
# or when version1 is older than version2
|
||||
# Compares two version strings. Returns true if version1 <= version2
|
||||
# and false otherwise
|
||||
#
|
||||
# @param [ String ] version1
|
||||
# @param [ String ] version2
|
||||
#
|
||||
# @return [ Boolean ]
|
||||
def self.is_newer_or_same?(version1, version2)
|
||||
def self.lesser_or_equal?(version1, version2)
|
||||
# Prepend a '0' if the version starts with a '.'
|
||||
version1 = prepend_zero(version1)
|
||||
version2 = prepend_zero(version2)
|
||||
|
||||
return true if (version1 == version2)
|
||||
# Both versions must be set
|
||||
return false unless (version1 and version2)
|
||||
@@ -23,4 +27,36 @@ class VersionCompare
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
# Compares two version strings. Returns true if version1 < version2
|
||||
# and false otherwise
|
||||
#
|
||||
# @param [ String ] version1
|
||||
# @param [ String ] version2
|
||||
#
|
||||
# @return [ Boolean ]
|
||||
def self.lesser?(version1, version2)
|
||||
# Prepend a '0' if the version starts with a '.'
|
||||
version1 = prepend_zero(version1)
|
||||
version2 = prepend_zero(version2)
|
||||
|
||||
return false if (version1 == version2)
|
||||
# Both versions must be set
|
||||
return false unless (version1 and version2)
|
||||
return false if (version1.empty? or version2.empty?)
|
||||
begin
|
||||
return true if (Gem::Version.new(version1) < Gem::Version.new(version2))
|
||||
rescue ArgumentError => e
|
||||
# Example: ArgumentError: Malformed version number string a
|
||||
return false if e.message =~ /Malformed version number string/
|
||||
raise
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
# @return [ String ]
|
||||
def self.prepend_zero(version)
|
||||
return nil if version.nil?
|
||||
version[0,1] == '.' ? "0#{version}" : version
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
require 'rubygems'
|
||||
|
||||
version = RUBY_VERSION.dup
|
||||
if Gem::Version.create(version) < Gem::Version.create(1.9)
|
||||
puts "Ruby >= 1.9 required to run wpscan (You have #{version})"
|
||||
|
||||
if Gem::Version.create(version) < Gem::Version.create(MIN_RUBY_VERSION)
|
||||
puts "Ruby >= #{MIN_RUBY_VERSION} required to run wpscan (You have #{version})"
|
||||
exit(1)
|
||||
end
|
||||
|
||||
@@ -13,27 +14,29 @@ Encoding.default_external = Encoding::UTF_8
|
||||
|
||||
begin
|
||||
# Standard libs
|
||||
require 'readline'
|
||||
require 'bundler/setup' unless kali_linux?
|
||||
require 'getoptlong'
|
||||
require 'optparse' # Will replace getoptlong
|
||||
require 'uri'
|
||||
require 'time'
|
||||
require 'resolv'
|
||||
require 'xmlrpc/client'
|
||||
require 'digest/md5'
|
||||
require 'digest/sha1'
|
||||
require 'readline'
|
||||
require 'base64'
|
||||
require 'rbconfig'
|
||||
require 'pp'
|
||||
require 'shellwords'
|
||||
require 'fileutils'
|
||||
require 'pathname'
|
||||
require 'cgi'
|
||||
# Third party libs
|
||||
require 'typhoeus'
|
||||
require 'json'
|
||||
require 'yajl/json_gem'
|
||||
require 'nokogiri'
|
||||
require 'terminal-table'
|
||||
require 'ruby-progressbar'
|
||||
require 'addressable/uri'
|
||||
# Custom libs
|
||||
require 'common/browser'
|
||||
require 'common/custom_option_parser'
|
||||
|
||||
@@ -21,6 +21,29 @@ class WebSite
|
||||
@uri.to_s
|
||||
end
|
||||
|
||||
# Checks if the remote website has ssl errors
|
||||
def ssl_error?
|
||||
return false unless @uri.scheme == 'https'
|
||||
c = get_root_path_return_code
|
||||
# http://www.rubydoc.info/github/typhoeus/ethon/Ethon/Easy:return_code
|
||||
return (
|
||||
c == :ssl_connect_error ||
|
||||
c == :peer_failed_verification ||
|
||||
c == :ssl_certproblem ||
|
||||
c == :ssl_cipher ||
|
||||
c == :ssl_cacert ||
|
||||
c == :ssl_cacert_badfile ||
|
||||
c == :ssl_issuer_error ||
|
||||
c == :ssl_crl_badfile ||
|
||||
c == :ssl_engine_setfailed ||
|
||||
c == :ssl_engine_notfound
|
||||
)
|
||||
end
|
||||
|
||||
def get_root_path_return_code
|
||||
Browser.get(@uri.to_s).return_code
|
||||
end
|
||||
|
||||
# Checks if the remote website is up.
|
||||
def online?
|
||||
Browser.get(@uri.to_s).code != 0
|
||||
@@ -52,8 +75,11 @@ class WebSite
|
||||
url ||= @uri.to_s
|
||||
response = Browser.get(url)
|
||||
|
||||
redirected_uri = URI.parse(add_trailing_slash(add_http_protocol(url)))
|
||||
if response.code == 301 || response.code == 302
|
||||
redirection = response.headers_hash['location']
|
||||
redirection = redirected_uri.merge(response.headers_hash['location']).to_s
|
||||
|
||||
return redirection if url == redirection # prevents infinite loop
|
||||
|
||||
# Let's check if there is a redirection in the redirection
|
||||
if other_redirection = redirection(redirection)
|
||||
@@ -65,15 +91,18 @@ class WebSite
|
||||
end
|
||||
|
||||
# Compute the MD5 of the page
|
||||
# Comments are deleted from the page to avoid cache generation details
|
||||
# Comments and scripts are deleted from the page to avoid cache generation details
|
||||
#
|
||||
# @param [ String, Typhoeus::Response ] page The url of the response of the page
|
||||
#
|
||||
# @return [ String ] The MD5 hash of the page
|
||||
def self.page_hash(page)
|
||||
page = Browser.get(page) unless page.is_a?(Typhoeus::Response)
|
||||
|
||||
Digest::MD5.hexdigest(page.body.gsub(/<!--.*?-->/m, ''))
|
||||
page = Browser.get(page, { followlocation: true, cache_ttl: 0 }) unless page.is_a?(Typhoeus::Response)
|
||||
# remove comments
|
||||
page = page.body.gsub(/<!--.*?-->/m, '')
|
||||
# remove javascript stuff
|
||||
page = page.gsub(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/m, '')
|
||||
Digest::MD5.hexdigest(page)
|
||||
end
|
||||
|
||||
def homepage_hash
|
||||
|
||||
@@ -12,12 +12,9 @@ class WebSite
|
||||
# Gets a robots.txt URL
|
||||
# @return [ String ]
|
||||
def robots_url
|
||||
temp = @uri.clone
|
||||
temp.path = '/robots.txt'
|
||||
temp.to_s
|
||||
@uri.clone.merge('robots.txt').to_s
|
||||
end
|
||||
|
||||
|
||||
# Parse robots.txt
|
||||
# @return [ Array ] URLs generated from robots.txt
|
||||
def parse_robots_txt
|
||||
@@ -31,6 +28,7 @@ class WebSite
|
||||
if entries
|
||||
entries.flatten!
|
||||
entries.compact.sort!
|
||||
entries.uniq!
|
||||
wordpress_path = @uri.path
|
||||
RobotsTxt.known_dirs.each do |d|
|
||||
entries.delete(d)
|
||||
@@ -42,9 +40,9 @@ class WebSite
|
||||
entries.each do |d|
|
||||
begin
|
||||
temp = @uri.clone
|
||||
temp.path = d
|
||||
temp.path = d.strip
|
||||
rescue URI::Error
|
||||
temp = d
|
||||
temp = d.strip
|
||||
end
|
||||
return_object << temp.to_s
|
||||
end
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
require 'web_site'
|
||||
require 'wp_target/malwares'
|
||||
require 'wp_target/wp_readme'
|
||||
require 'wp_target/wp_registrable'
|
||||
require 'wp_target/wp_config_backup'
|
||||
require 'wp_target/wp_must_use_plugins'
|
||||
require 'wp_target/wp_login_protection'
|
||||
require 'wp_target/wp_custom_directories'
|
||||
require 'wp_target/wp_full_path_disclosure'
|
||||
|
||||
class WpTarget < WebSite
|
||||
include WpTarget::Malwares
|
||||
include WpTarget::WpReadme
|
||||
include WpTarget::WpRegistrable
|
||||
include WpTarget::WpConfigBackup
|
||||
include WpTarget::WpMustUsePlugins
|
||||
include WpTarget::WpLoginProtection
|
||||
include WpTarget::WpCustomDirectories
|
||||
include WpTarget::WpFullPathDisclosure
|
||||
@@ -21,14 +21,20 @@ class WpTarget < WebSite
|
||||
attr_reader :verbose
|
||||
|
||||
def initialize(target_url, options = {})
|
||||
raise Exception.new('target_url can not be nil or empty') if target_url.nil? || target_url == ''
|
||||
super(target_url)
|
||||
|
||||
@verbose = options[:verbose]
|
||||
@wp_content_dir = options[:wp_content_dir]
|
||||
@wp_plugins_dir = options[:wp_plugins_dir]
|
||||
@multisite = nil
|
||||
@vhost = options[:vhost]
|
||||
|
||||
Browser.instance.referer = url
|
||||
if @vhost
|
||||
Browser.instance.vhost = @vhost
|
||||
end
|
||||
|
||||
Browser.instance(options.merge(:max_threads => options[:threads]))
|
||||
end
|
||||
|
||||
# check if the target website is
|
||||
@@ -38,7 +44,14 @@ class WpTarget < WebSite
|
||||
|
||||
response = Browser.get_and_follow_location(@uri.to_s)
|
||||
|
||||
if response.body =~ /["'][^"']*\/wp-content\/[^"']*["']/i
|
||||
# Note: in the future major WPScan version, change the user-agent to see
|
||||
# if the response is a 200 ?
|
||||
fail "The target is responding with a 403, this might be due to a WAF or a plugin.\n" \
|
||||
'You should try to supply a valid user-agent via the --user-agent option or use the --random-agent option' if response.code == 403
|
||||
|
||||
dir = wp_content_dir ? wp_content_dir : 'wp-content'
|
||||
|
||||
if response.body =~ /["'][^"']*\/#{Regexp.escape(dir)}\/[^"']*["']/i
|
||||
wordpress = true
|
||||
else
|
||||
|
||||
@@ -65,9 +78,7 @@ class WpTarget < WebSite
|
||||
|
||||
# Let's check if the login url is redirected (to https url for example)
|
||||
redirection = redirection(url)
|
||||
if redirection
|
||||
url = redirection
|
||||
end
|
||||
url = redirection if redirection
|
||||
|
||||
url
|
||||
end
|
||||
@@ -93,7 +104,7 @@ class WpTarget < WebSite
|
||||
end
|
||||
# :nocov:
|
||||
|
||||
# The version is not yet considerated
|
||||
# The version is not yet considered
|
||||
#
|
||||
# @param [ String ] name
|
||||
# @param [ String ] version
|
||||
@@ -116,11 +127,21 @@ class WpTarget < WebSite
|
||||
|
||||
# @return [ String ]
|
||||
def debug_log_url
|
||||
@uri.merge("#{wp_content_dir()}/debug.log").to_s
|
||||
@uri.merge("#{wp_content_dir}/debug.log").to_s
|
||||
end
|
||||
|
||||
# @return [ String ]
|
||||
def upload_dir_url
|
||||
@uri.merge("#{wp_content_dir}/uploads/").to_s
|
||||
end
|
||||
|
||||
# @return [ String ]
|
||||
def includes_dir_url
|
||||
@uri.merge("wp-includes/").to_s
|
||||
end
|
||||
|
||||
# Script for replacing strings in wordpress databases
|
||||
# reveals databse credentials after hitting submit
|
||||
# reveals database credentials after hitting submit
|
||||
# http://interconnectit.com/124/search-and-replace-for-wordpress-databases/
|
||||
#
|
||||
# @return [ String ]
|
||||
@@ -133,4 +154,27 @@ class WpTarget < WebSite
|
||||
resp = Browser.get(search_replace_db_2_url)
|
||||
resp.code == 200 && resp.body[%r{by interconnect}i]
|
||||
end
|
||||
|
||||
# Script used to recover locked out admin users
|
||||
# http://yoast.com/emergency-wordpress-access/
|
||||
# https://codex.wordpress.org/User:MichaelH/Orphaned_Plugins_needing_Adoption/Emergency
|
||||
#
|
||||
# @return [ String ]
|
||||
def emergency_url
|
||||
@uri.merge('emergency.php').to_s
|
||||
end
|
||||
|
||||
# @return [ Boolean ]
|
||||
def emergency_exists?
|
||||
resp = Browser.get(emergency_url)
|
||||
resp.code == 200 && resp.body[%r{password}i]
|
||||
end
|
||||
|
||||
def upload_directory_listing_enabled?
|
||||
directory_listing_enabled?(upload_dir_url)
|
||||
end
|
||||
|
||||
def include_directory_listing_enabled?
|
||||
directory_listing_enabled?(includes_dir_url)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
class WpTarget < WebSite
|
||||
module Malwares
|
||||
# Used as cache :
|
||||
# nil => malwares not checked,
|
||||
# [] => no malwares,
|
||||
# otherwise array of malwares url found
|
||||
@malwares = nil
|
||||
|
||||
def has_malwares?(malwares_file_path = nil)
|
||||
!malwares(malwares_file_path).empty?
|
||||
end
|
||||
|
||||
# return array of string (url of malwares found)
|
||||
def malwares(malwares_file_path = nil)
|
||||
unless @malwares
|
||||
malwares_found = []
|
||||
malwares_file = Malwares.malwares_file(malwares_file_path)
|
||||
index_page_body = Browser.get(@uri.to_s).body
|
||||
|
||||
File.open(malwares_file, 'r') do |file|
|
||||
file.readlines.collect do |url|
|
||||
chomped_url = url.chomp
|
||||
|
||||
if chomped_url.length > 0
|
||||
malwares_found += index_page_body.scan(Malwares.malware_pattern(chomped_url))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
malwares_found.flatten!
|
||||
malwares_found.uniq!
|
||||
|
||||
@malwares = malwares_found
|
||||
end
|
||||
@malwares
|
||||
end
|
||||
|
||||
def self.malwares_file(malwares_file_path)
|
||||
malwares_file_path || DATA_DIR + '/malwares.txt'
|
||||
end
|
||||
|
||||
def self.malware_pattern(url_regex)
|
||||
# no need to escape regex here, because malware.txt contains regex
|
||||
%r{<(?:script|iframe).* src=(?:"|')(#{url_regex}[^"']*)(?:"|')[^>]*>}i
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -14,7 +14,7 @@ class WpTarget < WebSite
|
||||
queue_count = 0
|
||||
|
||||
backups.each do |file|
|
||||
file_url = @uri.merge(URI.escape(file)).to_s
|
||||
file_url = @uri.merge(url_encode(file)).to_s
|
||||
request = browser.forge_request(file_url)
|
||||
|
||||
request.on_complete do |response|
|
||||
@@ -40,9 +40,9 @@ class WpTarget < WebSite
|
||||
# @return [ Array ]
|
||||
def self.config_backup_files
|
||||
%w{
|
||||
wp-config.php~ #wp-config.php# wp-config.php.save wp-config.php.swp wp-config.php.swo wp-config.php_bak
|
||||
wp-config.bak wp-config.php.bak wp-config.save wp-config.old wp-config.php.old wp-config.php.orig
|
||||
wp-config.orig wp-config.php.original wp-config.original wp-config.txt
|
||||
wp-config.php~ #wp-config.php# wp-config.php.save .wp-config.php.swp wp-config.php.swp wp-config.php.swo
|
||||
wp-config.php_bak wp-config.bak wp-config.php.bak wp-config.save wp-config.old wp-config.php.old
|
||||
wp-config.php.orig wp-config.orig wp-config.php.original wp-config.original wp-config.txt
|
||||
} # thanks to Feross.org for these
|
||||
end
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user