����JFIFXX�����    $.' ",#(7),01444'9=82<.342  2!!22222222222222222222222222222222222222222222222222����"��4�� ���,�PG"Z_�4�˷����kjز�Z�,F+��_z�,�© �����zh6�٨�ic�fu���#ډb���_�N�?��wQ���5-�~�I���8����TK<5o�Iv-�����k�_U_�����~b�M��d����Ӝ�U�Hh��?]��E�w��Q���k�{��_}qFW7HTՑ��Y��F�?_�'ϔ��_�Ջt��=||I ��6�έ"�����D���/[�k�9���Y�8ds|\���Ҿp6�Ҵ���]��.����6�z<�v��@]�i%��$j��~�g��J>��no����pM[me�i$[����s�o�ᘨ�˸ nɜG-�ĨU�ycP�3.DB�li�;��hj���x7Z^�N�h������N3u{�:j�x�힞��#M&��jL P@_���� P��&��o8������9�����@Sz6�t7#O�ߋ �s}Yf�T���lmr����Z)'N��k�۞p����w\�Tȯ?�8`�O��i{wﭹW�[�r�� ��Q4F�׊���3m&L�=��h3����z~��#�\�l :�F,j@�� ʱ�wQT����8�"kJO���6�֚l����}���R�>ډK���]��y����&����p�}b��;N�1�m�r$�|��7�>e�@B�TM*-iH��g�D�)� E�m�|�ؘbҗ�a��Ҿ����t4���o���G��*oCN�rP���Q��@z,|?W[0�����:�n,jWiE��W��$~/�hp\��?��{(�0���+�Y8rΟ�+����>S-S����VN;�}�s?.����� w�9��˟<���Mq4�Wv'��{)0�1mB��V����W[�����8�/<� �%���wT^�5���b��)iM� pg�N�&ݝ��VO~�q���u���9� ����!��J27����$O-���! �:�%H��� ـ����y�ΠM=t{!S�� oK8������t<����è:a������[�����ա�H���~��w��Qz`�po�^ ����Q��n� �,uu�C�$ ^���,������8�#��:�6��e�|~���!�3�3.�\0��q��o�4`.|� ����y�Q�`~;�d�ׯ,��O�Zw�������`73�v�܋�<���Ȏ�� ـ4k��5�K�a�u�=9Yd��$>x�A�&�� j0� ���vF��� Y�|�y��� ~�6�@c��1vOp�Ig����4��l�OD���L����� R���c���j�_�uX6��3?nk��Wy�f;^*B� ��@�~a�`��Eu������+���6�L��.ü>��}y���}_�O�6�͐�:�YrG�X��kG�����l^w���~㒶sy��Iu�!� W ��X��N�7BV��O��!X�2����wvG�R�f�T#�����t�/?���%8�^�W�aT��G�cL�M���I��(J����1~�8�?aT ���]����AS�E��(��*E}� 2��#I/�׍qz��^t�̔���b�Yz4x���t�){ OH��+(E��A&�N�������XT��o��"�XC��'���)}�J�z�p� ��~5�}�^����+�6����w��c��Q�|Lp�d�H��}�(�.|����k��c4^�"�����Z?ȕ ��a<�L�!039C� �Eu�C�F�Ew�ç ;�n?�*o���B�8�bʝ���'#Rqf���M}7����]����s2tcS{�\icTx;�\��7K���P���ʇ Z O-��~��c>"��?�������P��E��O�8��@�8��G��Q�g�a�Վ���󁶠�䧘��_%#r�>�1�z�a��eb��qcPѵ��n���#L��� =��׀t� L�7�`��V���A{�C:�g���e@�w1 Xp3�c3�ġ����p��M"'-�@n4���fG��B3�DJ�8[Jo�ߐ���gK)ƛ��$���� ���8�3�����+���� �����6�ʻ���� ���S�kI�*KZlT _`���?��K����QK�d����B`�s}�>���`��*�>��,*@J�d�oF*����弝��O}�k��s��]��y�ߘ��c1G�V���<=�7��7����6�q�PT��tXԀ�!9*4�4Tހ3XΛex�46���Y��D ����� �BdemDa����\�_l,��G�/���֌7���Y�](�xTt^%�GE�����4�}bT���ڹ�����;Y)���B�Q��u��>J/J �⮶.�XԄ��j�ݳ�+E��d ��r�5�_D�1 ��o�� �B�x�΢�#���<��W�����8���R6�@g�M�.��� dr�D��>(otU��@x=��~v���2� ӣ�d�oBd��3�eO�6�㣷�����ݜ6��6Y��Qz`��S��{���\P�~z m5{J/L��1������<�e�ͅPu�b�]�ϔ���'������f�b� Zpw��c`"��i���BD@:)ִ�:�]��hv�E�w���T�l��P���"Ju�}��وV J��G6��. J/�Qgl߭�e�����@�z�Zev2u�)]կ�����7x���s�M�-<ɯ�c��r�v�����@��$�ޮ}lk���a���'����>x��O\�ZFu>�����ck#��&:��`�$�ai�>2Δ����l���oF[h��lE�ܺ�Πk:)���`�� $[6�����9�����kOw�\|���8}������ބ:��񶐕��I�A1/�=�2[�,�!��.}gN#�u����b��� ~��݊��}34q����d�E��Lc��$��"�[q�U�硬g^��%B �z���r�pJ�ru%v\h1Y�ne`ǥ:g���pQM~�^�Xi� ��`S�:V29.�P���V�?B�k�� AEvw%�_�9C�Q����wKekPؠ�\�;Io d�{ ߞo�c1eP����\� `����E=���@K<�Y���eڼ�J���w����{av�F�'�M�@/J��+9p���|]�����Iw &`��8���&M�hg��[�{��Xj��%��Ӓ�$��(����ʹN���<>�I���RY���K2�NPlL�ɀ)��&e����B+ь����( � �JTx���_?EZ� }@ 6�U���뙢ط�z��dWI�n` D����噥�[��uV��"�G&Ú����2g�}&m��?ċ�"����Om#��������� ��{�ON��"S�X��Ne��ysQ���@Fn��Vg���dX�~nj�]J�<�K]:��FW��b�������62�=��5f����JKw��bf�X�55��~J �%^����:�-�QIE��P��v�nZum� z � ~ə ���� ���ة����;�f��\v���g�8�1��f24;�V���ǔ�)����9���1\��c��v�/'Ƞ�w�������$�4�R-��t���� e�6�/�ġ �̕Ecy�J���u�B���<�W�ַ~�w[B1L۲�-JS΂�{���΃������A��20�c#��@ 0!1@AP"#2Q`$3V�%45a6�FRUq��� ����^7ׅ,$n�������+��F�`��2X'��0vM��p�L=������5��8������u�p~���.�`r�����\���O��,ư�0oS ��_�M�����l���4�kv\JSd���x���SW�<��Ae�IX����������$I���w�:S���y���›R��9�Q[���,�5�;�@]�%���u�@ *ro�lbI �� ��+���%m:�͇ZV�����u�̉����θau<�fc�.����{�4Ա� �Q����*�Sm��8\ujqs]{kN���)qO�y�_*dJ�b�7���yQqI&9�ԌK!�M}�R�;������S�T���1���i[U�ɵz�]��U)V�S6���3$K{�ߊ<�(� E]Զ[ǼENg�����'�\?#)Dkf��J���o��v���'�%ƞ�&K�u�!��b�35LX�Ϸ��63$K�a�;�9>,R��W��3�3� d�JeTYE.Mϧ��-�o�j3+y��y^�c�������VO�9NV\nd�1 ��!͕_)a�v;����թ�M�lWR1��)El��P;��yوÏ�u 3�k�5Pr6<�⒲l�!˞*��u־�n�!�l:����UNW ��%��Chx8vL'��X�@��*��)���̮��ˍ��� ���D-M�+J�U�kvK����+�x8��cY������?�Ԡ��~3mo��|�u@[XeY�C�\Kp�x8�oC�C�&����N�~3-H���� ��MX�s�u<`���~"WL��$8ξ��3���a�)|:@�m�\���^�`�@ҷ)�5p+��6���p�%i)P M���ngc�����#0Aruz���RL+xSS?���ʮ}()#�t��mˇ!��0}}y����<�e� �-ή�Ԩ��X������ MF���ԙ~l L.3���}�V뽺�v�����멬��Nl�)�2����^�Iq��a��M��qG��T�����c3#������3U�Ǎ���}��לS�|qa��ڃ�+���-��2�f����/��bz��ڐ�� �ݼ[2�ç����k�X�2�* �Z�d���J�G����M*9W���s{��w���T��x��y,�in�O�v��]���n����P�$�JB@=4�OTI�n��e�22a\����q�d���%�$��(���:���: /*�K[PR�fr\nڙdN���F�n�$�4�[�� U�zƶ����� �mʋ���,�ao�u 3�z� �x��Kn����\[��VFmbE;�_U��&V�Gg�]L�۪&#n%�$ɯ�dG���D�TI=�%+AB�Ru#��b4�1�»x�cs�YzڙJG��f��Il��d�eF'T� iA��T���uC�$����Y��H?����[!G`}���ͪ� �纤Hv\������j�Ex�K���!���OiƸ�Yj�+u-<���'q����uN�*�r\��+�]���<�wOZ.fp�ێ��,-*)V?j-kÊ#�`�r��dV����(�ݽBk�����G�ƛk�QmUڗe��Z���f}|����8�8��a���i��3'J�����~G_�^���d�8w������ R�`(�~�.��u���l�s+g�bv���W���lGc}��u���afE~1�Ue������Z�0�8�=e�� f@/�jqEKQQ�J��oN��J���W5~M>$6�Lt�;$ʳ{���^��6�{����v6���ķܰg�V�cnn �~z�x�«�,2�u�?cE+Ș�H؎�%�Za�)���X>uW�Tz�Nyo����s���FQƤ��$��*�&�LLXL)�1�" L��eO��ɟ�9=���:t��Z���c��Ž���Y?�ӭV�wv�~,Y��r�ۗ�|�y��GaF�����C�����.�+� ���v1���fήJ�����]�S��T��B��n5sW}y�$��~z�'�c ��8 ��� ,! �p��VN�S��N�N�q��y8z˱�A��4��*��'������2n<�s���^ǧ˭P�Jޮɏ�U�G�L�J�*#��<�V��t7�8����TĜ>��i}K%,���)[��z�21z ?�N�i�n1?T�I�R#��m-�����������������1����lA�`��fT5+��ܐ�c�q՝��ʐ��,���3�f2U�եmab��#ŠdQ�y>\��)�SLY����w#��.���ʑ�f��� ,"+�w�~�N�'�c�O�3F�������N<���)j��&��,-� �љ���֊�_�zS���TǦ����w�>��?�������n��U仆�V���e�����0���$�C�d���rP �m�׈e�Xm�Vu� �L��.�bֹ��� �[Դaզ���*��\y�8�Է:�Ez\�0�Kq�C b��̘��cө���Q��=0Y��s�N��S.���3.���O�o:���#���v7�[#߫ ��5�܎�L���Er4���9n��COWlG�^��0k�%<���ZB���aB_���������'=��{i�v�l�$�uC���mƎҝ{�c㱼�y]���W�i ��ߧc��m�H� m�"�"�����;Y�ߝ�Z�Ǔ�����:S#��|}�y�,/k�Ld� TA�(�AI$+I3��;Y*���Z��}|��ӧO��d�v��..#:n��f>�>���ȶI�TX��� 8��y����"d�R�|�)0���=���n4��6ⲑ�+��r<�O�܂~zh�z����7ܓ�HH�Ga롏���nCo�>������a ���~]���R���̲c?�6(�q�;5%� |�uj�~z8R=X��I�V=�|{v�Gj\gc��q����z�؋%M�ߍ����1y��#��@f^���^�>N�����#x#۹��6�Y~�?�dfPO��{��P�4��V��u1E1J �*|���%���JN��`eWu�zk M6���q t[�� ��g�G���v��WIG��u_ft����5�j�"�Y�:T��ɐ���*�;� e5���4����q$C��2d�}���� _S�L#m�Yp��O�.�C�;��c����Hi#֩%+) �Ӎ��ƲV���SYź��g |���tj��3�8���r|���V��1#;.SQ�A[���S������#���`n�+���$��$I �P\[�@�s��(�ED�z���P��])8�G#��0B��[ى��X�II�q<��9�~[Z멜�Z�⊔IWU&A>�P~�#��dp<�?����7���c��'~���5 ��+$���lx@�M�dm��n<=e�dyX��?{�|Aef ,|n3�<~z�ƃ�uۧ�����P��Y,�ӥQ�*g�#먙R�\���;T��i,��[9Qi歉����c>]9�� ��"�c��P�� �Md?٥��If�ت�u��k��/����F��9�c*9��Ǎ:�ØF���z�n*�@|I�ށ9����N3{'��[�'ͬ�Ҳ4��#}��!�V� Fu��,�,mTIk���v C�7v���B�6k�T9��1�*l� '~��ƞF��lU��'�M ����][ΩũJ_�{�i�I�n��$���L�� j��O�dx�����kza۪��#�E��Cl����x˘�o�����V���ɞ�ljr��)�/,�߬h�L��#��^��L�ф�,íMƁe�̩�NB�L�����iL����q�}��(��q��6IçJ$�W�E$��:������=#����(�K�B����zђ <��K(�N�۫K�w��^O{!����)�H���>x�������lx�?>Պ�+�>�W���,Ly!_�D���Ō�l���Q�!�[ �S����J��1��Ɛ�Y}��b,+�Lo�x�ɓ)����=�y�oh�@�꥟/��I��ѭ=��P�y9��� �ۍYӘ�e+�p�Jnϱ?V\SO%�(�t� ���=?MR�[Ș�����d�/ ��n�l��B�7j� ��!�;ӥ�/�[-���A�>�dN�sLj ��,ɪv��=1c�.SQ�O3�U���ƀ�ܽ�E����������̻��9G�ϷD�7(�}��Ävӌ\�y�_0[w ���<΍>����a_��[0+�L��F.�޺��f�>oN�T����q;���y\��bՃ��y�jH�<|q-eɏ�_?_9+P���Hp$�����[ux�K w�Mw��N�ی'$Y2�=��q���KB��P��~������Yul:�[<����F1�2�O���5=d����]Y�sw:���Ϯ���E��j,_Q��X��z`H1,#II ��d�wr��P˂@�ZJV����y$�\y�{}��^~���[:N����ߌ�U�������O��d�����ؾe��${p>G��3c���Ė�lʌ�� ת��[��`ϱ�-W����dg�I��ig2��� ��}s ��ؤ(%#sS@���~���3�X�nRG�~\jc3�v��ӍL��M[JB�T��s3}��j�Nʖ��W����;7��ç?=X�F=-�=����q�ߚ���#���='�c��7���ڑW�I(O+=:uxq�������������e2�zi+�kuG�R��������0�&e�n���iT^J����~\jy���p'dtG��s����O��3����9* �b#Ɋ�� p������[Bws�T�>d4�ۧs���nv�n���U���_�~,�v����ƜJ1��s�� �QIz��)�(lv8M���U=�;����56��G���s#�K���MP�=��LvyGd��}�VwWBF�'�à �?MH�U�g2�� ����!�p�7Q��j��ڴ����=��j�u��� Jn�A s���uM������e��Ɔ�Ҕ�!)'��8Ϣ�ٔ��ޝ(��Vp���צ֖d=�IC�J�Ǡ{q������kԭ�߸���i��@K����u�|�p=..�*+����x�����z[Aqġ#s2a�Ɗ���RR�)*HRsi�~�a &f��M��P����-K�L@��Z��Xy�'x�{}��Zm+���:�)�) IJ�-i�u���� ���ܒH��'�L(7�y�GӜq���� j��� 6ߌg1�g�o���,kر���tY�?W,���p���e���f�OQS��!K�۟cҒA�|ս�j�>��=⬒��˧L[�� �߿2JaB~R��u�:��Q�] �0H~���]�7��Ƽ�I���(}��cq '�ήET���q�?f�ab���ӥvr� �)o��-Q��_'����ᴎo��K������;��V���o��%���~OK ����*��b�f:���-ťIR��`B�5!RB@���ï�� �u �̯e\�_U�_������� g�ES��3�������QT��a����x����U<~�c?�*�#]�MW,[8O�a�x��]�1bC|踤�P��lw5V%�)�{t�<��d��5���0i�XSU��m:��Z�┵�i�"��1�^B�-��P�hJ��&)O��*�D��c�W��vM��)����}���P��ܗ-q����\mmζZ-l@�}��a��E�6��F�@��&Sg@���ݚ�M����� ȹ 4����#p�\H����dYDo�H���"��\��..R�B�H�z_�/5˘����6��KhJR��P�mƶi�m���3�,#c�co��q�a)*Pt����R�m�k�7x�D�E�\Y�閣_X�<���~�)���c[[�BP����6�Yq���S��0����%_����;��Àv�~�| VS؇ ��'O0��F0��\���U�-�d@�����7�SJ*z��3n��y��P����O���������m�~�P�3|Y��ʉr#�C�<�G~�.,! ���bqx���h~0=��!ǫ�jy����l�O,�[B��~��|9��ٱ����Xly�#�i�B��g%�S��������tˋ���e���ې��\[d�t)��.+u�|1 ������#�~Oj����hS�%��i.�~X���I�H�m��0n���c�1uE�q��cF�RF�o���7� �O�ꮧ� ���ۛ{��ʛi5�rw?׌#Qn�TW��~?y$��m\�\o����%W� ?=>S�N@�� �Ʈ���R����N�)�r"C�:��:����� �����#��qb��Y�. �6[��2K����2u�Ǧ�HYR��Q�MV��� �G�$��Q+.>�����nNH��q�^��� ����q��mM��V��D�+�-�#*�U�̒ ���p욳��u:�������IB���m���PV@O���r[b= �� ��1U�E��_Nm�yKbN�O���U�}�the�`�|6֮P>�\2�P�V���I�D�i�P�O;�9�r�mAHG�W�S]��J*�_�G��+kP�2����Ka�Z���H�'K�x�W�MZ%�O�YD�Rc+o��?�q��Ghm��d�S�oh�\�D�|:W������UA�Qc yT�q������~^�H��/��#p�CZ���T�I�1�ӏT����4��"�ČZ�����}��`w�#�*,ʹ�� ��0�i��課�Om�*�da��^gJ݅{���l�e9uF#T�ֲ��̲�ٞC"�q���ߍ ոޑ�o#�XZTp����@ o�8��(jd��xw�]�,f���`~�|,s��^����f�1���t��|��m�򸄭/ctr��5s��7�9Q�4�H1꠲BB@l9@���C�����+�wp�xu�£Yc�9��?`@#�o�mH�s2��)�=��2�.�l����jg�9$�Y�S�%*L������R�Y������7Z���,*=�䷘$�������arm�o�ϰ���UW.|�r�uf����IGw�t����Zwo��~5 ��YյhO+=8fF�)�W�7�L9lM�̘·Y���֘YLf�큹�pRF���99.A �"wz��=E\Z���'a� 2��Ǚ�#;�'}�G���*��l��^"q��+2FQ� hj��kŦ��${���ޮ-�T�٭cf�|�3#~�RJ����t��$b�(R��(����r���dx� >U b�&9,>���%E\� Ά�e�$��'�q't��*�א���ެ�b��-|d���SB�O�O��$�R+�H�)�܎�K��1m`;�J�2�Y~9��O�g8=vqD`K[�F)k�[���1m޼c��n���]s�k�z$@��)!I �x՝"v��9=�ZA=`Ɠi �:�E��)`7��vI��}d�YI�_ �o�:ob���o ���3Q��&D&�2=�� �Ά��;>�h����y.*ⅥS������Ӭ�+q&����j|UƧ����}���J0��WW< ۋS�)jQR�j���Ư��rN)�Gű�4Ѷ(�S)Ǣ�8��i��W52���No˓� ۍ%�5brOn�L�;�n��\G����=�^U�dI���8$�&���h��'���+�(������cȁ߫k�l��S^���cƗjԌE�ꭔ��gF���Ȓ��@���}O���*;e�v�WV���YJ\�]X'5��ղ�k�F��b 6R�o՜m��i N�i����>J����?��lPm�U��}>_Z&�KK��q�r��I�D�Չ~�q�3fL�:S�e>���E���-G���{L�6p�e,8��������QI��h��a�Xa��U�A'���ʂ���s�+טIjP�-��y�8ۈZ?J$��W�P� ��R�s�]��|�l(�ԓ��sƊi��o(��S0��Y� 8�T97.�����WiL��c�~�dxc�E|�2!�X�K�Ƙਫ਼�$((�6�~|d9u+�qd�^3�89��Y�6L�.I�����?���iI�q���9�)O/뚅����O���X��X�V��ZF[�یgQ�L��K1���RҖr@v�#��X�l��F���Нy�S�8�7�kF!A��sM���^rkp�jP�DyS$N���q��nxҍ!U�f�!eh�i�2�m���`�Y�I�9r�6� �TF���C}/�y�^���Η���5d�'��9A-��J��>{�_l+�`��A���[�'��յ�ϛ#w:݅�%��X�}�&�PSt�Q�"�-��\縵�/����$Ɨh�Xb�*�y��BS����;W�ջ_mc�����vt?2}1�;qS�d�d~u:2k5�2�R�~�z+|HE!)�Ǟl��7`��0�<�,�2*���Hl-��x�^����'_TV�gZA�'j� ^�2Ϊ��N7t�����?w�� �x1��f��Iz�C-Ȗ��K�^q�;���-W�DvT�7��8�Z�������� hK�(P:��Q- �8�n�Z���܃e貾�<�1�YT<�,�����"�6{/ �?�͟��|1�:�#g��W�>$����d��J��d�B��=��jf[��%rE^��il:��B���x���Sּ�1հ��,�=��*�7 fcG��#q� �eh?��2�7�����,�!7x��6�n�LC�4x��},Geǝ�tC.��vS �F�43��zz\��;QYC,6����~;RYS/6���|2���5���v��T��i����������mlv��������&� �nRh^ejR�LG�f���? �ۉҬܦƩ��|��Ȱ����>3����!v��i�ʯ�>�v��オ�X3e���_1z�Kȗ\<������!�8���V��]��?b�k41�Re��T�q��mz��TiOʦ�Z��Xq���L������q"+���2ۨ��8}�&N7XU7Ap�d�X��~�׿��&4e�o�F��� �H����O���č�c�� 懴�6���͉��+)��v;j��ݷ�� �UV�� i��� j���Y9GdÒJ1��詞�����V?h��l����l�cGs�ځ�������y�Ac�����\V3�? �� ܙg�>qH�S,�E�W�[�㺨�uch�⍸�O�}���a��>�q�6�n6����N6�q������N ! 1AQaq�0@����"2BRb�#Pr���3C`��Scst���$4D���%Td�� ?���N����a��3��m���C���w��������xA�m�q�m���m������$����4n淿t'��C"w��zU=D�\R+w�p+Y�T�&�պ@��ƃ��3ޯ?�Aﶂ��aŘ���@-�����Q�=���9D��ռ�ѻ@��M�V��P��܅�G5�f�Y<�u=,EC)�<�Fy'�"�&�չ�X~f��l�KԆV��?�� �W�N����=(� �;���{�r����ٌ�Y���h{�١������jW����P���Tc�����X�K�r��}���w�R��%��?���E��m�� �Y�q|����\lEE4���r���}�lsI�Y������f�$�=�d�yO����p�����yBj8jU�o�/�S��?�U��*������ˍ�0������u�q�m [�?f����a�� )Q�>����6#������� ?����0UQ����,IX���(6ڵ[�DI�MNލ�c&���υ�j\��X�R|,4��� j������T�hA�e��^���d���b<����n�� �즇�=!���3�^�`j�h�ȓr��jẕ�c�,ٞX����-����a�ﶔ���#�$��]w�O��Ӫ�1y%��L�Y<�wg#�ǝ�̗`�x�xa�t�w��»1���o7o5��>�m뭛C���Uƃߜ}�C���y1Xνm�F8�jI���]����H���ۺиE@I�i;r�8ӭ����V�F�Շ| ��&?�3|x�B�MuS�Ge�=Ӕ�#BE5G�����Y!z��_e��q�р/W>|-�Ci߇�t�1ޯќd�R3�u��g�=0 5��[?�#͏��q�cf���H��{ ?u�=?�?ǯ���}Z��z���hmΔ�BFTW�����<�q�(v� ��!��z���iW]*�J�V�z��gX֧A�q�&��/w���u�gYӘa���; �i=����g:��?2�dž6�ى�k�4�>�Pxs����}������G�9��3 ���)gG�R<>r h�$��'nc�h�P��Bj��J�ҧH� -��N1���N��?��~��}-q!=��_2hc�M��l�vY%UE�@|�v����M2�.Y[|y�"Eï��K�ZF,�ɯ?,q�?v�M 80jx�"�;�9vk�����+ ֧�� �ȺU��?�%�vcV��mA�6��Qg^M����A}�3�nl� QRN�l8�kkn�'�����(��M�7m9و�q���%ޟ���*h$Zk"��$�9��: �?U8�Sl��,,|ɒ��xH(ѷ����Gn�/Q�4�P��G�%��Ա8�N��!� �&�7�;���eKM7�4��9R/%����l�c>�x;������>��C�:�����t��h?aKX�bhe�ᜋ^�$�Iհ �hr7%F$�E��Fd���t��5���+�(M6�t����Ü�UU|zW�=a�Ts�Tg������dqP�Q����b'�m���1{|Y����X�N��b �P~��F^F:����k6�"�j!�� �I�r�`��1&�-$�Bevk:y���#yw��I0��x��=D�4��tU���P�ZH��ڠ底taP��6����b>�xa����Q�#� WeF��ŮNj�p�J* mQ�N����*I�-*�ȩ�F�g�3 �5��V�ʊ�ɮ�a��5F���O@{���NX��?����H�]3��1�Ri_u��������ѕ�� ����0��� F��~��:60�p�͈�S��qX#a�5>���`�o&+�<2�D����: �������ڝ�$�nP���*)�N�|y�Ej�F�5ټ�e���ihy�Z �>���k�bH�a�v��h�-#���!�Po=@k̆IEN��@��}Ll?j�O������߭�ʞ���Q|A07x���wt!xf���I2?Z��<ץ�T���cU�j��]��陎Ltl �}5�ϓ��$�,��O�mˊ�;�@O��jE��j(�ا,��LX���LO���Ц�90�O �.����a��nA���7������j4 ��W��_ٓ���zW�jcB������y՗+EM�)d���N�g6�y1_x��p�$Lv:��9�"z��p���ʙ$��^��JԼ*�ϭ����o���=x�Lj�6�J��u82�A�H�3$�ٕ@�=Vv�]�'�qEz�;I˼��)��=��ɯ���x �/�W(V���p�����$ �m�������u�����񶤑Oqˎ�T����r��㠚x�sr�GC��byp�G��1ߠ�w e�8�$⿄����/�M{*}��W�]˷.�CK\�ުx���/$�WPw���r� |i���&�}�{�X� �>��$-��l���?-z���g����lΆ���(F���h�vS*���b���߲ڡn,|)mrH[���a�3�ר�[1��3o_�U�3�TC�$��(�=�)0�kgP���� ��u�^=��4 �WYCҸ:��vQ�ר�X�à��tk�m,�t*��^�,�}D*� �"(�I��9R����>`�`��[~Q]�#af��i6l��8���6�:,s�s�N6�j"�A4���IuQ��6E,�GnH��zS�HO�uk�5$�I�4��ؤ�Q9�@��C����wp�BGv[]�u�Ov���0I4���\��y�����Q�Ѹ��~>Z��8�T��a��q�ޣ;z��a���/��S��I:�ܫ_�|������>=Z����8:�S��U�I�J��"IY���8%b8���H��:�QO�6�;7�I�S��J��ҌAά3��>c���E+&jf$eC+�z�;��V����� �r���ʺ������my�e���aQ�f&��6�ND��.:��NT�vm�<- u���ǝ\MvZY�N�NT��-A�>jr!S��n�O 1�3�Ns�%�3D@���`������ܟ 1�^c<���� �a�ɽ�̲�Xë#�w�|y�cW�=�9I*H8�p�^(4���՗�k��arOcW�tO�\�ƍR��8����'�K���I�Q�����?5�>[�}��yU�ײ -h��=��% q�ThG�2�)���"ו3]�!kB��*p�FDl�A���,�eEi�H�f�Ps�����5�H:�Փ~�H�0Dت�D�I����h�F3�������c��2���E��9�H��5�zԑ�ʚ�i�X�=:m�xg�hd(�v����׊�9iS��O��d@0ڽ���:�p�5�h-��t�&���X�q�ӕ,��ie�|���7A�2���O%P��E��htj��Y1��w�Ѓ!����  ���� ࢽ��My�7�\�a�@�ţ�J �4�Ȼ�F�@o�̒?4�wx��)��]�P��~�����u�����5�����7X ��9��^ܩ�U;Iꭆ 5 �������eK2�7(�{|��Y׎ �V��\"���Z�1� Z�����}��(�Ǝ"�1S���_�vE30>���p;� ΝD��%x�W�?W?v����o�^V�i�d��r[��/&>�~`�9Wh��y�;���R��� ;;ɮT��?����r$�g1�K����A��C��c��K��l:�'��3 c�ﳯ*"t8�~l��)���m��+U,z��`(�>yJ�?����h>��]��v��ЍG*�{`��;y]��I�T� ;c��NU�fo¾h���/$���|NS���1�S�"�H��V���T���4��uhǜ�]�v;���5�͠x��'C\�SBpl���h}�N����� A�Bx���%��ޭ�l��/����T��w�ʽ]D�=����K���ž�r㻠l4�S�O?=�k �M:� ��c�C�a�#ha���)�ѐxc�s���gP�iG��{+���x���Q���I= �� z��ԫ+ �8"�k�ñ�j=|����c ��y��CF��/��*9ж�h{ �?4�o� ��k�m�Q�N�x��;�Y��4膚�a�w?�6�>e]�����Q�r�:����g�,i"�����ԩA�*M�<�G��b�if��l^M��5� �Ҩ�{����6J��ZJ�����P�*�����Y���ݛu�_4�9�I8�7���������,^ToR���m4�H��?�N�S�ѕw��/S��甍�@�9H�S�T��t�ƻ���ʒU��*{Xs�@����f�����֒Li�K{H�w^���������Ϥm�tq���s� ���ք��f:��o~s��g�r��ט� �S�ѱC�e]�x���a��) ���(b-$(�j>�7q�B?ӕ�F��hV25r[7 Y� }L�R��}����*sg+��x�r�2�U=�*'WS��ZDW]�WǞ�<��叓���{�$�9Ou4��y�90-�1�'*D`�c�^o?(�9��u���ݐ��'PI&� f�Jݮ�������:wS����jfP1F:X �H�9dԯ���˝[�_54 �}*;@�ܨ�� ð�yn�T���?�ןd�#���4rG�ͨ��H�1�|-#���Mr�S3��G�3�����)�.᧏3v�z֑��r����$G"�`j �1t��x0<Ɔ�Wh6�y�6��,œ�Ga��gA����y��b��)��h�D��ß�_�m��ü �gG;��e�v��ݝ�nQ� ��C����-�*��o���y�a��M��I�>�<���]obD��"�:���G�A��-\%LT�8���c�)��+y76���o�Q�#*{�(F�⽕�y����=���rW�\p���۩�c���A���^e6��K������ʐ�cVf5$�'->���ՉN"���F�"�UQ@�f��Gb~��#�&�M=��8�ט�JNu9��D��[̤�s�o�~������ G��9T�tW^g5y$b��Y'��س�Ǵ�=��U-2 #�MC�t(�i� �lj�@Q 5�̣i�*�O����s�x�K�f��}\��M{E�V�{�υ��Ƈ�����);�H����I��fe�Lȣr�2��>��W�I�Ȃ6������i��k�� �5�YOxȺ����>��Y�f5'��|��H+��98pj�n�.O�y�������jY��~��i�w'������l�;�s�2��Y��:'lg�ꥴ)o#'Sa�a�K��Z� �m��}�`169�n���"���x��I ��*+� }F<��cГ���F�P�������ֹ*�PqX�x۩��,� ��N�� �4<-����%����:��7����W���u�`����� $�?�I��&����o��o��`v�>��P��"��l���4��5'�Z�gE���8���?��[�X�7(��.Q�-��*���ތL@̲����v��.5���[��=�t\+�CNܛ��,g�SQnH����}*F�G16���&:�t��4ُ"A��̣��$�b �|����#rs��a�����T�� ]�<�j��BS�('$�ɻ� �wP;�/�n��?�ݜ��x�F��yUn�~mL*-�������Xf�wd^�a�}��f�,=t�׵i�.2/wpN�Ep8�OР���•��R�FJ� 55TZ��T �ɭ�<��]��/�0�r�@�f��V��V����Nz�G��^���7hZi����k��3�,kN�e|�vg�1{9]_i��X5y7� 8e]�U����'�-2,���e"����]ot�I��Y_��n�(JҼ��1�O ]bXc���Nu�No��pS���Q_���_�?i�~�x h5d'�(qw52] ��'ޤ�q��o1�R!���`ywy�A4u���h<קy���\[~�4�\ X�Wt/� 6�����n�F�a8��f���z �3$�t(���q��q�x��^�XWeN'p<-v�!�{�(>ӽDP7��ո0�y)�e$ٕv�Ih'Q�EA�m*�H��RI��=:��� ���4牢) �%_iN�ݧ�l]� �Nt���G��H�L��� ɱ�g<���1V�,�J~�ٹ�"K��Q�� 9�HS�9�?@��k����r�;we݁�]I�!{ �@�G�[�"��`���J:�n]�{�cA�E����V��ʆ���#��U9�6����j�#Y�m\��q�e4h�B�7��C�������d<�?J����1g:ٳ���=Y���D�p�ц� ׈ǔ��1�]26؜oS�'��9�V�FVu�P�h�9�xc�oq�X��p�o�5��Ա5$�9W�V(�[Ak�aY錎qf;�'�[�|���b�6�Ck��)��#a#a˙��8���=äh�4��2��C��4tm^ �n'c���]GQ$[Wҿ��i���vN�{Fu ��1�gx��1┷���N�m��{j-,��x�� Ūm�ЧS�[�s���Gna���䑴�� x�p 8<������97�Q���ϴ�v�aϚG��Rt�Һ׈�f^\r��WH�JU�7Z���y)�vg=����n��4�_)y��D'y�6�]�c�5̪�\� �PF�k����&�c;��cq�$~T�7j ���nç]�<�g ":�to�t}�159�<�/�8������m�b�K#g'I'.W�����6��I/��>v��\�MN��g���m�A�yQL�4u�Lj�j9��#44�t��l^�}L����n��R��!��t��±]��r��h6ٍ>�yҏ�N��fU�� ���� Fm@�8}�/u��jb9������he:A�y�ծw��GpΧh�5����l}�3p468��)U��d��c����;Us/�֔�YX�1�O2��uq�s��`hwg�r~�{ R��mhN��؎*q 42�*th��>�#���E����#��Hv�O����q�}�����6�e��\�,Wk�#���X��b>��p}�դ��3���T5��†��6��[��@�P�y*n��|'f�֧>�lư΂�̺����SU�'*�q�p�_S�����M�� '��c�6�����m�� ySʨ;M��r���Ƌ�m�Kxo,���Gm�P��A�G�:��i��w�9�}M(�^�V��$ǒ�ѽ�9���|���� �a����J�SQ�a���r�B;����}���ٻ֢�2�%U���c�#�g���N�a�ݕ�'�v�[�OY'��3L�3�;,p�]@�S��{ls��X�'���c�jw�k'a�.��}�}&�� �dP�*�bK=ɍ!����;3n�gΊU�ߴmt�'*{,=SzfD� A��ko~�G�aoq�_mi}#�m�������P�Xhύ����mxǍ�΂���巿zf��Q���c���|kc�����?���W��Y�$���_Lv����l߶��c���`?����l�j�ݲˏ!V��6����U�Ђ(A���4y)H���p�Z_�x��>���e��R��$�/�`^'3qˏ�-&Q�=?��CFVR �D�fV�9��{�8g�������n�h�(P"��6�[�D���< E�����~0<@�`�G�6����Hг�cc�� �c�K.5��D��d�B���`?�XQ��2��ٿyqo&+�1^� DW�0�ꊩ���G�#��Q�nL3��c���������/��x ��1�1[y�x�პCW��C�c�UĨ80�m�e�4.{�m��u���I=��f�����0QRls9���f���������9���~f�����Ǩ��a�"@�8���ȁ�Q����#c�ic������G��$���G���r/$W�(��W���V�"��m�7�[m�A�m����bo��D� j����۳� l���^�k�h׽����� ��#� iXn�v��eT�k�a�^Y�4�BN��ĕ��0 !01@Q"2AaPq3BR������?���@4�Q�����T3,���㺠�W�[=JK�Ϟ���2�r^7��vc�:�9 �E�ߴ�w�S#d���Ix��u��:��Hp��9E!�� V 2;73|F��9Y���*ʬ�F��D����u&���y؟��^EA��A��(ɩ���^��GV:ݜDy�`��Jr29ܾ�㝉��[���E;Fzx��YG��U�e�Y�C���� ����v-tx����I�sם�Ę�q��Eb�+P\ :>�i�C'�;�����k|z�رn�y]�#ǿb��Q��������w�����(�r|ӹs��[�D��2v-%��@;�8<a���[\o[ϧw��I!��*0�krs)�[�J9^��ʜ��p1)� "��/_>��o��<1����A�E�y^�C��`�x1'ܣn�p��s`l���fQ��):�l����b>�Me�jH^?�kl3(�z:���1ŠK&?Q�~�{�ٺ�h�y���/�[��V�|6��}�KbX����mn[-��7�5q�94�������dm���c^���h� X��5��<�eޘ>G���-�}�دB�ޟ� ��|�rt�M��V+�]�c?�-#ڛ��^ǂ}���Lkr���O��u�>�-D�ry� D?:ޞ�U��ǜ�7�V��?瓮�"�#���r��չģVR;�n���/_� ؉v�ݶe5d�b9��/O��009�G���5n�W����JpA�*�r9�>�1��.[t���s�F���nQ� V 77R�]�ɫ8����_0<՜�IF�u(v��4��F�k�3��E)��N:��yڮe��P�`�1}�$WS��J�SQ�N�j�ٺ��޵�#l���ј(�5=��5�lǏmoW�v-�1����v,W�mn��߀$x�<����v�j(����c]��@#��1������Ǔ���o'��u+����;G�#�޸��v-lη��/(`i⣍Pm^���ԯ̾9Z��F��������n��1��� ��]�[��)�'������:�֪�W��FC����� �B9،!?���]��V��A�Վ�M��b�w��G F>_DȬ0¤�#�QR�[V��kz���m�w�"��9ZG�7'[��=�Q����j8R?�zf�\a�=��O�U����*oB�A�|G���2�54 �p��.w7� �� ��&������ξxGHp� B%��$g�����t�Џ򤵍z���HN�u�Я�-�'4��0��;_��3 !01"@AQa2Pq#3BR������?��ʩca��en��^��8���<�u#��m*08r��y�N"�<�Ѳ0��@\�p��� �����Kv�D��J8�Fҽ� �f�Y��-m�ybX�NP����}�!*8t(�OqѢ��Q�wW�K��ZD��Δ^e��!� ��B�K��p~�����e*l}z#9ң�k���q#�Ft�o��S�R����-�w�!�S���Ӥß|M�l޶V��!eˈ�8Y���c�ЮM2��tk���� ������J�fS����Ö*i/2�����n]�k�\���|4yX�8��U�P.���Ы[���l��@"�t�<������5�lF���vU�����W��W��;�b�cД^6[#7@vU�xgZv��F�6��Q,K�v��� �+Ъ��n��Ǣ��Ft���8��0��c�@�!�Zq s�v�t�;#](B��-�nῃ~���3g������5�J�%���O������n�kB�ĺ�.r��+���#�N$?�q�/�s�6��p��a����a��J/��M�8��6�ܰ"�*������ɗud"\w���aT(����[��F��U՛����RT�b���n�*��6���O��SJ�.�ij<�v�MT��R\c��5l�sZB>F��<7�;EA��{��E���Ö��1U/�#��d1�a�n.1ě����0�ʾR�h��|�R��Ao�3�m3 ��%�� ���28Q� ��y��φ���H�To�7�lW>����#i`�q���c����a��� �m,B�-j����݋�'mR1Ήt�>��V��p���s�0IbI�C.���1R�ea�����]H�6����������4B>��o��](��$B���m�����a�!=��?�B� K�Ǿ+�Ծ"�n���K��*��+��[T#�{E�J�S����Q�����s�5�:�U�\wĐ�f�3����܆&�)����I���Ԇw��E T�lrTf6Q|R�h:��[K�� �z��c֧�G�C��%\��_�a�84��HcO�bi��ؖV��7H �)*ģK~Xhչ0��4?�0��� �E<���}3���#���u�?�� ��|g�S�6ꊤ�|�I#Hڛ� �ա��w�X��9��7���Ŀ%�SL��y6č��|�F�a 8���b��$�sק�h���b9RAu7�˨p�Č�_\*w��묦��F ����4D~�f����|(�"m���NK��i�S�>�$d7SlA��/�²����SL��|6N�}���S�˯���g��]6��; �#�.��<���q'Q�1|KQ$�����񛩶"�$r�b:���N8�w@��8$�� �AjfG|~�9F ���Y��ʺ��Bwؒ������M:I岎�G��`s�YV5����6��A �b:�W���G�q%l�����F��H���7�������Fsv7��k�� 403WebShell
403Webshell
Server IP : 51.161.54.47  /  Your IP : 216.73.216.143
Web Server : Apache/2.4.68 (Unix) OpenSSL/1.1.1k
System : Linux host.ditinformatica.ar 4.18.0-553.153.1.el8_10.x86_64 #1 SMP Thu Aug 6 00:53:12 EDT 2026 x86_64
User : kalaycom ( 1021)
PHP Version : 7.4.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /usr/share/nmap/nselib/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /usr/share/nmap/nselib/brute.lua
---
-- The brute library is an attempt to create a common framework for performing
-- password guessing against remote services.
--
-- The library currently attempts to parallelize the guessing by starting
-- a number of working threads and increasing that number gradually until
-- brute.threads limit is reached. The starting number of threads can be set
-- with brute.start argument, it defaults to 5. The brute.threads argument
-- defaults to 20. It is worth noticing that the number of working threads
-- will grow exponentially until any error occurs, after that the engine
-- will switch to linear growth.
--
-- The library contains the following classes:
-- * <code>Engine</code>
-- ** The actual engine doing the brute-forcing .
-- * <code>Error</code>
-- ** Class used to return errors back to the engine.
-- * <code>Options</code>
-- ** Stores any options that should be used during brute-forcing.
--
-- In order to make use of the framework a script needs to implement a Driver
-- class. The Driver class is then to be passed as a parameter to the Engine
-- constructor, which creates a new instance for each guess. The Driver class
-- SHOULD implement the following four methods:
--
-- <code>
-- Driver:login = function( self, username, password )
-- Driver:check = function( self )
-- Driver:connect = function( self )
-- Driver:disconnect = function( self )
-- </code>
--
-- The <code>login</code> method does not need a lot of explanation. The login
-- function should return two parameters. If the login was successful it should
-- return true and a <code>creds.Account</code>. If the login was a failure it
-- should return false and a <code>brute.Error</code>. The driver can signal
-- the Engine to retry a set of credentials by calling the Error objects
-- <code>setRetry</code> method. It may also signal the Engine to abort all
-- password guessing by calling the Error objects <code>setAbort</code> method.
-- Finally, the driver can notify the Engine about protocol related exception
-- (like the ftp code 421 "Too many connections") by calling
-- <code>setReduce</code> method. The latter will signal the Engine to reduce
-- the number of running worker threads.
--
-- The following example code demonstrates how the Error object can be used.
--
-- <code>
-- -- After a number of incorrect attempts VNC blocks us, so we abort
-- if ( not(status) and x:match("Too many authentication failures") ) then
--   local err = brute.Error:new( data )
--   -- signal the engine to abort
--   err:setAbort( true )
--   return false, err
-- elseif ( not(status) ) then
--   local err = brute.Error:new( "VNC handshake failed" )
--   -- This might be temporary, signal the engine to retry
--   err:setRetry( true )
--   return false, err
-- end
-- .
-- .
-- .
-- -- Return a simple error, no retry needed
-- return false, brute.Error:new( "Incorrect password" )
-- </code>
--
-- The purpose of the <code>check</code> method is to be able to determine
-- whether the script has all the information it needs, before starting the
-- brute force. It's the method where you should check, e.g., if the correct
-- database or repository URL was specified or not. On success, the
-- <code>check</code> method returns true, on failure it returns false and the
-- brute force engine aborts.
--
-- NOTE: The <code>check</code> method is deprecated and will be removed from
-- all scripts in the future. Scripts should do this check in the action
-- function instead.
--
-- The <code>connect</code> method provides the framework with the ability to
-- ensure that the thread can run once it has been dispatched a set of
-- credentials. As the sockets in NSE are limited we want to limit the risk of
-- a thread blocking, due to insufficient free sockets, after it has acquired a
-- username and password pair.
--
-- The following sample code illustrates how to implement a sample
-- <code>Driver</code> that sends each username and password over a socket.
--
-- <code>
-- Driver = {
--   new = function(self, host, port, options)
--     local o = {}
--     setmetatable(o, self)
--     self.__index = self
--     o.host = host
--     o.port = port
--     o.options = options
--     return o
--   end,
--   connect = function( self )
--     self.socket = nmap.new_socket()
--     return self.socket:connect( self.host, self.port )
--   end,
--   disconnect = function( self )
--     return self.socket:close()
--   end,
--   check = function( self )
--     return true
--   end,
--   login = function( self, username, password )
--     local status, err, data
--     status, err = self.socket:send( username .. ":" .. password)
--     status, data = self.socket:receive_bytes(1)
--
--     if ( data:match("SUCCESS") ) then
--       return true, creds.Account:new(username, password, creds.State.VALID)
--     end
--     return false, brute.Error:new( "login failed" )
--   end,
-- }
-- </code>
--
-- The following sample code illustrates how to pass the <code>Driver</code>
-- off to the brute engine.
--
-- <code>
-- action = function(host, port)
--   local options = { key1 = val1, key2 = val2 }
--   local status, accounts = brute.Engine:new(Driver, host, port, options):start()
--   if( not(status) ) then
--     return accounts
--   end
--   return stdnse.format_output( true, accounts )
-- end
-- </code>
--
-- The Engine is written with performance and reasonable resource usage in mind
-- and requires minimum extra work from a script developer. A trivial approach
-- is to spawn as many working threads as possible regardless of network
-- conditions, other scripts' needs, and protocol response. This indeed works
-- well, but only in ideal conditions. In reality there might be several
-- scripts running or only limited number of threads are allowed to use sockets
-- at any given moment (as it is in Nmap). A more intelligent approach is to
-- automate the management of Engine's running threads, so that performance
-- of other scripts does not suffer because of exhaustive brute force work.
-- This can be done on three levels: protocol, network, and resource level.
--
-- On the protocol level the developer should notify the Engine about connection
-- restrictions imposed by a server that can be learned during a protocol
-- communication. Like code 421 "To many connections" is used in FTP. Reasonably
-- in such cases we would like to reduce the number of connections to this
-- service, hence saving resources for other work and reducing the load on the
-- target server. This can be done by returning an Error object with called
-- <code>setReduce</code> method on it. The error will make the Engine reduce
-- the number of running threads.
--
-- Following is an example how it can be done for FTP brute.
--
-- <code>
-- local line = <response from the server>
--
-- if(string.match(line, "^230")) then
--   stdnse.debug1("Successful login: %s/%s", user, pass)
--   return true, creds.Account:new( user, pass, creds.State.VALID)
-- elseif(string.match(line, "^530")) then
--   return false, brute.Error:new( "Incorrect password" )
-- elseif(string.match(line, "^421")) then
--   local err = brute.Error:new("Too many connections")
--   err:setReduce(true)
--   return false, err
-- elseif(string.match(line, "^220")) then
-- elseif(string.match(line, "^331")) then
-- else
--   stdnse.debug1("WARNING: Unhandled response: %s", line)
--   local err = brute.Error:new("Unhandled response")
--   err:setRetry(true)
--   return false, err
-- end
-- </code>
--
-- On the network level we want to catch errors that can occur because of
-- network congestion or target machine specifics, say firewalled. These
-- errors can be caught as return results of operations on sockets, like
-- <code>local status, err = socket.receive()</code>. Asking a developer to
-- relay such errors to the Engine is counterproductive, and it would lead to
-- bloated scripts with lots of repetitive code. The Engine takes care of that
-- with a little help from the developer. The only thing that needs to be
-- done is to use <code>brute.new_socket()</code> instead of
-- <code>nmap.new_socket()</code> when creating a socket in a script.
--
-- NOTE: A socket created with <code>brute.new_socket()</code> will behave as
-- a regular socket when used without the brute library. The returned object
-- is a BruteSocket instance, which can be treated as a regular socket object.
--
-- Example on creating "brute" socket.
--
-- <code>
-- connect = function( self )
--   self.socket = brute.new_socket()
--   local status, err = self.socket:connect(self.host, self.port)
--   self.socket:set_timeout(arg_timeout)
--   if(not(status)) then
--     return false, brute.Error:new( "Couldn't connect to host: " .. err )
--   end
--   return true
-- end
-- </code>
--
-- On the resource level the Engine can query the current status of the NSE.
-- As of the time of writing, the only parameter used is a number of threads
-- waiting for connection (as was said before the NSE has a constraint on the
-- number of concurrent connections due to performance reasons). With a
-- running brute script the limit can be hit pretty fast, which can affect
-- performance of other scripts. To mitigate this situation resource management
-- strategy is used, and the Engine will reduce the number of working threads
-- if there are any threads waiting for connection. As a result the preference
-- for connection will be given to non brute scripts and if there are many
-- brute scripts running simultaneously, then they will not exhaust resources
-- unnecessarily.
-- This feature is enabled by default and does not require any additional work
-- from the developer.
--
-- Stagnation avoidance mechanism is implemented to alert users about services
-- that might have failed during bruteforcing. The Engine will abort if all working
-- threads have been experiencing connection errors during 100 consequentive
-- iterations of the main thread loop. If <code>brute.killstagnated</code>
-- is set to <code>false</code> the Engine will continue after issuing a
-- warning.
--
-- For a complete example of a brute implementation consult the
-- <code>svn-brute.nse</code> or <code>vnc-brute.nse</code> scripts
--
-- @args brute.useraspass guess the username as password for each user
--       (default: true)
-- @args brute.emptypass guess an empty password for each user
--       (default: false)
-- @args brute.unique make sure that each password is only guessed once
--       (default: true)
-- @args brute.firstonly stop guessing after first password is found
--       (default: false)
-- @args brute.passonly iterate over passwords only for services that provide
--       only a password for authentication. (default: false)
-- @args brute.retries the number of times to retry if recoverable failures
--       occur. (default: 2)
-- @args brute.delay the number of seconds to wait between guesses (default: 0)
-- @args brute.threads the number of initial worker threads, the number of
--       active threads will be automatically adjusted.
-- @args brute.mode can be user, pass or creds and determines what mode to run
--       the engine in.
--       * user - the unpwdb library is used to guess passwords, every password
--                password is tried for each user. (The user iterator is in the
--                outer loop)
--       * pass - the unpwdb library is used to guess passwords, each password
--                is tried for every user. (The password iterator is in the
--                outer loop)
--       * creds- a set of credentials (username and password pairs) are
--                guessed against the service. This allows for lists of known
--                or common username and password combinations to be tested.
--       If no mode is specified and the script has not added any custom
--       iterator the pass mode will be enabled.
-- @args brute.credfile a file containing username and password pairs delimited
--       by '/'
-- @args brute.guesses the number of guesses to perform against each account.
--       (default: 0 (unlimited)). The argument can be used to prevent account
--       lockouts.
-- @args brute.start the number of threads the engine will start with.
--       (default: 5).
--
-- @author Patrik Karlsson <patrik@cqure.net>
-- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html

--
-- Version 0.73
-- Created 06/12/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 07/13/2010 - v0.2 - added connect, disconnect methods to Driver
--                             <patrik@cqure.net>
-- Revised 07/21/2010 - v0.3 - documented missing argument brute.mode
-- Revised 07/23/2010 - v0.4 - fixed incorrect statistics and changed output to
--                             include statistics, and to display "no accounts
--                             found" message.
-- Revised 08/14/2010 - v0.5 - added some documentation and smaller changes per
--                             David's request.
-- Revised 08/30/2010 - v0.6 - added support for custom iterators and did some
--                             needed cleanup.
-- Revised 06/19/2011 - v0.7 - added support for creds library [Patrik]
-- Revised 07/07/2011 - v0.71- fixed some minor bugs, and changed credential
--                             iterator to use a file handle instead of table
-- Revised 07/21/2011 - v0.72- added code to allow script reporting invalid
--                             (non existing) accounts using setInvalidAccount
-- Revised 11/12/2011 - v0.73- added support for max guesses per account to
--                             prevent account lockouts.
--                             bugfix: added support for guessing the username
--                             as password per default, as suggested by the
--                             documentation.
-- Revised 07/11/2016 - v.8  - added smart resource management and error handling
--                             mechanisms. Sergey Khegay <g.sergeykhegay@gmail.com>

local coroutine = require "coroutine"
local creds = require "creds"
local io = require "io"
local nmap = require "nmap"
local os = require "os"
local stdnse = require "stdnse"
local table = require "table"
local unpwdb = require "unpwdb"
local math = require "math"
_ENV = stdnse.module("brute", stdnse.seeall)

-- Engine options that can be set by scripts
-- Supported options are:
--   * firstonly     - stop after finding the first correct password
--                     (can be set using script-arg brute.firstonly)
--   * passonly      - guess passwords only, don't supply a username
--                     (can be set using script-arg brute.passonly)
--   * max_retries   - the amount of retries to do before aborting
--                     (can be set using script-arg brute.retries)
--   * delay         - sets the delay between attempts
--                     (can be set using script-arg brute.delay)
--   * mode          - can be set to either creds, user or pass and controls
--                     whether the engine should iterate over users, passwords
--                     or fetch a list of credentials from a single file.
--                     (can be set using script-arg brute.mode)
--   * title         - changes the title of the result table where the
--                     passwords are returned.
--   * nostore       - don't store the results in the credential library
--   * max_guesses   - the maximum amount of guesses to perform for each
--                     account.
--   * useraspass    - guesses the username as password (default: true)
--   * emptypass     - guesses an empty string as password (default: false)
--   * killstagnated - abort the Engine if bruteforcing has stagnated
--                     getting too many connections errors. (default: true)
--
Options = {

  new = function (self)
    local o = {}
    setmetatable(o, self)
    self.__index = self

    o.emptypass = self.checkBoolArg("brute.emptypass", false)
    o.useraspass = self.checkBoolArg("brute.useraspass", true)
    o.firstonly = self.checkBoolArg("brute.firstonly", false)
    o.passonly = self.checkBoolArg("brute.passonly", false)
    o.killstagnated = self.checkBoolArg("brute.killstagnated", true)
    o.max_retries = tonumber(stdnse.get_script_args("brute.retries")) or 2
    o.delay = tonumber(stdnse.get_script_args("brute.delay")) or 0
    o.max_guesses = tonumber(stdnse.get_script_args("brute.guesses")) or 0

    return o
  end,

  --- Checks if a script argument is boolean true or false
  --
  -- @param arg string containing the name of the argument to check
  -- @param default boolean containing the default value
  -- @return boolean, true if argument evaluates to 1 or true, else false
  checkBoolArg = function (arg, default)
    local val = stdnse.get_script_args(arg) or default
    return (val == "true" or val == true or tonumber(val) == 1)
  end,

  --- Sets the brute mode to either iterate over users or passwords
  -- @see description for more information.
  --
  -- @param mode string containing either "user" or "password"
  -- @return status true on success else false
  -- @return err string containing the error message on failure
  setMode = function (self, mode)
    local modes = {
      "password",
      "user",
      "creds",
    }
    local supported = false

    for _, m in ipairs(modes) do
      if mode == m then
        supported = true
      end
    end

    if not supported then
      stdnse.debug1("ERROR: brute.options.setMode: mode %s not supported", mode)
      return false, "Unsupported mode"
    else
      self.mode = mode
    end
    return true
  end,

  --- Sets an option parameter
  --
  -- @param param string containing the parameter name
  -- @param value string containing the parameter value
  setOption = function (self, param, value)
    self[param] = value
  end,

  --- Set an alternate title for the result output (default: Accounts)
  --
  -- @param title string containing the title value
  setTitle = function (self, title)
    self.title = title
  end,

}

-- The account object which is to be reported back from each driver
-- The Error class, is currently only used to flag for retries
-- It also contains the error message, if one was returned from the driver.
Error = {
  retry = false,

  new = function (self, msg)
    local o = {
      msg = msg,
      done = false,
      reduce = nil,
    }
    setmetatable(o, self)
    self.__index = self
    return o
  end,

  --- Is the error recoverable?
  --
  -- @return status true if the error is recoverable, false if not
  isRetry = function (self)
    return self.retry
  end,

  --- Set the error as recoverable
  --
  -- @param r boolean true if the engine should attempt to retry the
  --        credentials, unset or false if not
  setRetry = function (self, r)
    self.retry = r
  end,

  --- Set the error as abort all threads
  --
  -- @param b boolean true if the engine should abort guessing on all threads
  setAbort = function (self, b)
    self.abort = b
  end,

  --- Was the error abortable
  --
  -- @return status true if the driver flagged the engine to abort
  isAbort = function (self)
    return self.abort
  end,

  --- Get the error message reported
  --
  -- @return msg string containing the error message
  getMessage = function (self)
    return self.msg
  end,

  --- Is the thread done?
  --
  -- @return status true if done, false if not
  isDone = function (self)
    return self.done
  end,

  --- Signals the engine that the thread is done and should be terminated
  --
  -- @param b boolean true if done, unset or false if not
  setDone = function (self, b)
    self.done = b
  end,

  -- Marks the username as invalid, aborting further guessing.
  -- @param username
  setInvalidAccount = function (self, username)
    self.invalid_account = username
  end,

  -- Checks if the error reported the account as invalid.
  -- @return username string containing the invalid account
  isInvalidAccount = function (self)
    return self.invalid_account
  end,

  --- Set the error as reduce the number of running threads
  --
  -- @param r boolean true if should reduce, unset or false if not
  setReduce = function (self, r)
    self.reduce = r
  end,

  --- Checks if the error signals to reduce the number of running threads
  --
  -- @return status true if reduce, false otherwise
  isReduce = function (self)
    if self.reduce then
      return true
    end
    return false
  end,
}

-- Auxillary data structure
Batch = {
  new = function (self, lim, stime)
    local o = {
      limit = lim or 3, -- maximum number of items
      full = false,
      data = {}, -- storage
      size = 0, -- current number of items
      start_time = stime or 0,
    }
    setmetatable(o, self)
    self.__index = self
    return o
  end,

  --- Adds new item to the vault (if possible)
  --
  -- @param obj, new object
  -- @return true if insert is successful, false if the vault is full
  add = function (self, obj)
    if self.size < self.limit then
      self.data[self.size + 1] = obj
      self.size = self.size + 1
      return true
    end

    return false
  end,

  isFull = function (self)
    if self.size >= self.limit then
      return true
    end

    return false
  end,

  getData = function (self)
    return self.data
  end,

  getSize = function (self)
    return self.size
  end,

  getStartTime = function (self)
    return self.start_time
  end,

  getLimit = function (self)
    return self.limit
  end,

  setLimit = function (self, lim)
    self.limit = lim
  end,
}


-- The brute engine, doing all the nasty work
Engine = {
  STAT_INTERVAL = 20,
  THREAD_TO_ENGINE = {},

  --- Creates a new Engine instance
  --
  -- @param driver, the driver class that should be instantiated
  -- @param host table as passed to the action method of the script
  -- @param port table as passed to the action method of the script
  -- @param options table containing any script specific options
  -- @return o new Engine instance
  new = function (self, driver, host, port, options)

    -- we want Engine.THREAD_TO_ENGINE to contain weak keys
    -- for effective garbage collection
    if getmetatable(Engine.THREAD_TO_ENGINE) == nil then
      setmetatable(Engine.THREAD_TO_ENGINE, {
          __mode = "k",
        })
    end

    local o = {
      driver = driver,
      host = host,
      port = port,
      driver_options = options,
      terminate_all = false,
      error = nil,
      counter = 0,
      threads = {},
      tps = {},
      iterator = nil,
      usernames = usernames_iterator(),
      passwords = passwords_iterator(),
      found_accounts = {},
      account_guesses = {},
      options = Options:new(),

      retry_accounts = {},
      initial_accounts_exhausted = false,
      batch = nil,
      tick = 0,
    }
    setmetatable(o, self)
    self.__index = self

    o.max_threads = tonumber(stdnse.get_script_args "brute.threads") or 20
    o.start_threads = tonumber(stdnse.get_script_args "brute.start") or 5

    return o
  end,

  --- Sets the username iterator
  --
  -- @param usernameIterator function to set as a username iterator
  setUsernameIterator = function (self, usernameIterator)
    self.usernames = usernameIterator
  end,

  --- Sets the password iterator
  --
  -- @param passwordIterator function to set as a password iterator
  setPasswordIterator = function (self, passwordIterator)
    self.passwords = passwordIterator
  end,

  --- Limit the number of worker threads
  --
  -- @param max number containing the maximum number of allowed threads
  setMaxThreads = function (self, max)
    self.max_threads = max
  end,

  --- Returns the number of non-dead threads
  --
  -- @return count number of non-dead threads
  threadCount = function (self)
    local count = 0

    for thread in pairs(self.threads) do
      if coroutine.status(thread) == "dead" then
        self.threads[thread] = nil
      else
        count = count + 1
      end
    end
    return count
  end,

  --- Calculates the number of threads that are actually doing any work
  --
  -- @return count number of threads performing activity
  activeThreads = function (self)
    local count = 0
    for thread, v in pairs(self.threads) do
      if v.guesses ~= nil then
        count = count + 1
      end
    end
    return count
  end,

  --- Iterator wrapper used to iterate over all registered iterators
  --
  -- @return iterator function
  get_next_credential = function (self)
    local function next_credential ()
      for user, pass in self.iterator do
        -- makes sure the credentials have not been tested before
        self.used_creds = self.used_creds or {}
        pass = pass or "nil"
        if not self.used_creds[user .. pass] then
          self.used_creds[user .. pass] = true
          coroutine.yield(user, pass)
        end
      end
      while true do
        coroutine.yield(nil, nil)
      end
    end
    return coroutine.wrap(next_credential)
  end,

  --- Does the actual authentication request
  --
  -- @return true on success, false on failure
  -- @return response Account on success, Error on failure
  doAuthenticate = function (self)

    local status, response
    local next_credential = self:get_next_credential()
    local tries = self.options.max_retries + 1
    local username, password
    local thread_data = Engine.getThreadData(coroutine.running())
    assert(thread_data, "Unknown coroutine is running")

    repeat
      local driver = self.driver:new(self.host, self.port, self.driver_options)

      status, response = driver:connect()

      -- Temporary workaround. Did not connect successfully
      -- due to stressed server
      if not status then
        -- We have to first check whether the response is a brute.Error
        -- since many times the connect method returns a string error instead,
        -- which could crash this thread in several places
        if response and not response.isReduce then
          -- Create a new Error
          response = Error:new("Connect error: " .. response)
          response:setRetry(true)
        end
        if response and response:isReduce() then
          local ret_creds = {}
          ret_creds.connect_phase = true
          return false, response, ret_creds
        end
      else
      -- Did we successfully connect?
        if not username and not password then
          repeat
            if #self.retry_accounts > 0 then
              -- stdnse.debug1("Using retry credentials")
              username = self.retry_accounts[#self.retry_accounts].username
              password = self.retry_accounts[#self.retry_accounts].password
              table.remove(self.retry_accounts, #self.retry_accounts)
            else
              username, password = next_credential()
            end

            thread_data.username = username
            thread_data.password = password


            if not username and not password then
              driver:disconnect()
              self.initial_accounts_exhausted = true
              return false
            end
          until (not self.found_accounts or not self.found_accounts[username])
            and (self.options.max_guesses == 0 or not self.account_guesses[username]
                  or self.options.max_guesses > self.account_guesses[username])

          -- increases the number of guesses for an account
          self.account_guesses[username] = self.account_guesses[username]
                                           and self.account_guesses[username] + 1 or 1
        end

        -- make sure that all threads locked in connect stat terminate quickly
        if Engine.terminate_all then
          driver:disconnect()
          driver = nil
          return false
        end

        local c
        -- Do we have a username or not?
        if username and #username > 0 then
          c = ("%s/%s"):format(username, #password > 0 and password or "<empty>")
        else
          c = ("%s"):format(#password > 0 and password or "<empty>")
        end

        local msg = (tries <= self.options.max_retries) and "Re-trying" or "Trying"
        stdnse.debug2("%s %s against %s:%d", msg, c, self.host.ip, self.port.number)
        status, response = driver:login(username, password)

        driver:disconnect()
        driver = nil

        if not status and response and response:isReduce() then
          local ret_creds = {}
          ret_creds.username = username
          ret_creds.password = password
          return false, response, ret_creds
        end

      end

      tries = tries - 1

      -- End if:
      -- * The guess was successful
      -- * The response was not set to retry
      -- * We've reached the maximum retry attempts
    until status or (response and not (response:isRetry())) or tries <= 0

    -- Increase the amount of total guesses
    self.counter = self.counter + 1

    return status, response
  end,


  login = function (self, cvar)
    local condvar = nmap.condvar(cvar)
    local thread_data = self.threads[coroutine.running()]
    local interval_start = os.time()


    while true do
      -- Should we terminate all threads or this particular thread?
      if (self.terminate_all or thread_data.terminate)
        or (self.initial_accounts_exhausted and #self.retry_accounts == 0) then
        break
      end

      -- Update tick and add this thread to the batch
      self.tick = self.tick + 1

      if not (self.batch:isFull()) and not thread_data.in_batch then
        self.batch:add(coroutine.running())

        thread_data.in_batch = true
        thread_data.ready = false
      end

      -- We expect doAuthenticate to pass the report variable received from the script
      local status, response, ret_creds = self:doAuthenticate()

      if thread_data.in_batch then
        thread_data.ready = true
      end

      if status then
        -- Prevent locked accounts from appearing several times
        if not self.found_accounts or self.found_accounts[response.username] == nil then
          if not self.options.nostore then
            local c = creds.Credentials:new(self.options.script_name, self.host, self.port)
            c:add(response.username, response.password, response.state)
          else
            self.credstore = self.credstore or {}
            table.insert(self.credstore, tostring(response))
          end

          stdnse.debug1("Discovered account: %s", tostring(response))

          -- if we're running in passonly mode, and want to continue guessing
          -- we will have a problem as the username is always the same.
          -- in this case we don't log the account as found.
          if not self.options.passonly then
            self.found_accounts[response.username] = true
          end

          -- Check if firstonly option was set, if so abort all threads
          if self.options.firstonly then
            self.terminate_all = true
          end
        end
      elseif ret_creds then
        if not ret_creds.connect_phase then
            -- add credentials to a vault
            self.retry_accounts[#self.retry_accounts + 1] = {
              username = ret_creds.username,
              password = ret_creds.password,
            }
        end
        -- notify the main thread that there were an error on this coroutine
        thread_data.protocol_error = true

        condvar "signal"
        condvar "wait"
      else
        if response and response:isAbort() then
          self.terminate_all = true
          self.error = response:getMessage()
          break
        elseif response and response:isDone() then
          break
        elseif response and response:isInvalidAccount() then
          self.found_accounts[response:isInvalidAccount()] = true
        end
      end

      local timediff = (os.time() - interval_start)

      -- This thread made another guess
      thread_data.guesses = (thread_data.guesses and thread_data.guesses + 1 or 1)

      -- Dump statistics at regular intervals
      if timediff > Engine.STAT_INTERVAL then
        interval_start = os.time()
        local tps = self.counter / (os.time() - self.starttime)
        table.insert(self.tps, tps)
        stdnse.debug2("threads=%d,tps=%.1f", self:activeThreads(), tps)
      end

      -- if delay was specified, do sleep
      if self.options.delay > 0 then
        stdnse.sleep(self.options.delay)
      end

      condvar "signal"
    end

    condvar "signal"
  end,

  --- Adds new worker thread using start function
  --
  -- @return new thread object
  addWorker = function (self, cvar)
    local co = stdnse.new_thread(self.login, self, cvar)

    Engine.THREAD_TO_ENGINE[co] = self

    self.threads[co] = {
      running = true,
      protocol_error = nil,
      attempt = 0,
      in_batch = false,
      ready = false,

      connection_error = nil,
      con_error_reason = nil,
      username = nil,
      password = nil,
    }

    return co
  end,

  addWorkerN = function (self, cvar, n)
    assert(n >= 0)
    for i = 1, n do
      self:addWorker(cvar)
    end
  end,

  renewBatch = function (self)
    if self.batch then
      local size = self.batch:getSize()
      local data = self.batch:getData()

      for i = 1, size do
        if self.threads[data[i]] then
          self.threads[data[i]].in_batch = false
          self.threads[data[i]].ready = false
        end
      end
    end

    self.batch = Batch:new(math.min(self:threadCount(), 3), self.tick)
  end,

  readyBatch = function (self)
    if not self.batch then
      return false
    end

    local n = self.batch:getSize()
    local data = self.batch:getData()

    if n == 0 then
      return false
    end

    for i = 1, n do
      if self.threads[data[i]] and coroutine.status(data[i]) ~= "dead" and self.threads[data[i]].in_batch then
        if not self.threads[data[i]].ready then
          return false
        end
      end
    end

    return true
  end,

  --- Starts the brute-force
  --
  -- @return status true on success, false on failure
  -- @return err string containing error message on failure
  start = function (self)

    local cvar = {}
    local condvar = nmap.condvar(cvar)

    assert(self.options.script_name, "SCRIPT_NAME was not set in options.script_name")
    assert(self.port.number and self.port.protocol, "Invalid port table detected")
    self.port.service = self.port.service or "unknown"

    -- Only run the check method if it exist. We should phase this out
    -- in favor of a check in the action function of the script
    if self.driver:new(self.host, self.port, self.driver_options).check then
      -- check if the driver is ready!
      local status, response = self.driver:new(self.host, self.port, self.driver_options):check()
      if not status then
        return false, response
      end
    end

    local usernames = self.usernames
    local passwords = self.passwords

    if "function" ~= type(usernames) then
      return false, ("Invalid usernames iterator: %s"):format(usernames)
    end
    if "function" ~= type(passwords) then
      return false, ("Invalid passwords iterator: %s"):format(passwords)
    end

    local mode = self.options.mode or stdnse.get_script_args "brute.mode"

    -- if no mode was given, but a credfile is present, assume creds mode
    if not mode and stdnse.get_script_args "brute.credfile" then
      if stdnse.get_script_args "userdb" or stdnse.get_script_args "passdb" then
        return false, "\n  ERROR: brute.credfile can't be used in combination with userdb/passdb"
      end
      mode = 'creds'
    end

    -- Are we guessing against a service that has no username (eg. VNC)
    if self.options.passonly then
      local function single_user_iter (next)
        local function next_user ()
          coroutine.yield ""
        end
        return coroutine.wrap(next_user)
      end
      -- only add this iterator if no other iterator was specified
      if self.iterator == nil then
        self.iterator = Iterators.user_pw_iterator(single_user_iter(), passwords)
      end
    elseif mode == 'creds' then
      local credfile = stdnse.get_script_args "brute.credfile"
      if not credfile then
        return false, "No credential file specified (see brute.credfile)"
      end

      local f = io.open(credfile, "r")
      if not f then
        return false, ("Failed to open credfile (%s)"):format(credfile)
      end

      self.iterator = Iterators.credential_iterator(f)
    elseif mode and mode == 'user' then
      self.iterator = self.iterator or Iterators.user_pw_iterator(usernames, passwords)
    elseif mode and mode == 'pass' then
      self.iterator = self.iterator or Iterators.pw_user_iterator(usernames, passwords)
    elseif mode then
      return false, ("Unsupported mode: %s"):format(mode)
      -- Default to the pw_user_iterator in case no iterator was specified
    elseif self.iterator == nil then
      self.iterator = Iterators.pw_user_iterator(usernames, passwords)
    end

    if (not mode or mode == 'user' or mode == 'pass') and self.options.useraspass then
      -- if we're only guessing passwords, this doesn't make sense
      if not self.options.passonly then
        self.iterator = unpwdb.concat_iterators(
          Iterators.pw_same_as_user_iterator(usernames, "lower"),
          self.iterator
        )
      end
    end

    if (not mode or mode == 'user' or mode == 'pass') and self.options.emptypass then
      local function empty_pass_iter ()
        local function next_pass ()
          coroutine.yield ""
        end
        return coroutine.wrap(next_pass)
      end
      self.iterator = Iterators.account_iterator(usernames, empty_pass_iter(), mode or "pass")
    end

    self.starttime = os.time()


    -- How many threads should start?
    local start_threads = self.start_threads
    -- If there are already too many threads waiting for connection,
    -- then start humbly with one thread
    if nmap.socket.get_stats().connect_waiting > 0 then
      start_threads = 1
    end

    -- Start `start_threads` number of threads
    self:addWorkerN(cvar, start_threads)
    self:renewBatch()

    local revive = false
    local killed_one = false
    local error_since_batch_start = false
    local stagnation_count = 0 -- number of times when all threads are stopped because of exceptions
    local quick_start = true
    local stagnated = true

    -- Main logic loop
    while true do
      local thread_count = self:threadCount()

      -- should we stop
      if thread_count <= 0 then
        if (self.initial_accounts_exhausted and #self.retry_accounts == 0) or self.terminate_all then
          break
        else
          -- there are some accounts yet to be checked, so revive the engine
          revive = true
        end
      end

      -- Reset flags
      killed_one = false
      error_since_batch_start = false

      -- Are all the threads have any kind of mistake?
      -- if not, then this variable will change to false after next loop
      stagnated = true

      -- Run through all coroutines and check their statuses
      -- if any mistake has happened kill one coroutine.
      -- We do not actually kill a coroutine right-away, we just
      -- signal it to finish work until some point an then die.
      for co, v in pairs(self.threads) do
        if not v.connection_error then
          stagnated = false
        end

        if v.protocol_error or v.connection_error then
          if v.attempt >= self.batch:getStartTime() then
            error_since_batch_start = true
          end

          if not killed_one then
            v.terminate = true
            killed_one = true

            if v.protocol_error then
              stdnse.debug2("Killed one thread because of PROTOCOL exception")
            else
              stdnse.debug2("Killed one thread because of CONNECTION exception")
            end
          end

          -- Remove error flags of the thread to let it continue to run
          v.protocol_error = nil
          v.connection_error = nil
        else
          -- If we got here, then at least one thread is running fine
          -- and there is no connection stagnation
          --stagnated = false
        end
      end

      if stagnated == true then
        stagnation_count = stagnation_count + 1

        -- If we get inside `if` below, then we are not making any
        -- guesses for too long. In this case it is reasonable to stop
        -- bruteforce.
        if stagnation_count == 100 then
          stdnse.debug1("WARNING: The service seems to have failed or is heavily firewalled... Consider aborting.")
          if self.options.killstagnated then
            self.error = "The service seems to have failed or is heavily firewalled..."
            self.terminate_all = true
          end
          stagnation_count = 0
        end
      else
        stagnation_count = 0
      end

      -- `quick_start` changes to false only once since Engine starts
      -- `quick_start` remains false till the end of the bruteforce.
      if killed_one then
        quick_start = false
      end

      -- Check if we possibly exhaust resources.
      if not killed_one then
        local waiting = nmap.socket.get_stats().connect_waiting

        if waiting ~= 0 then
          local kill_count = 1
          if waiting > 5 then
            kill_count = math.max(math.floor(thread_count / 2), 1)
          end

          for co, v in pairs(self.threads) do
            if coroutine.status(co) ~= "dead" then
              stdnse.debug2("Killed one because of RESOURCE management")
              v.terminate = true
              killed_one = true

              kill_count = kill_count - 1
              if kill_count == 0 then
                break
              end
            end
          end
        end

      end

      -- Renew the batch if there was an error since we started to assemble the batch
      -- or the batch's limit is unreachable with current number of threads
      -- or when some thread does not change state to ready for too long
      if error_since_batch_start
        or not killed_one and thread_count < self.batch:getLimit()
        or (thread_count > 0 and self.tick - self.batch:getStartTime() > 10) then
        self:renewBatch()
      end

      if (not killed_one and self.batch:isFull() and thread_count < self.max_threads)
        or revive then

        local num_to_add = 1
        if quick_start then
          num_to_add = math.min(self.max_threads - thread_count, thread_count)
        end

        self:addWorkerN(cvar, num_to_add)
        self:renewBatch()
        revive = false
      end


      local threads = self:threadCount()
      stdnse.debug2("Status: #threads = %d, #retry_accounts = %d, initial_accounts_exhausted = %s, waiting = %d",
        threads, #self.retry_accounts, tostring(self.initial_accounts_exhausted),
        nmap.socket.get_stats().connect_waiting)

      if threads > 0 then
        -- wake up other threads
        -- wait for all threads to finish running
        condvar "broadcast"
        condvar "wait"
      end
    end


    local valid_accounts

    if not self.options.nostore then
      valid_accounts = creds.Credentials:new(self.options.script_name, self.host, self.port):getTable()
    else
      valid_accounts = self.credstore
    end

    local result = stdnse.output_table()
    -- Did we find any accounts, if so, do formatting
    if valid_accounts and #valid_accounts > 0 then
      result[self.options.title or "Accounts"] = valid_accounts
    else
      result.Accounts = "No valid accounts found"
    end

    -- calculate the average tps
    local sum = 0
    for _, v in ipairs(self.tps) do
      sum = sum + v
    end
    local time_diff = (os.time() - self.starttime)
    time_diff = (time_diff == 0) and 1 or time_diff
    local tps = (sum == 0) and (self.counter / time_diff) or (sum / #self.tps)

    -- Add the statistics to the result
    result.Statistics = ("Performed %d guesses in %d seconds, average tps: %.1f"):format( self.counter, time_diff, tps )

    if self.options.max_guesses > 0 then
      -- we only display a warning if the guesses are equal to max_guesses
      for user, guesses in pairs(self.account_guesses) do
        if guesses == self.options.max_guesses then
          result.Information = ("Guesses restricted to %d tries per account to avoid lockout"):format(self.options.max_guesses)
          break
        end
      end
    end

    -- Did any error occur? If so add this to the result.
    if self.error then
      result.ERROR = self.error
      return false, result
    end
    return true, result
  end,

  getEngine = function (co)
    local engine = Engine.THREAD_TO_ENGINE[co]
    if not engine then
      stdnse.debug1("WARNING: No engine associated with %s", coroutine.running())
    end
    return engine
  end,

  getThreadData = function (co)
    local engine = Engine.getEngine(co)
    if not engine then
      return nil
    end
    return engine.threads[co]
  end,
}

--- Default username iterator that uses unpwdb
--
function usernames_iterator ()
  local status, usernames = unpwdb.usernames()
  if not status then
    return usernames or "Failed to load usernames"
  end
  return usernames
end

--- Default password iterator that uses unpwdb
--
function passwords_iterator ()
  local status, passwords = unpwdb.passwords()
  if not status then
    return passwords or "Failed to load passwords"
  end
  return passwords
end

Iterators = {

  --- Iterates over each user and password
  --
  -- @param users table/function containing list of users
  -- @param pass table/function containing list of passwords
  -- @param mode string, should be either 'user' or 'pass' and controls
  --        whether the users or passwords are in the 'outer' loop
  -- @return function iterator
  account_iterator = function (users, pass, mode)
    local function next_credential ()
      local outer, inner
      if "table" == type(users) then
        users = unpwdb.table_iterator(users)
      end
      if "table" == type(pass) then
        pass = unpwdb.table_iterator(pass)
      end

      if mode == 'pass' then
        outer, inner = pass, users
      elseif mode == 'user' then
        outer, inner = users, pass
      else
        return
      end

      for o in outer do
        for i in inner do
          if mode == 'pass' then
            coroutine.yield(i, o)
          else
            coroutine.yield(o, i)
          end
        end
        inner "reset"
      end
      while true do
        coroutine.yield(nil, nil)
      end
    end
    return coroutine.wrap(next_credential)
  end,


  --- Try each password for each user (user in outer loop)
  --
  -- @param users table/function containing list of users
  -- @param pass table/function containing list of passwords
  -- @return function iterator
  user_pw_iterator = function (users, pass)
    return Iterators.account_iterator(users, pass, "user")
  end,

  --- Try each user for each password (password in outer loop)
  --
  -- @param users table/function containing list of users
  -- @param pass table/function containing list of passwords
  -- @return function iterator
  pw_user_iterator = function (users, pass)
    return Iterators.account_iterator(users, pass, "pass")
  end,

  --- An iterator that returns the username as password
  --
  -- @param users function returning the next user
  -- @param case string [optional] 'upper' or 'lower', specifies if user
  --        and password pairs should be case converted.
  -- @return function iterator
  pw_same_as_user_iterator = function (users, case)
    local function next_credential ()
      for user in users do
        if case == 'upper' then
          coroutine.yield(user, user:upper())
        elseif case == 'lower' then
          coroutine.yield(user, user:lower())
        else
          coroutine.yield(user, user)
        end
      end
      users "reset"
      while true do
        coroutine.yield(nil, nil)
      end
    end
    return coroutine.wrap(next_credential)
  end,

  --- An iterator that returns the username and uppercase password
  --
  -- @param users table containing list of users
  -- @param pass table containing list of passwords
  -- @param mode string, should be either 'user' or 'pass' and controls
  --        whether the users or passwords are in the 'outer' loop
  -- @return function iterator
  pw_ucase_iterator = function (users, passwords, mode)
    local function next_credential ()
      for user, pass in Iterators.account_iterator(users, passwords, mode) do
        coroutine.yield(user, pass:upper())
      end
      while true do
        coroutine.yield(nil, nil)
      end
    end
    return coroutine.wrap(next_credential)
  end,

  --- Credential iterator (for default or known user/pass combinations)
  --
  -- @param f file handle to file containing credentials separated by '/'
  -- @return function iterator
  credential_iterator = function (f)
    local function next_credential ()
      local c = {}
      for line in f:lines() do
        if not (line:match "^#!comment:") then
          local trim = function (s)
            return s:match '^()%s*$' and '' or s:match '^%s*(.*%S)'
          end
          line = trim(line)
          local user, pass = line:match "^([^%/]*)%/(.*)$"
          coroutine.yield(user, pass)
        end
      end
      f:close()
      while true do
        coroutine.yield(nil, nil)
      end
    end
    return coroutine.wrap(next_credential)
  end,

  unpwdb_iterator = function (mode)
    local status, users, passwords

    status, users = unpwdb.usernames()
    if not status then
      return
    end

    status, passwords = unpwdb.passwords()
    if not status then
      return
    end

    return Iterators.account_iterator(users, passwords, mode)
  end,

}

-- These functions all return a boolean and an error (or result)
-- and should all be wrapped in order to check status of the engine.
checkwrap = {
  connect = true,
  send = true,
  receive = true,
  receive_lines = true,
  receive_buf = true,
  receive_bytes = true,
}

-- A socket wrapper class.
-- Instances of this class can be treated as regular sockets.
-- This wrapper is used to relay connection errors to the corresponding Engine
-- instance.
BruteSocket = {
  new = function (self)
    local o = {
      socket = nil,
    }
    setmetatable(o, self)

    self.__index = function (instance, key)
      local f = rawget(self, key)
      if f then
        -- BruteSocket function
        return f
      else
        -- something provided by NSE socket
        f = instance.socket[key]
      end
      -- Check if it should be wrapped with a checkStatus call
      if checkwrap[key] then
        return function(s, ...)
          local status, err = f(instance.socket, ...)
          instance:checkStatus(status, err)
          return status, err
        end
      elseif type(f) == "function" then
        -- not wrapped? call the function on the underlying socket
        return function (s, ...)
          return f(instance.socket, ...)
        end
      end
      return f
    end

    o.socket = nmap.new_socket()

    return o
  end,

  getSocket = function (self)
    return self.socket
  end,

  checkStatus = function (self, status, err)
    if not status and (err == "ERROR" or err == "TIMEOUT") then
      local engine = Engine.getEngine(coroutine.running())

      if not engine then
        stdnse.debug2("WARNING: No associated engine detected for %s", coroutine.running())
        return -- behave like a usual socket
      end

      local thread_data = Engine.getThreadData(coroutine.running())

      engine.retry_accounts[#engine.retry_accounts + 1] = {
        username = thread_data.username,
        password = thread_data.password,
      }

      thread_data.connection_error = true
      thread_data.con_error_reason = err
    end
  end,
}

function new_socket ()
  return BruteSocket:new()
end


return _ENV

Youez - 2016 - github.com/yon3zu
LinuXploit