Browse Source

XSSer v1.8.2 - 'The Hiv3' release

epsylon 1 year ago
parent
commit
28334db377

+ 20 - 0
.gitattributes

@@ -0,0 +1,20 @@
+*.conf text eol=lf
+*.md text eol=lf
+*.md5 text eol=lf
+*.py text eol=lf
+*.xml text eol=lf
+LICENSE text eol=lf
+COMMITMENT text eol=lf
+
+*_ binary
+*.dll binary
+*.pdf binary
+*.so binary
+*.wav binary
+*.zip binary
+*.x32 binary
+*.x64 binary
+*.exe binary
+*.sln binary
+*.vcproj binary
+

+ 47 - 0
.github/CODE_OF_CONDUCT.md

@@ -0,0 +1,47 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project leader at epsylon@riseup.net. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
+

File diff suppressed because it is too large
+ 37 - 0
.github/CONTRIBUTING.md


+ 38 - 0
.github/ISSUE_TEMPLATE/bug_report.md

@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: bug report
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+1. Run '...'
+2. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Running environment:**
+ - XSSer version [e.g. 1.8.2]
+ - Installation method [e.g. git]
+ - Operating system: [e.g. Debian 4.19.16-1~bpo9+1 (2019-02-07) ]
+ - Python version [e.g. 3.7]
+
+**Target details:**
+ - XSS techniques found by xsser [e.g. DOM-Based XSS]
+ - WAF/IPS [if any]
+ - Relevant console output [if any]
+ - Exception traceback [if any]
+
+**Additional context**
+Add any other context about the problem here.
+
+---

+ 22 - 0
.github/ISSUE_TEMPLATE/feature_request.md

@@ -0,0 +1,22 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: feature request
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
+
+---

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+__pycache__/
+*.py[cod]

+ 547 - 0
.pylintrc

@@ -0,0 +1,547 @@
+# Based on Apache 2.0 licensed code from https://github.com/ClusterHQ/flocker
+
+[MASTER]
+
+# Specify a configuration file.
+#rcfile=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+init-hook="from pylint.config import find_pylintrc; import os, sys; sys.path.append(os.path.dirname(find_pylintrc()))"
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=
+
+# Pickle collected data for later comparisons.
+persistent=no
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+# Use multiple processes to speed up Pylint.
+# DO NOT CHANGE THIS VALUES >1 HIDE RESULTS!!!!!
+jobs=1
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+unsafe-load-any-extension=no
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code
+extension-pkg-whitelist=
+
+# Allow optimization of some AST trees. This will activate a peephole AST
+# optimizer, which will apply various small optimizations. For instance, it can
+# be used to obtain the result of joining multiple strings with the addition
+# operator. Joining a lot of strings can lead to a maximum recursion error in
+# Pylint and this flag can prevent that. It has one side effect, the resulting
+# AST will be different than the one from reality.
+optimize-ast=no
+
+
+[MESSAGES CONTROL]
+
+# Only show warnings with the listed confidence levels. Leave empty to show
+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
+confidence=
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time. See also the "--disable" option for examples.
+disable=all
+
+enable=import-error,
+       import-self,
+       reimported,
+       wildcard-import,
+       misplaced-future,
+       deprecated-module,
+       unpacking-non-sequence,
+       invalid-all-object,
+       undefined-all-variable,
+       used-before-assignment,
+       cell-var-from-loop,
+       global-variable-undefined,
+       redefine-in-handler,
+       unused-import,
+       unused-wildcard-import,
+       global-variable-not-assigned,
+       undefined-loop-variable,
+       global-at-module-level,
+       bad-open-mode,
+       redundant-unittest-assert,
+       boolean-datetime
+       deprecated-method,
+       anomalous-unicode-escape-in-string,
+       anomalous-backslash-in-string,
+       not-in-loop,
+       continue-in-finally,
+       abstract-class-instantiated,
+       star-needs-assignment-target,
+       duplicate-argument-name,
+       return-in-init,
+       too-many-star-expressions,
+       nonlocal-and-global,
+       return-outside-function,
+       return-arg-in-generator,
+       invalid-star-assignment-target,
+       bad-reversed-sequence,
+       nonexistent-operator,
+       yield-outside-function,
+       init-is-generator,
+       nonlocal-without-binding,
+       lost-exception,
+       assert-on-tuple,
+       dangerous-default-value,
+       duplicate-key,
+       useless-else-on-loop
+       expression-not-assigned,
+       confusing-with-statement,
+       unnecessary-lambda,
+       pointless-statement,
+       pointless-string-statement,
+       unnecessary-pass,
+       unreachable,
+       using-constant-test,
+       bad-super-call,
+       missing-super-argument,
+       slots-on-old-class,
+       super-on-old-class,
+       property-on-old-class,
+       not-an-iterable,
+       not-a-mapping,
+       format-needs-mapping,
+       truncated-format-string,
+       missing-format-string-key,
+       mixed-format-string,
+       too-few-format-args,
+       bad-str-strip-call,
+       too-many-format-args,
+       bad-format-character,
+       format-combined-specification,
+       bad-format-string-key,
+       bad-format-string,
+       missing-format-attribute,
+       missing-format-argument-key,
+       unused-format-string-argument
+       unused-format-string-key,
+       invalid-format-index,
+       bad-indentation,
+       mixed-indentation,
+       unnecessary-semicolon,
+       lowercase-l-suffix,
+       invalid-encoded-data,
+       unpacking-in-except,
+       import-star-module-level,
+       long-suffix,
+       old-octal-literal,
+       old-ne-operator,
+       backtick,
+       old-raise-syntax,
+       metaclass-assignment,
+       next-method-called,
+       dict-iter-method,
+       dict-view-method,
+       indexing-exception,
+       raising-string,
+       using-cmp-argument,
+       cmp-method,
+       coerce-method,
+       delslice-method,
+       getslice-method,
+       hex-method,
+       nonzero-method,
+       t-method,
+       setslice-method,
+       old-division,
+       logging-format-truncated,
+       logging-too-few-args,
+       logging-too-many-args,
+       logging-unsupported-format,
+       logging-format-interpolation,
+       invalid-unary-operand-type,
+       unsupported-binary-operation,
+       not-callable,
+       redundant-keyword-arg,
+       assignment-from-no-return,
+       assignment-from-none,
+       not-context-manager,
+       repeated-keyword,
+       missing-kwoa,
+       no-value-for-parameter,
+       invalid-sequence-index,
+       invalid-slice-index,
+       unexpected-keyword-arg,
+       unsupported-membership-test,
+       unsubscriptable-object,
+       access-member-before-definition,
+       method-hidden,
+       assigning-non-slot,
+       duplicate-bases,
+       inconsistent-mro,
+       inherit-non-class,
+       invalid-slots,
+       invalid-slots-object,
+       no-method-argument,
+       no-self-argument,
+       unexpected-special-method-signature,
+       non-iterator-returned,
+       arguments-differ,
+       signature-differs,
+       bad-staticmethod-argument,
+       non-parent-init-called,
+       bad-except-order,
+       catching-non-exception,
+       bad-exception-context,
+       notimplemented-raised,
+       raising-bad-type,
+       raising-non-exception,
+       misplaced-bare-raise,
+       duplicate-except,
+       nonstandard-exception,
+       binary-op-exception,
+       not-async-context-manager,
+       yield-inside-async-function
+
+# Needs investigation:
+# abstract-method (might be indicating a bug? probably not though)
+# protected-access (requires some refactoring)
+# attribute-defined-outside-init (requires some refactoring)
+# super-init-not-called (requires some cleanup)
+
+# Things we'd like to enable someday:
+# redefined-builtin (requires a bunch of work to clean up our code first)
+# redefined-outer-name (requires a bunch of work to clean up our code first)
+# undefined-variable (re-enable when pylint fixes https://github.com/PyCQA/pylint/issues/760)
+# no-name-in-module (giving us spurious warnings https://github.com/PyCQA/pylint/issues/73)
+# unused-argument (need to clean up or code a lot, e.g. prefix unused_?)
+# function-redefined (@overload causes lots of spurious warnings)
+# too-many-function-args (@overload causes spurious warnings... I think)
+# parameter-unpacking (needed for eventual Python 3 compat)
+# print-statement (needed for eventual Python 3 compat)
+# filter-builtin-not-iterating (Python 3)
+# map-builtin-not-iterating (Python 3)
+# range-builtin-not-iterating (Python 3)
+# zip-builtin-not-iterating (Python 3)
+# many others relevant to Python 3
+# unused-variable (a little work to cleanup, is all)
+
+# ...
+[REPORTS]
+
+# Set the output format. Available formats are text, parseable, colorized, msvs
+# (visual studio) and html. You can also give a reporter class, eg
+# mypackage.mymodule.MyReporterClass.
+output-format=parseable
+
+# Put messages in a separate file for each module / package specified on the
+# command line instead of printing them on stdout. Reports (if any) will be
+# written in a file name "pylint_global.[txt|html]".
+files-output=no
+
+# Tells whether to display a full report or only the messages
+reports=no
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectively contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details
+#msg-template=
+
+
+[LOGGING]
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format
+logging-modules=logging
+
+
+[FORMAT]
+
+# Maximum number of characters on a single line.
+max-line-length=100
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )?<?https?://\S+>?$
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
+
+# List of optional constructs for which whitespace checking is disabled. `dict-
+# separator` is used to allow tabulation in dicts, etc.: {1  : 1,\n222: 2}.
+# `trailing-comma` allows a space between comma and closing bracket: (a, ).
+# `empty-line` allows space-only lines.
+no-space-check=trailing-comma,dict-separator
+
+# Maximum number of lines in a module
+max-module-lines=1000
+
+# String used as indentation unit. This is usually "    " (4 spaces) or "\t" (1
+# tab).
+indent-string='    '
+
+# Number of spaces of indent required inside a hanging  or continued line.
+indent-after-paren=4
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=
+
+
+[TYPECHECK]
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis. It
+# supports qualified module names, as well as Unix pattern matching.
+ignored-modules=thirdparty.six.moves
+
+# List of classes names for which member attributes should not be checked
+# (useful for classes with attributes dynamically set). This supports can work
+# with qualified names.
+ignored-classes=
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+generated-members=
+
+
+[VARIABLES]
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# A regular expression matching the name of dummy variables (i.e. expectedly
+# not used).
+dummy-variables-rgx=_$|dummy
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,_cb
+
+
+[SIMILARITIES]
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+# Ignore imports when computing similarities.
+ignore-imports=no
+
+
+[SPELLING]
+
+# Spelling dictionary name. Available dictionaries: none. To make it working
+# install python-enchant package.
+spelling-dict=
+
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
+
+# A path to a file that contains private dictionary; one word per line.
+spelling-private-dict-file=
+
+# Tells whether to store unknown words to indicated private dictionary in
+# --spelling-private-dict-file option instead of raising a message.
+spelling-store-unknown-words=no
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,XXX,TODO
+
+
+[BASIC]
+
+# List of builtins function names that should not be used, separated by a comma
+bad-functions=map,filter,input
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,j,k,ex,Run,_
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,bar,baz,toto,tutu,tata
+
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
+
+# Include a hint for the correct naming format with invalid-name
+include-naming-hint=no
+
+# Regular expression matching correct function names
+function-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for function names
+function-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression matching correct variable names
+variable-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for variable names
+variable-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression matching correct constant names
+const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+
+# Naming hint for constant names
+const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+
+# Regular expression matching correct attribute names
+attr-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for attribute names
+attr-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression matching correct argument names
+argument-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for argument names
+argument-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression matching correct class attribute names
+class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
+
+# Naming hint for class attribute names
+class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
+
+# Regular expression matching correct inline iteration names
+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+
+# Naming hint for inline iteration names
+inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
+
+# Regular expression matching correct class names
+class-rgx=[A-Z_][a-zA-Z0-9]+$
+
+# Naming hint for class names
+class-name-hint=[A-Z_][a-zA-Z0-9]+$
+
+# Regular expression matching correct module names
+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Naming hint for module names
+module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Regular expression matching correct method names
+method-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for method names
+method-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=^_
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
+
+
+[ELIF]
+
+# Maximum number of nested blocks for function / method body
+max-nested-blocks=5
+
+
+[IMPORTS]
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=regsub,TERMIOS,Bastion,rexec
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled)
+import-graph=
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled)
+int-import-graph=
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=5
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore
+ignored-argument-names=_.*
+
+# Maximum number of locals for function / method body
+max-locals=15
+
+# Maximum number of return / yield for function / method body
+max-returns=6
+
+# Maximum number of branch for function / method body
+max-branches=12
+
+# Maximum number of statements in function / method body
+max-statements=50
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=7
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+# Maximum number of boolean expressions in a if statement
+max-bool-expr=5
+
+
+[CLASSES]
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,__new__,setUp
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=mcs
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,_fields,_replace,_source,_make
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when being caught. Defaults to
+# "Exception"
+overgeneral-exceptions=Exception
+

+ 46 - 0
COMMITMENT

@@ -0,0 +1,46 @@
+GPL Cooperation Commitment
+Version 1.0
+
+Before filing or continuing to prosecute any legal proceeding or claim
+(other than a Defensive Action) arising from termination of a Covered
+License, we commit to extend to the person or entity ('you') accused
+of violating the Covered License the following provisions regarding
+cure and reinstatement, taken from GPL version 3. As used here, the
+term 'this License' refers to the specific Covered License being
+enforced.
+
+    However, if you cease all violation of this License, then your
+    license from a particular copyright holder is reinstated (a)
+    provisionally, unless and until the copyright holder explicitly
+    and finally terminates your license, and (b) permanently, if the
+    copyright holder fails to notify you of the violation by some
+    reasonable means prior to 60 days after the cessation.
+
+    Moreover, your license from a particular copyright holder is
+    reinstated permanently if the copyright holder notifies you of the
+    violation by some reasonable means, this is the first time you
+    have received notice of violation of this License (for any work)
+    from that copyright holder, and you cure the violation prior to 30
+    days after your receipt of the notice.
+
+We intend this Commitment to be irrevocable, and binding and
+enforceable against us and assignees of or successors to our
+copyrights.
+
+Definitions
+
+'Covered License' means the GNU General Public License, version 2
+(GPLv2), the GNU Lesser General Public License, version 2.1
+(LGPLv2.1), or the GNU Library General Public License, version 2
+(LGPLv2), all as published by the Free Software Foundation.
+
+'Defensive Action' means a legal proceeding or claim that We bring
+against you in response to a prior proceeding or claim initiated by
+you or your affiliate.
+
+'We' means each contributor to this repository as of the date of
+inclusion of this file, including subsidiaries of a corporate
+contributor.
+
+This work is available under a Creative Commons Attribution-ShareAlike
+4.0 International license (https://creativecommons.org/licenses/by-sa/4.0/).

+ 1 - 1
Makefile

@@ -4,7 +4,7 @@ PYTHON=`which python`
 DESTDIR=/
 BUILDIR=$(CURDIR)/debian/xsser
 PROJECT=xsser
-VERSION=1.8.1
+VERSION=1.8.2
 
 all:
 	@echo "make source - Create source package"

+ 83 - 77
README.md

@@ -1,77 +1,83 @@
-  ![XSSer](https://xsser.03c8.net/xsser/thehive1.png "XSSer")
-
-----------
-
- + Web: https://xsser.03c8.net
-
-----------
-
-  Cross Site "Scripter" (aka XSSer) is an automatic -framework- to detect, exploit and report XSS vulnerabilities in web-based applications.
-
-  It provides several options to try to bypass certain filters and various special techniques for code injection.
-
-  XSSer has pre-installed [ > 1300 XSS ] attacking vectors and can bypass-exploit code on several browsers/WAFs:
-
-     [PHPIDS]: PHP-IDS
-     [Imperva]: Imperva Incapsula WAF
-     [WebKnight]: WebKnight WAF
-     [F5]: F5 Big IP WAF
-     [Barracuda]: Barracuda WAF
-     [ModSec]: Mod-Security
-     [QuickDF]: QuickDefense
-     [Chrome]: Google Chrome
-     [IE]: Internet Explorer
-     [FF]: Mozilla's Gecko rendering engine, used by Firefox/Iceweasel
-     [NS-IE]: Netscape in IE rendering engine mode
-     [NS-G]: Netscape in the Gecko rendering engine mode
-     [Opera]: Opera 
-
-  ![XSSer](https://xsser.03c8.net/xsser/url_generation.png "XSSer URL Generation Schema")
-
-----------
-
-#### Installing:
-
-  XSSer runs on many platforms. It requires Python and the following libraries:
-
-      python-pycurl - Python bindings to libcurl
-      python-xmlbuilder - create xml/(x)html files - Python 2.x
-      python-beautifulsoup - error-tolerant HTML parser for Python
-      python-geoip - Python bindings for the GeoIP IP-to-country resolver library
-
-  On Debian-based systems (ex: Ubuntu), run: 
-
-      sudo apt-get install python-pycurl python-xmlbuilder python-beautifulsoup python-geoip
-
-  On other systems such as: Kali, Ubuntu, ArchLinux, ParrotSec, Fedora, etc... also run:
-
-      pip install geoip 
-
-####  Source libs:
-
-   * Python: https://www.python.org/downloads/
-   * PyCurl: http://pycurl.sourceforge.net/
-   * PyBeautifulSoup: https://pypi.python.org/pypi/BeautifulSoup
-   * PyGeoIP: https://pypi.python.org/pypi/GeoIP
-
-----------
-
-####  License:
-
-  XSSer is released under the GPLv3. You can find the full license text
-in the [LICENSE](./docs/LICENSE) file.
-
-----------
-
-####  Screenshots:
-
-  ![XSSer](https://xsser.03c8.net/xsser/thehive2.png "XSSer Shell")
-
-  ![XSSer](https://xsser.03c8.net/xsser/thehive3.png "XSSer Manifesto")
-
-  ![XSSer](https://xsser.03c8.net/xsser/thehive4.png "XSSer Configuration")
-
-  ![XSSer](https://xsser.03c8.net/xsser/thehive5.png "XSSer Bypassers")
-
-  ![XSSer](https://xsser.03c8.net/xsser/zika4.png "XSSer GeoMap")
-
+  ![XSSer](https://xsser.03c8.net/xsser/thehive1.png "XSSer")
+
+----------
+
+ + Web: https://xsser.03c8.net
+
+----------
+
+  Cross Site "Scripter" (aka XSSer) is an automatic -framework- to detect, exploit and report XSS vulnerabilities in web-based applications.
+
+  It provides several options to try to bypass certain filters and various special techniques for code injection.
+
+  XSSer has pre-installed [ > 1300 XSS ] attacking vectors and can bypass-exploit code on several browsers/WAFs:
+
+     [PHPIDS]: PHP-IDS
+     [Imperva]: Imperva Incapsula WAF
+     [WebKnight]: WebKnight WAF
+     [F5]: F5 Big IP WAF
+     [Barracuda]: Barracuda WAF
+     [ModSec]: Mod-Security
+     [QuickDF]: QuickDefense
+     [Sucuri]: SucuriWAF 
+     [Chrome]: Google Chrome
+     [IE]: Internet Explorer
+     [FF]: Mozilla's Gecko rendering engine, used by Firefox/Iceweasel
+     [NS-IE]: Netscape in IE rendering engine mode
+     [NS-G]: Netscape in the Gecko rendering engine mode
+     [Opera]: Opera Browser
+
+  ![XSSer](https://xsser.03c8.net/xsser/url_generation.png "XSSer URL Generation Schema")
+
+----------
+
+#### Installing:
+
+XSSer runs on many platforms. It requires Python (3.x) and the following libraries:
+
+    - python3-pycurl - Python bindings to libcurl (Python 3)
+    - python3-bs4 - error-tolerant HTML parser for Python 3
+    - python3-geoip - Python3 bindings for the GeoIP IP-to-country resolver library
+    - python3-geoip2 - Python geoip2 API for web services and databases - Python 3.x
+    - python3-gi - Python 3 bindings for gobject-introspection libraries
+    - python3-cairocffi - cffi-based cairo bindings for Python (Python3)
+
+On Debian-based systems (ex: Ubuntu), run: 
+
+    sudo apt-get install python3-pycurl python3-bs4 python3-geoip python3-geoip2 python3-gi python3-cairocffi
+
+On other systems such as: Kali, Ubuntu, ArchLinux, ParrotSec, Fedora, etc... also run:
+
+    sudo pip3 install pycurl bs4 geoip2 gobject cairocffi
+
+####  Source libs:
+
+   * Python: https://www.python.org/downloads/
+   * PyCurl: http://pycurl.sourceforge.net/
+   * PyBeautifulSoup4: https://pypi.org/project/beautifulsoup4/
+   * PyGeoIP: https://pypi.org/project/python-geoip-python3/
+   * PyGeoIP2: https://pypi.org/project/geoip2/
+   * PyGObject: https://pypi.org/project/gobject/
+   * PyCairocffi: https://pypi.org/project/cairocffi/
+
+----------
+
+####  License:
+
+  XSSer is released under the GPLv3. You can find the full license text
+in the [LICENSE](./docs/LICENSE) file.
+
+----------
+
+####  Screenshots:
+
+  ![XSSer](https://xsser.03c8.net/xsser/thehive2.png "XSSer Shell")
+
+  ![XSSer](https://xsser.03c8.net/xsser/thehive3.png "XSSer Manifesto")
+
+  ![XSSer](https://xsser.03c8.net/xsser/thehive4.png "XSSer Configuration")
+
+  ![XSSer](https://xsser.03c8.net/xsser/thehive5.png "XSSer Bypassers")
+
+  ![XSSer](https://xsser.03c8.net/xsser/zika4.png "XSSer GeoMap")
+

+ 27 - 27
core/crawler.py

@@ -20,17 +20,16 @@ with xsser; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import sys
-import urllib
-import urllib2
-import urlparse
+import urllib.request, urllib.parse, urllib.error
 import pycurl
 import time
 import traceback
-import curlcontrol
-import threadpool
-from Queue import Queue
+from . import curlcontrol
+from . import threadpool
+from queue import Queue
 from collections import defaultdict
-from BeautifulSoup import BeautifulSoup
+from bs4 import BeautifulSoup
+from bs4.dammit import EncodingDetector
 
 class EmergencyLanding(Exception):
     pass
@@ -65,7 +64,7 @@ class Crawler(object):
         if self._reporter:
             self._reporter.report(msg)
         else:
-            print msg
+            print(msg)
 
     def set_reporter(self, reporter):
         self._reporter = reporter
@@ -74,30 +73,30 @@ class Crawler(object):
         """
         find parameters in given url.
         """
-        parsed = urllib2.urlparse.urlparse(url)
+        parsed = urllib.parse.urlparse(url)
         if "C=" in parsed.query and "O=" in  parsed.query:
             qs = ""
         else:
-            qs = urlparse.parse_qs(parsed.query)
+            qs = urllib.parse.parse_qs(parsed.query)
         if parsed.scheme:
             path = parsed.scheme + "://" + parsed.netloc + parsed.path
         else:
             path = parsed.netloc + parsed.path
         for arg_name in qs:
             key = (arg_name, parsed.netloc)
-            zipped = zip(*self._found_args[key])
+            zipped = list(zip(*self._found_args[key]))
             if not zipped or not path in zipped[0]:
                 self._found_args[key].append([path, url])
                 self.generate_result(arg_name, path, url)
         if not qs:
-            parsed = urllib2.urlparse.urlparse(url)
+            parsed = urllib.parse.urlparse(url)
             if path.endswith("/"):
                 attack_url = path + "XSS"
             else:
                 attack_url = path + "/XSS"
             if not attack_url in self._parent.crawled_urls:
                 self._parent.crawled_urls.append(attack_url)
-        ncurrent = sum(map(lambda s: len(s), self._found_args.values()))
+        ncurrent = sum([len(s) for s in list(self._found_args.values())])
         if ncurrent >= self._max:
             self._armed = False
 
@@ -110,7 +109,7 @@ class Crawler(object):
         """
         if not self._armed:
             return []
-        parsed = urllib2.urlparse.urlparse(path)
+        parsed = urllib.parse.urlparse(path)
         basepath = parsed.scheme + "://" + parsed.netloc
         self._parse_external = not local_only
         if not self.pool:
@@ -138,14 +137,14 @@ class Crawler(object):
             self.pool.joinAllDismissedWorkers()
 
     def generate_result(self, arg_name, path, url):
-        parsed = urllib2.urlparse.urlparse(url)
-        qs = urlparse.parse_qs(parsed.query)
+        parsed = urllib.parse.urlparse(url)
+        qs = urllib.parse.parse_qs(parsed.query)
         qs_joint = {}
-        for key, val in qs.iteritems():
+        for key, val in qs.items():
             qs_joint[key] = val[0]
         attack_qs = dict(qs_joint)
         attack_qs[arg_name] = "XSS"
-        attack_url = path + '?' + urllib.urlencode(attack_qs)
+        attack_url = path + '?' + urllib.parse.urlencode(attack_qs)
         if not attack_url in self._parent.crawled_urls:
             self._parent.crawled_urls.append(attack_url)
 
@@ -227,7 +226,7 @@ class Crawler(object):
                 links.add(href)
             else:
                 break
-        return map(lambda s: {'href': s}, links)
+        return [{'href': s} for s in links]
 
     def _get_done_dummy(self, request, result):
         path = request.args[0][0]
@@ -248,7 +247,7 @@ class Crawler(object):
         except:
             encoding = None
         try:
-            soup = BeautifulSoup(html_data, fromEncoding=encoding)
+            soup = BeautifulSoup(html_data, 'html.parser')
             links = None
         except:
             soup = None
@@ -260,21 +259,21 @@ class Crawler(object):
             forms = soup.findAll('form')
             for form in forms:
                 pars = {}
-                if form.has_key("action"):
-                    action_path = urlparse.urljoin(path, form["action"])
+                if "action" in form:
+                    action_path = urllib.parse.urljoin(path, form["action"])
                 else:
                     action_path = path
                 for input_par in form.findAll('input'):
-                    if not input_par.has_key("name"):
+                    if "name" not in input_par:
                         continue
                     value = "foo"
-                    if input_par.has_key("value") and input_par["value"]:
+                    if "value" in input_par and input_par["value"]:
                         value = input_par["value"]
                     pars[input_par["name"]] = value
                 for input_par in form.findAll('select'):
                     pars[input_par["name"]] = "1"
                 if pars:
-                    links.append({"url":action_path + '?' + urllib.urlencode(pars)})
+                    links.append({"url":action_path + '?' + urllib.parse.urlencode(pars)})
                 else:
                     self.report("form with no pars")
                     links.append({"url":action_path})
@@ -288,7 +287,8 @@ class Crawler(object):
             links = links[:self._max]
         for a in links:
             try:
-                href = str(a['href'].encode('utf-8'))
+                #href = str(a['href'].encode('utf-8'))
+                href = str(a['href'])
             except KeyError:
                 # this link has no href
                 continue
@@ -297,7 +297,7 @@ class Crawler(object):
                 continue
             if href.startswith("javascript") or href.startswith('mailto:'):
                 continue
-            href = urlparse.urljoin(path, href)
+            href = urllib.parse.urljoin(path, href)
             if not href.startswith("http") or not "." in href:
                 continue
             href = href.split('#',1)[0]

+ 33 - 37
core/curlcontrol.py

@@ -19,12 +19,8 @@ You should have received a copy of the GNU General Public License along
 with xsser; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
-import os, urllib, mimetools, pycurl, re, time, random
-
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
+import os, urllib.request, urllib.parse, urllib.error, email, pycurl, re, time, random
+from io import StringIO as StringIO
 
 class Curl:
     """
@@ -90,10 +86,10 @@ class Curl:
         self.set_nosignals(1)
 
         def payload_callback(x):
-            self.payload += x
+            self.payload += str(x)
         self.set_option(pycurl.WRITEFUNCTION, payload_callback)
         def header_callback(x):
-            self.header.write(x)
+            self.header.write(str(x))
         self.set_option(pycurl.HEADERFUNCTION, header_callback)
 
     def set_url(self, url):
@@ -163,7 +159,7 @@ class Curl:
         """
         Set the given option.
         """
-        apply(self.handle.setopt, args)
+        self.handle.setopt(*args)
 
     def set_verbosity(self, level):
         """
@@ -335,7 +331,7 @@ class Curl:
         else:
             self.set_option(pycurl.FOLLOWLOCATION , 0)
             if self.fli:
-                print "\n[E] You must launch --follow-redirects command to set correctly this redirections limit\n"
+                print("\n[E] You must launch --follow-redirects command to set correctly this redirections limit\n")
                 return
         """ 
         Set the HTTP authentication method: Basic, Digest, GSS, NTLM or Certificate
@@ -343,11 +339,11 @@ class Curl:
         if self.atype and self.acred:
             atypelower = self.atype.lower()
             if atypelower not in ( "basic", "digest", "ntlm", "gss" ):
-                print "\n[E] HTTP authentication type value must be: Basic, Digest, GSS or NTLM\n"
+                print("\n[E] HTTP authentication type value must be: Basic, Digest, GSS or NTLM\n")
                 return
             acredregexp = re.search("^(.*?)\:(.*?)$", self.acred)
             if not acredregexp:
-                print "\n[E] HTTP authentication credentials value must be in format username:password\n"
+                print("\n[E] HTTP authentication credentials value must be in format username:password\n")
                 return
             user = acredregexp.group(1)
             password = acredregexp.group(2)
@@ -364,10 +360,10 @@ class Curl:
                 self.set_option(pycurl.HTTPAUTH, None)
             self.set_option(pycurl.HTTPHEADER, ["Accept:"])
         elif self.atype and not self.acred:
-            print "\n[E] You specified the HTTP authentication type, but did not provide the credentials\n"
+            print("\n[E] You specified the HTTP authentication type, but did not provide the credentials\n")
             return
         elif not self.atype and self.acred:
-            print "\n[E] You specified the HTTP authentication credentials, but did not provide the type\n"
+            print("\n[E] You specified the HTTP authentication credentials, but did not provide the type\n")
             return
         #if self.acert:
         #    acertregexp = re.search("^(.+?),\s*(.+?)$", self.acert)
@@ -411,7 +407,7 @@ class Curl:
         Get a url.
         """
         if params:
-            url += "?" + urllib.urlencode(params)
+            url += "?" + urllib.parse.urlencode(params)
         self.set_option(pycurl.HTTPGET, 1)
         return self.__request(url)
 
@@ -435,11 +431,11 @@ class Curl:
         """
         self.header.seek(0,0)
         url = self.handle.getinfo(pycurl.EFFECTIVE_URL)
-        if url[:5] == 'http:':
+        if url.startswith('http'):
             self.header.readline()
-            m = mimetools.Message(self.header)
+            m = email.message_from_string(str(self.header))
         else:
-            m = mimetools.Message(StringIO())
+            m = email.message_from_string(str(StringIO()))
         #m['effective-url'] = url
         m['http-code'] = str(self.handle.getinfo(pycurl.HTTP_CODE))
         m['total-time'] = str(self.handle.getinfo(pycurl.TOTAL_TIME))
@@ -467,37 +463,37 @@ class Curl:
         """
         Print selected options.
         """
-        print "\nCookie:", cls.cookie
-        print "User Agent:", cls.agent
-        print "Referer:", cls.referer
-        print "Extra Headers:", cls.headers
+        print("\nCookie:", cls.cookie)
+        print("User Agent:", cls.agent)
+        print("Referer:", cls.referer)
+        print("Extra Headers:", cls.headers)
         if cls.xforw == True:
-            print "X-Forwarded-For:", "Random IP"
+            print("X-Forwarded-For:", "Random IP")
         else:
-            print "X-Forwarded-For:", cls.xforw
+            print("X-Forwarded-For:", cls.xforw)
         if cls.xclient == True:
-            print "X-Client-IP:", "Random IP"
+            print("X-Client-IP:", "Random IP")
         else:
-            print "X-Client-IP:", cls.xclient
-        print "Authentication Type:", cls.atype
-        print "Authentication Credentials:", cls.acred
+            print("X-Client-IP:", cls.xclient)
+        print("Authentication Type:", cls.atype)
+        print("Authentication Credentials:", cls.acred)
         if cls.ignoreproxy == True:
-            print "Proxy:", "Ignoring system default HTTP proxy"
+            print("Proxy:", "Ignoring system default HTTP proxy")
         else:
-            print "Proxy:", cls.proxy
-        print "Timeout:", cls.timeout
+            print("Proxy:", cls.proxy)
+        print("Timeout:", cls.timeout)
         if cls.tcp_nodelay == True:
-            print "Delaying:", "TCP_NODELAY activate"
+            print("Delaying:", "TCP_NODELAY activate")
         else:
-            print "Delaying:", cls.delay, "seconds"
+            print("Delaying:", cls.delay, "seconds")
         if cls.followred == True:
-            print "Follow 302 code:", "active"
+            print("Follow 302 code:", "active")
             if cls.fli:
-                print"Limit to follow:", cls.fli
+                print("Limit to follow:", cls.fli)
         else:
-            print "Delaying:", cls.delay, "seconds"
+            print("Delaying:", cls.delay, "seconds")
 
-        print "Retries:", cls.retries, "\n"
+        print("Retries:", cls.retries, "\n")
 
     def answered(self, check):
         """

+ 27 - 27
core/dork.py

@@ -20,13 +20,13 @@ with xsser; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 ........
 
-List of search engines: http://en.wikipedia.org/wiki/List_of_search_engines
+List of search engines: https://en.wikipedia.org/wiki/List_of_search_engines
 
 Currently supported: duck(default), startpage, yahoo, bing
 
 """
-import urllib2, traceback, re, random, urllib
-urllib2.socket.setdefaulttimeout(5.0)
+import urllib.request, urllib.error, urllib.parse, traceback, re, random
+urllib.request.socket.setdefaulttimeout(5.0)
 
 DEBUG = 0
 
@@ -52,46 +52,46 @@ class Dorker(object):
         """
         if self._engine == 'bing': # works at 20-02-2011 -> 19-02-2016 -> 09-04-2018 -> 26-08-2019
             search_url = 'https://www.bing.com/search?q="' + str(search) + '"'
-            print "\nSearching query:", urllib2.unquote(search_url)
+            print("\nSearching query:", urllib.parse.unquote(search_url))
         elif self._engine == 'yahoo': # works at 20-02-2011 -> 19-02-2016 -> -> 09-04-2018 -> 26-08-2019
             search_url = 'https://search.yahoo.com/search?q="' + str(search) + '"'
-            print "\nSearching query:", urllib2.unquote(search_url)
+            print("\nSearching query:", urllib.parse.unquote(search_url))
         elif self._engine == 'duck': # works at 26-08-2019
             search_url = 'https://duckduckgo.com/html/' 
             q = 'instreamset:(url):"' + str(search) + '"' # set query to search literally on results
             query_string = { 'q':q }
-            print "\nSearching query:", urllib2.unquote(search_url) + " [POST: (" + q + ")]"
+            print("\nSearching query:", urllib.parse.unquote(search_url) + " [POST: (" + q + ")]")
         elif self._engine == 'startpage': # works at 26-08-2019
             search_url = 'https://www.startpage.com/do/asearch'
             q = 'url:"' + str(search) + '"' # set query to search literally on results
             query_string = { 'cmd':'process_search', 'query':q }
-            print "\nSearching query:", urllib2.unquote(search_url) + " [POST: (" + q + ")]"
+            print("\nSearching query:", urllib.parse.unquote(search_url) + " [POST: (" + q + ")]")
         else:
-            print "\n[Error] This search engine is not being supported!\n"
-            print '-'*25 
-            print "\n[Info] Use one from this list:\n"
+            print("\n[Error] This search engine is not being supported!\n")
+            print('-'*25) 
+            print("\n[Info] Use one from this list:\n")
             for e in self.search_engines:
-                print "+ "+e
-            print "\n ex: xsser -d 'profile.asp?num=' --De 'duck'"
-            print " ex: xsser -l --De 'startpage'"
-            print "\n[Info] Or try them all:\n\n ex: xsser -d 'news.php?id=' --Da\n"
+                print("+ "+e)
+            print("\n ex: xsser -d 'profile.asp?num=' --De 'duck'")
+            print(" ex: xsser -l --De 'startpage'")
+            print("\n[Info] Or try them all:\n\n ex: xsser -d 'news.php?id=' --Da\n")
         try:
             self.search_url = search_url
             user_agent = random.choice(self.agents).strip() # set random user-agent
             referer = '127.0.0.1' # set referer to localhost / WAF black magic!
             headers = {'User-Agent' : user_agent, 'Referer' : referer}
             if self._engine == 'bing' or self._engine == 'yahoo': # using GET
-                req = urllib2.Request(search_url, None, headers)
+                req = urllib.request.Request(search_url, None, headers)
             elif self._engine == 'duck' or self._engine == 'startpage': # using POST
-                data = urllib.urlencode(query_string)
-                req = urllib2.Request(search_url, data, headers)
-            html_data = urllib2.urlopen(req).read()
-            print "\n[Info] Retrieving requested info..."
-        except urllib2.URLError, e:
+                data = urllib.parse.urlencode(query_string)
+                req = urllib.request.Request(search_url, data, headers)
+            html_data = urllib.request.urlopen(req).read().decode('utf8')
+            print("\n[Info] Retrieving requested info...\n")
+        except urllib.error.URLError as e:
             if DEBUG:
                 traceback.print_exc()
-            print "\n[Error] Cannot connect!"
-            print "\n" + "-"*50
+            print("\n[Error] Cannot connect!")
+            print("\n" + "-"*50)
             return
         if self._engine == 'bing':
             regex = '<h2><a href="(.+?)" h=' # regex magics 08/2019
@@ -102,11 +102,11 @@ class Dorker(object):
         if self._engine == 'startpage':
             regex = 'target="_blank">(.+?)</a>' # regex magics 08/2019
         pattern = re.compile(regex)
-        links = re.findall(pattern, html_data)
+        links = re.findall(pattern, html_data, flags=0)
         found_links = []
         if links:
             for link in links:
-                link = urllib2.unquote(link)
+                link = urllib.parse.unquote(link)
                 if self._engine == "yahoo":
                     if "RU=https://www.yahoo.com/" in link:
                         link = "" # invalid url
@@ -116,7 +116,7 @@ class Dorker(object):
                     if link2 not in found_links: # parse that target is not duplicated
                         found_links.append(link)
         else:
-            print "\n[Error] Not any link found for that query!"
+            print("\n[Error] Not any link found for that query!")
         return found_links
 
 if __name__ == '__main__':
@@ -124,6 +124,6 @@ if __name__ == '__main__':
         dork = Dorker(a)
         res = dork.dork("news.php?id=")
         if res:
-            print "\n[+] Search Engine:", a, "| Found: ", len(res), "\n"
+            print("\n[+] Search Engine:", a, "| Found: ", len(res), "\n")
             for b in res:
-                print " *", b
+                print(" *", b)

+ 4 - 4
core/encdec.py

@@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License along
 with xsser; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
-import urllib
+import urllib.request, urllib.parse, urllib.error
 
 class EncoderDecoder(object):
     """
@@ -78,7 +78,7 @@ class EncoderDecoder(object):
         """
         encoded=''
         for char in string:
-            encoded=encoded+urllib.quote(char)
+            encoded=encoded+urllib.parse.quote(char)
         return encoded
 
     def _ipDwordEncode(self, string):
@@ -106,9 +106,9 @@ class EncoderDecoder(object):
         # In the case it's not an IP
         if len(tblIP)!=4:
             return 0
-        octIP = map(lambda s: oct(int(s)).zfill(4), tblIP)
+        octIP = [oct(int(s)).zfill(4) for s in tblIP]
         return ".".join(octIP)
 
 if __name__ == "__main__":
     encdec = EncoderDecoder()
-    print encdec._ipOctalEncode("127.0.0.1")
+    print(encdec._ipOctalEncode("127.0.0.1"))

+ 1 - 1
core/flashxss.py

@@ -47,4 +47,4 @@ class FlashInjections(object):
 
 if __name__ == '__main__':
     flash_xss_injection = FlashInjections('')
-    print flash_xss_injection.flash_xss('FlashXSSpoison.swf' , "<script>alert('XSS')</script>")
+    print(flash_xss_injection.flash_xss('FlashXSSpoison.swf' , "<script>alert('XSS')</script>"))

+ 61 - 67
core/globalmap.py

@@ -20,22 +20,31 @@ with xsser; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
 import os
-import gtk
-import user
-import gobject
+from pathlib import Path
+import gi
+gi.require_version('Gtk', '3.0')
+gi.require_version('Gdk', '3.0')
+gi.require_version('PangoCairo', '1.0')
+from gi.repository import Gtk as gtk
+from gi.repository import Gdk as gdk
+gdk.threads_init()
+from gi.repository import GObject as gobject
+from gi.repository import PangoCairo as pangocairo
+from gi.repository import GdkPixbuf
 from core.reporter import XSSerReporter
 from core.curlcontrol import Curl
-from glib import markup_escape_text
 from collections import defaultdict
 from threading import Thread
 import traceback
-import urllib
-import urlparse
+import urllib.request, urllib.parse, urllib.error
 import math
 import cairo
+import cairocffi
 import gzip
-import pangocairo
 import time
+from PIL import Image
+import array
+import GeoIP
 
 class PointType(object):
     checked = 15
@@ -96,19 +105,15 @@ class DownloadThread(Thread):
             os.makedirs(os.path.dirname(geo_db_path))
         self._parent.report_state('getting city database', 0.0)
         try:
-            urllib.urlretrieve('http://xsser.03c8.net/map/GeoLiteCity.dat.gz',
+            urllib.request.urlretrieve('https://xsser.03c8.net/map/GeoLite2-City.dat.gz',
                            geo_db_path+'.gz', reportfunc)
         except:
             try:
-                urllib.urlretrieve('http://xsser.sf.net/map/GeoLiteCity.dat.gz',
+                urllib.request.urlretrieve('https://xsser.sf.net/map/GeoLite2-City.dat.gz',
                            geo_db_path+'.gz', reportfunc)
             except:
-                try:
-                    urllib.urlretrieve('http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz',
-                           geo_db_path+'.gz', reportfunc)
-                except:
-                    self._parent.report_state('error downloading map', 0.0)
-                    self._map.geomap_failed()
+                self._parent.report_state('error downloading map', 0.0)
+                self._map.geomap_failed()
         else:
             self._parent.report_state('map downloaded (restart XSSer!!!!)', 0.0)
             f_in = gzip.open(geo_db_path+'.gz', 'rb')
@@ -135,14 +140,14 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
             self.finish_init()
 
     def geomap_ready(self):
-        gtk.gdk.threads_enter()
+        gdk.threads_enter()
         gobject.timeout_add(0, self.finish_init)
-        gtk.gdk.threads_leave()
+        gdk.threads_leave()
 
     def geomap_failed(self):
-        gtk.gdk.threads_enter()
+        gdk.threads_enter()
         gobject.timeout_add(0, self.failed_init)
-        gtk.gdk.threads_leave()
+        gdk.threads_leave()
 
     def failed_init(self):
         if hasattr(self, '_t'):
@@ -150,7 +155,6 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
             delattr(self, '_t')
 
     def finish_init(self):
-        import GeoIP
         if hasattr(self, '_t'):
             self._t.join()
             delattr(self, '_t')
@@ -176,20 +180,20 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
         self._frozenlines = []
         self._points = []
         self._crosses = []
-        self.connect("expose_event", self.expose)
+        self.connect('draw', self.expose)
         self.connect("query-tooltip", self.on_query_tooltip)
-        if self.window:
-            self.window.invalidate_rect(self.allocation, True)
+        self.queue_draw()
         if not self._onattack:
             self.add_test_points()
 
     def get_geodb_path(self):
         ownpath = os.path.dirname(os.path.dirname(__file__))
         gtkpath = os.path.join(ownpath, 'gtk')
-        if os.path.exists(os.path.join(gtkpath, 'GeoLiteCity.dat')):
-            return os.path.join(gtkpath, 'GeoLiteCity.dat')
+        if os.path.exists(os.path.join(gtkpath, 'map/GeoIP.dat')):
+            return os.path.join(gtkpath, 'map/GeoIP.dat')
         else:
-            return os.path.join(user.home, '.xsser', 'GeoLiteCity.dat')
+            home = str(Path.home())
+            return os.path.join(home, '.xsser', 'GeoIP.dat')
 
     def find_points(self, x, y, distance=9.0):
         points = []
@@ -202,8 +206,8 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
                 points.append(self._points[point[2]])
                 self._selected.append(point[2])
         if points:
-            rect = gtk.gdk.Rectangle(0,0,self.width, self.height)
-            self.window.invalidate_rect(rect, True)
+            rect = gdk.Rectangle()
+            self.queue_draw()
         return points
 
     def on_query_tooltip(self, widget, x, y, keyboard_mode, tooltip):
@@ -223,21 +227,21 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
                 crawls.extend(point.reports[PointType.crawled])
             if finalsuccess:
                 text += "<b>browser checked sucesses:</b>\n"
-                text += "\n".join(map(lambda s: markup_escape_text(s), finalsuccess))
+                text += "\n".join(map(lambda s: gobject.markup_escape_text(s), finalsuccess))
                 if failures or success:
                     text += "\n"
 
             if success:
                 text += "<b>sucesses:</b>\n"
-                text += "\n".join(map(lambda s: markup_escape_text(s), success))
+                text += "\n".join(map(lambda s: gobject.markup_escape_text(s), success))
                 if failures:
                     text += "\n"
             if failures:
                 text += "<b>failures:</b>\n"
-                text += "\n".join(map(lambda s: markup_escape_text(s), failures))
+                text += "\n".join(map(lambda s: gobject.markup_escape_text(s), failures))
             if crawls and not failures and not success:
                 text += "<b>crawls:</b>\n"
-                text += "\n".join(map(lambda s: markup_escape_text(s), crawls))
+                text += "\n".join(map(lambda s: gobject.markup_escape_text(s), crawls))
 
             tooltip.set_markup(str(text))
             return True
@@ -260,26 +264,20 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
         self._crosses = []
         self._stats = [0,0,0,0,0,0,0]
 
-    def expose(self, widget, event):
+    def expose(self, widget, cr):
         if not self.mapcontext:
             self._mappixbuf = self._pixbuf.copy()
-            self.mapsurface = cairo.ImageSurface.create_for_data(self._mappixbuf.get_pixels_array(), 
-                                               cairo.FORMAT_ARGB32,
-                                               self.width,
-                                               self.height,
-                                               self._pixbuf.get_rowstride())
+            self.mapsurface = cairo.ImageSurface.create_from_png('gtk/images/world.png')
             self.mapcontext = cairo.Context(self.mapsurface)
+        self.context = cr
         self.draw_frozen_lines()
-        self.context = self.window.cairo_create()
-      
         self.context.set_source_surface(self.mapsurface)
-        self.context.rectangle(event.area.x, event.area.y,
-                              event.area.width, event.area.height)
-        self.context.clip()
-        self.context.rectangle(event.area.x, event.area.y,
-                              event.area.width, event.area.height)
+        self.context.rectangle(self._min_x, self._max_x, self.width, self.height)
+        self.context.fill()
+        self.context.rectangle(self._min_x, self._max_x, self.width, self.height)
         self.context.fill()
-        self.context.set_source_color(gtk.gdk.Color(0,0,0))
+        self.context.paint()
+        self.context.set_source_rgb(0,0,0)
         self._min_x = 5 # we have the scale at the left for now
         self._max_x = 0
         if self.geo:
@@ -309,9 +307,8 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
         for point in self._points:
             key = (point.latitude, point.longitude)
             newpoints[key].append(point)
-
         self._points = []
-        for points in newpoints.itervalues():
+        for points in newpoints.values():
             win_type = points[0]
             win_size = points[0]
             for point in points[1:]:
@@ -410,8 +407,8 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
         self.context.move_to(x, y)
         v = (5.0-self._current_text[1])/5.0
         self.context.scale(0.1+max(v, 1.0), 0.1+max(v, 1.0))
-        self.context.set_source_color(gtk.gdk.Color(*gtkcol((v,)*3)))
-        u = urlparse.urlparse(text)
+        self.context.set_source_rgb(*gtkcol((v,)*3))
+        u = urllib.parse.urlparse(text)
         self.context.show_text(u.netloc)
         self.context.restore()
 
@@ -442,7 +439,7 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
     def draw_point(self, point):
         if point.size:
             self.context.save()
-            self.context.set_source_color(gtk.gdk.Color(*point.gtkcolor))
+            self.context.set_source_rgb(*point.gtkcolor)
             self.context.translate(point.x, point.y)
             self.context.arc(0.0, 0.0, 2.4*point.size, 0, 2*math.pi)
             self.context.close_path()
@@ -455,7 +452,7 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
             self.context.translate(point.x, point.y)
             self.context.rotate(point.size)
             self.context.set_line_width(0.8*point.size)
-            self.context.set_source_color(gtk.gdk.Color(*point.gtkcolor))
+            self.context.set_source_rgb(*point.gtkcolor)
             self.context.move_to(-3*point.size, -3*point.size)
             self.context.rel_line_to(6*point.size, 6*point.size)
             self.context.stroke()
@@ -488,11 +485,8 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
         self.clear()
 
     def queue_redraw(self):
-        rect = gtk.gdk.region_rectangle((self._min_x,0,self._max_x-self._min_x,
-                                  self.height))
-        if self.window:
-            self.window.invalidate_region(rect, True)
-            del rect
+        rect = gdk.Rectangle()
+        self.queue_draw()
 
     def mosquito_crashed(self, dest_url, reason):
         self._current_text = [dest_url, 5.0]
@@ -502,9 +496,9 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
         except:
             return
         self.add_cross(lon, lat, crash_color, dest_url)
-        gtk.gdk.threads_enter()
+        gdk.threads_enter()
         self.queue_redraw()
-        gtk.gdk.threads_leave()
+        gdk.threads_leave()
 
     def add_checked(self, dest_url):
         self._current_text = [dest_url, 5.0]
@@ -514,9 +508,9 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
         except:
             return
         self.add_point(lon, lat, PointType.checked, dest_url)
-        gtk.gdk.threads_enter()
+        gdk.threads_enter()
         self.queue_redraw()
-        gtk.gdk.threads_leave()
+        gdk.threads_leave()
 
     def add_success(self, dest_url):
         self._current_text = [dest_url, 5.0]
@@ -526,9 +520,9 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
         except:
             return
         self.add_point(lon, lat, PointType.success, dest_url)
-        gtk.gdk.threads_enter()
+        gdk.threads_enter()
         self.queue_redraw()
-        gtk.gdk.threads_leave()
+        gdk.threads_leave()
 
     def add_failure(self, dest_url):
         self._current_text = [dest_url, 5.0]
@@ -538,9 +532,9 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
         except:
             return
         self.add_point(lon, lat, PointType.failed, dest_url)
-        gtk.gdk.threads_enter()
+        gdk.threads_enter()
         self.queue_redraw()
-        gtk.gdk.threads_leave()
+        gdk.threads_leave()
 
     def add_link(self, orig_url, dest_url):
         try:
@@ -566,9 +560,9 @@ class GlobalMap(gtk.DrawingArea, XSSerReporter):
         except:
             return
         self.add_point(lon, lat, PointType.crawled, dest_url)
-        gtk.gdk.threads_enter()
+        gdk.threads_enter()
         self.queue_redraw()
-        gtk.gdk.threads_leave()
+        gdk.threads_leave()
 
     def plot_point_mercator(self, lat, lng):
         longitude_shift = -23

+ 90 - 85
core/gtkcontroller.py

@@ -22,16 +22,19 @@ Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 import sys
 import os, datetime 
 import math
-import gtk
 import socket
-import urlparse
 import webbrowser
 import threading
-import gobject
+import gi
+gi.require_version('Gtk', '3.0')
+gi.require_version('Gdk', '3.0')
+from gi.repository import Gtk as gtk
+from gi.repository import Gdk as gdk
+from gi.repository import GLib as gobject
 from threading import Thread
 from xml.dom import minidom
 
-gtk.gdk.threads_init()
+gdk.threads_init()
 
 use_twisted = False
 
@@ -70,7 +73,6 @@ class Controller(XSSerReporter):
         self.output_wizard = wTree.get_object('textview_w_start')
         self._wizard_buffer = self.output_wizard.get_buffer()
         self.counters_label = wTree.get_object('counters_label')
-
         self._report_vulnerables = wTree.get_object('report_vulnerables').get_buffer()
         self._report_success = wTree.get_object('report_success').get_buffer()
         self._report_failed = wTree.get_object('report_failed').get_buffer()
@@ -214,10 +216,10 @@ class Controller(XSSerReporter):
         combobox.add_attribute(cell, 'text', 0)  
 
     def start_crawl(self, dest_url):
-        gtk.gdk.threads_enter()
+        gdk.threads_enter()
         self.status.set_text("scanning")
         self.status.pulse()
-        gtk.gdk.threads_leave()
+        gdk.threads_leave()
         self.add_report_text(self._report_crawling, dest_url)
 
     def add_checked(self, dest_url):
@@ -226,9 +228,9 @@ class Controller(XSSerReporter):
     def add_success(self, dest_url):
         self.add_report_text(self._report_vulnerables, dest_url)
         totalhits = self.wTree.get_object('totalhits')
-        totalhits.set_property("label", int(totalhits.get_property("label"))+1)
+        totalhits.set_property("label", str(int(totalhits.get_property("label"))+1))
         successhits = self.wTree.get_object('successhits')
-        successhits.set_property("label", int(successhits.get_property("label"))+1)
+        successhits.set_property("label", str(int(successhits.get_property("label"))+1))
 
     def report_error(self, error_msg):
         self.add_report_text(self._report_failed, error_msg)
@@ -239,20 +241,19 @@ class Controller(XSSerReporter):
     def add_failure(self, dest_url):
         self.add_report_text(self._report_failed, dest_url)
         totalhits = self.wTree.get_object('totalhits')
-        totalhits.set_property("label", int(totalhits.get_property("label"))+1)
+        totalhits.set_property("label", str(int(totalhits.get_property("label"))+1))
         failedhits = self.wTree.get_object('failedhits')
-        failedhits.set_property("label", int(failedhits.get_property("label"))+1)
+        failedhits.set_property("label", str(int(failedhits.get_property("label"))+1))
 
     def add_report_text(self, gtkbuffer, text):
-        gtk.gdk.threads_enter()
+        gdk.threads_enter()
         iter = gtkbuffer.get_end_iter()
         gtkbuffer.insert(iter, text+'\n')
-        gtk.gdk.threads_leave()
+        gdk.threads_leave()
 
     def setup_mozembed(self):
         self.moz = MozChecker(self)
         self.mothership.set_webbrowser(self.moz)
-        #self.moz.hide()
 
     def fill_combos(self):
         # ui comboboxes
@@ -301,27 +302,32 @@ class Controller(XSSerReporter):
             auth_none.set_property('active', True)
  
         commandsenter = self.wTree.get_object('commandsenter')
-        cmd = self.generate_command()
-        commandsenter.set_property("text"," ".join(cmd))
+
+        targetenter = self.wTree.get_object('targetenter')
+        explorer_enter = self.wTree.get_object('explorer_enter')
+        if targetenter.get_text() == "" and explorer_enter.get_text() == "":
+            pass
+        else:
+            cmd = self.generate_command()
+            commandsenter.set_property("text"," ".join(cmd))
     
-        app = xsser()
-        options = app.create_options(cmd)
-        app.set_options(options)
+            app = xsser()
+            options = app.create_options(cmd)
+            app.set_options(options)
         
-        app.set_reporter(self)
-        pass
+            app.set_reporter(self)
+            pass
 
-        # set visor counters to zero
-        totalhits = self.wTree.get_object('totalhits')
-        totalhits.set_property("label", "0")
-        failedhits = self.wTree.get_object('failedhits')
-        failedhits.set_property("label", "0")
-        successhits = self.wTree.get_object('successhits')
-        successhits.set_property("label", "0")
+            # set visor counters to zero
+            totalhits = self.wTree.get_object('totalhits')
+            totalhits.set_property("label", "0")
+            failedhits = self.wTree.get_object('failedhits')
+            failedhits.set_property("label", "0")
+            successhits = self.wTree.get_object('successhits')
+            successhits.set_property("label", "0")
 
     def end_attack(self):
-        #self._flying.join()
-        gtk.gdk.threads_enter()
+        gdk.threads_enter()
         self.status.set_text("idle")
         self.status.set_fraction(0.0)
         fly_button = self.wTree.get_object('fly')
@@ -329,10 +335,9 @@ class Controller(XSSerReporter):
         fly_button.set_sensitive(True)
         if self._quitting:
             pass
-            #self.do_quit()
         else:
             gobject.timeout_add(0, self.park_mosquito)
-        gtk.gdk.threads_leave()
+        gdk.threads_leave()
 
     def park_mosquito(self):
         self._flying.join()
@@ -383,24 +388,24 @@ class Controller(XSSerReporter):
             crawled = "X"
         pars = [crawled, rem, th_count, work_count]
 
-        gtk.gdk.threads_enter()
+        gdk.threads_enter()
         self.counters_label.set_text(" ".join(pars))
         if pars[3]:
             pars[3] = "\nworks in queue: %s"%(pars[3],)
         self.counters_label.set_tooltip_text('crawled during last attack: %s\nremaining checks: %s\nalive threads: %s %s' % tuple(pars))
-        gtk.gdk.threads_leave()
+        gdk.threads_leave()
 
     def report_state(self, state, val=-1):
         if not gtk:
             # exiting..
             return
-        gtk.gdk.threads_enter()
+        gdk.threads_enter()
         self.status.set_text(state)
         if val == -1:
             self.status.pulse()
         else:
             self.status.set_fraction(val)
-        gtk.gdk.threads_leave()
+        gdk.threads_leave()
         self.update_counters_label()
 
     def on_fly_clicked(self, widget):
@@ -436,7 +441,7 @@ class Controller(XSSerReporter):
 
         if t.app.options == None:
             pass
-        elif targetenter.get_text() == None and explorer_enter.get_text() == None:
+        elif targetenter.get_text() == "" and explorer_enter.get_text() == "":
             pass
         else:
             t.start()
@@ -773,15 +778,15 @@ class Controller(XSSerReporter):
         hboxurl = self.wTree.get_object('hboxurl')
         vboxdork = self.wTree.get_object('vboxdork')
         next1 = self.wTree.get_object('next1')
-        if combo_choose.get_active_text() == '0':
+        if combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '0':
             vbox_step.set_property("visible", False)
             next1.set_property("visible", False)
-        if combo_choose.get_active_text() == '1':
+        if combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '1':
             vbox_step.set_property("visible", True)
             hboxurl.set_property("visible", True)
             vboxdork.set_property("visible", False)
             next1.set_property("visible", True)
-        elif combo_choose.get_active_text() == '2':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '2':
             vbox_step.set_property("visible", True)
             hboxurl.set_property("visible", False)
             vboxdork.set_property("visible", True)
@@ -815,12 +820,12 @@ class Controller(XSSerReporter):
         alert_step1_url = self.wTree.get_object('alert_step1_url')
         alert_step1_dork = self.wTree.get_object('alert_step1_dork')
 
-        if step1_entry_url.get_text() == '' and (combo_choose.get_active_text() == '1'):
+        if step1_entry_url.get_text() == '' and (combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '1'):
             alert_step1_url.set_property("visible", True)
             step_view1.set_property("visible", True)
             step_view2.set_property("visible", False)
 
-        elif step1_entry_dork.get_text() == '' and (combo_choose.get_active_text() == '2'):
+        elif step1_entry_dork.get_text() == '' and (combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '2'):
             alert_step1_dork.set_property("visible", True)
             step_view1.set_property("visible", True)
             step_view2.set_property("visible", False)
@@ -830,10 +835,10 @@ class Controller(XSSerReporter):
             step_view1.set_property("visible", False)
             step_view2.set_property("visible", True)
 
-        self.combo_step1_choose = combo_choose.get_active_text()
+        self.combo_step1_choose = combo_choose.get_model().get_value(combo_choose.get_active_iter(),0)
         self.target_option = step1_entry_url.get_text()
         self.dork_option = step1_entry_dork.get_text()
-        self.dorkengine_option = step1_entry_dorkengine.get_active_text()
+        self.dorkengine_option = step1_entry_dorkengine.get_model().get_value(step1_entry_dorkengine.get_active_iter(),0)
 
     def on_combobox_step2_changed(self, widget):
         combo_choose = self.wTree.get_object('combobox_step2')
@@ -841,26 +846,26 @@ class Controller(XSSerReporter):
         step2_entry_payload = self.wTree.get_object('step2_entry_payload')
         alert_step2 = self.wTree.get_object('alert_step2')
         next2 = self.wTree.get_object('next2')
-        if combo_choose.get_active_text() == '0':
+        if combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '0':
             vbox_step2.set_property("visible", False)
             alert_step2.set_property("visible", False)
             next2.set_property("visible", False)
             step2_entry_payload.set_property("text", "")
-        if combo_choose.get_active_text() == '1':
+        if combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '1':
             vbox_step2.set_property("visible", True)
             alert_step2.set_property("visible", False)
             next2.set_property("visible", True)
             step2_entry_payload.set_property("text", "")
-        elif combo_choose.get_active_text() == '2':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '2':
             vbox_step2.set_property("visible", True)
             next2.set_property("visible", True)
             alert_step2.set_property("visible", False)
             step2_entry_payload.set_property("text", "")
-        elif combo_choose.get_active_text() == '3':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '3':
             vbox_step2.set_property("visible", False)
             next2.set_property("visible", True)
             alert_step2.set_property("visible", False)
-        elif combo_choose.get_active_text() == '4':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '4':
             vbox_step2.set_property("visible", False)
             next2.set_property("visible", True)
             alert_step2.set_property("visible", False)
@@ -893,7 +898,7 @@ class Controller(XSSerReporter):
         combo_choose = self.wTree.get_object('combobox_step2')
         step2_entry_payload = self.wTree.get_object('step2_entry_payload')
         alert_step2 = self.wTree.get_object('alert_step2')
-        if step2_entry_payload.get_text() == '' and (combo_choose.get_active_text() == '1' or combo_choose.get_active_text() == '2') :
+        if step2_entry_payload.get_text() == '' and (combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '1' or combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '2') :
             alert_step2.set_property("visible", True)
             step_view2.set_property("visible", True)
             step_view3.set_property("visible", False)
@@ -902,7 +907,7 @@ class Controller(XSSerReporter):
             step_view2.set_property("visible", False) 
             step_view3.set_property("visible", True)
 
-        self.combo_step2_choose = combo_choose.get_active_text()
+        self.combo_step2_choose = combo_choose.get_model().get_value(combo_choose.get_active_iter(),0)
         self.payload_option = step2_entry_payload.get_text()
 
     def on_combobox_step3_changed(self, widget):
@@ -911,25 +916,25 @@ class Controller(XSSerReporter):
         step3_entry_proxy = self.wTree.get_object('step3_entry_proxy')
         alert_step3 = self.wTree.get_object('alert_step3')
         next3 = self.wTree.get_object('next3')
-        if combo_choose.get_active_text() == '0':
+        if combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '0':
             vbox_step3.set_property("visible", False)
             alert_step3.set_property("visible", False)
             next3.set_property("visible", False)
             step3_entry_proxy.set_property("text", "")
-        if combo_choose.get_active_text() == '1':
+        if combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '1':
             vbox_step3.set_property("visible", True)
             alert_step3.set_property("visible", False)
             next3.set_property("visible", True)
             step3_entry_proxy.set_property("text", "")
-        elif combo_choose.get_active_text() == '2':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '2':
             vbox_step3.set_property("visible", False)
             next3.set_property("visible", True)
             alert_step3.set_property("visible", False)
-        elif combo_choose.get_active_text() == '3':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '3':
             vbox_step3.set_property("visible", False)
             next3.set_property("visible", True)
             alert_step3.set_property("visible", False)
-        elif combo_choose.get_active_text() == '4':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '4':
             vbox_step3.set_property("visible", False)
             next3.set_property("visible", True)
             alert_step3.set_property("visible", False)
@@ -955,7 +960,7 @@ class Controller(XSSerReporter):
         combo_choose = self.wTree.get_object('combobox_step3')
         step3_entry_proxy = self.wTree.get_object('step3_entry_proxy')
         alert_step3 = self.wTree.get_object('alert_step3')
-        if step3_entry_proxy.get_text() == '' and combo_choose.get_active_text() == '1':
+        if step3_entry_proxy.get_text() == '' and combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '1':
             alert_step3.set_property("visible", True)
             step_view3.set_property("visible", True)
             step_view4.set_property("visible", False)
@@ -964,9 +969,9 @@ class Controller(XSSerReporter):
             step_view3.set_property("visible", False)
             step_view4.set_property("visible", True)
 
-        self.combo_step3_choose = combo_choose.get_active_text()
+        self.combo_step3_choose = combo_choose.get_model().get_value(combo_choose.get_active_iter(),0)
         self.proxy_option = step3_entry_proxy.get_text()
-        if combo_choose.get_active_text() == '2':
+        if combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '2':
             self.proxy_option = "http://127.0.0.1:8118"
 
     def on_combobox_step4_changed(self, widget):
@@ -975,27 +980,27 @@ class Controller(XSSerReporter):
         step4_entry_cem = self.wTree.get_object('step4_entry_cem')
         alert_step4 = self.wTree.get_object('alert_step4')
         next4 = self.wTree.get_object('next4')
-        if combo_choose.get_active_text() == '0':
+        if combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '0':
             vbox_step4.set_property("visible", False)
             alert_step4.set_property("visible", False)
             next4.set_property("visible", False)
             step4_entry_cem.set_property("text", "")
-        elif combo_choose.get_active_text() == '1':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '1':
             vbox_step4.set_property("visible", False)
             alert_step4.set_property("visible", False)
             next4.set_property("visible", True)
-        elif combo_choose.get_active_text() == '2':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '2':
             vbox_step4.set_property("visible", False)
             alert_step4.set_property("visible", False)
             next4.set_property("visible", True)
-        elif combo_choose.get_active_text() == '3':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '3':
             vbox_step4.set_property("visible", False)
             alert_step4.set_property("visible", False)
             next4.set_property("visible", True)
-        elif combo_choose.get_active_text() == '4':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '4':
             vbox_step4.set_property("visible", True)
             next4.set_property("visible", True)
-        elif combo_choose.get_active_text() == '5':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '5':
             vbox_step4.set_property("visible", False)
             next4.set_property("visible", True)
             alert_step4.set_property("visible", False)
@@ -1019,7 +1024,7 @@ class Controller(XSSerReporter):
         combo_choose = self.wTree.get_object('combobox_step4')
         step4_entry_cem = self.wTree.get_object('step4_entry_cem')
         alert_step4 = self.wTree.get_object('alert_step4')
-        if step4_entry_cem.get_text() == '' and combo_choose.get_active_text() == '4':
+        if step4_entry_cem.get_text() == '' and combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '4':
             alert_step4.set_property("visible", True)
             step_view4.set_property("visible", True)
             step_view5.set_property("visible", False)
@@ -1028,7 +1033,7 @@ class Controller(XSSerReporter):
             step_view4.set_property("visible", False)
             step_view5.set_property("visible", True)
 
-        self.combo_step4_choose = combo_choose.get_active_text()
+        self.combo_step4_choose = combo_choose.get_model().get_value(combo_choose.get_active_iter(),0)
         self.cem_option = step4_entry_cem.get_text()
 
     def on_combobox_step5_changed(self, widget):
@@ -1037,20 +1042,20 @@ class Controller(XSSerReporter):
         step5_entry_scripts = self.wTree.get_object('step5_entry_scripts')
         alert_step5 = self.wTree.get_object('alert_step5')
         next5 = self.wTree.get_object('next5')
-        if combo_choose.get_active_text() == '0':
+        if combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '0':
             vbox_step5.set_property("visible", False)
             alert_step5.set_property("visible", False)
             next5.set_property("visible", False)
             step5_entry_scripts.set_property("text", "")
-        elif combo_choose.get_active_text() == '1':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '1':
             vbox_step5.set_property("visible", False)
             alert_step5.set_property("visible", False)
             next5.set_property("visible", True)
-        elif combo_choose.get_active_text() == '2':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '2':
             vbox_step5.set_property("visible", True)
             alert_step5.set_property("visible", False)
             next5.set_property("visible", True)
-        elif combo_choose.get_active_text() == '3':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '3':
             vbox_step5.set_property("visible", False)
             alert_step5.set_property("visible", False)
             next5.set_property("visible", True)
@@ -1076,7 +1081,7 @@ class Controller(XSSerReporter):
         combo_choose = self.wTree.get_object('combobox_step5')
         step5_entry_scripts = self.wTree.get_object('step5_entry_scripts')
         alert_step5 = self.wTree.get_object('alert_step5')
-        if step5_entry_scripts.get_text() == '' and combo_choose.get_active_text() == '2':
+        if step5_entry_scripts.get_text() == '' and combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == '2':
             alert_step5.set_property("visible", True)
             step_view5.set_property("visible", True)
             step_view_end.set_property("visible", False)
@@ -1085,7 +1090,7 @@ class Controller(XSSerReporter):
             step_view5.set_property("visible", False)
             step_view_end.set_property("visible", True)
 
-        self.combo_step5_choose = combo_choose.get_active_text()
+        self.combo_step5_choose = combo_choose.get_model().get_value(combo_choose.get_active_iter(),0)
         self.scripts_option = step5_entry_scripts.get_text()
 
         # building end form
@@ -1311,23 +1316,23 @@ class Controller(XSSerReporter):
         image_geomap = self.wTree.get_object('image_geomap')
         vbox9 = self.wTree.get_object('vbox9')
 
-        if combo_choose.get_active_text() == 'OFF':
+        if combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == 'OFF':
             self.map.set_property("visible", False)
             vbox9.set_property("visible", False)
             if self._flying:
                 self._flying.remove_reporter(self.map)
                 self.mothership.remove_reporter(self.map)
 
-        elif combo_choose.get_active_text() == 'ON':
+        elif combo_choose.get_model().get_value(combo_choose.get_active_iter(),0) == 'ON':
             vbox9.set_property("visible", True)
             if not self.map:
                 image_geomap.realize()
                 drawarea = GlobalMap(self, image_geomap.get_pixbuf(), self._flying)
-                vbox = image_geomap.parent
+                vbox = image_geomap.get_parent()
                 vbox.remove(image_geomap)
                 eventbox = gtk.EventBox()
                 eventbox.add(drawarea)
-                vbox.pack_end(eventbox)
+                vbox.pack_end(eventbox, True, True, 0)
                 eventbox.show()
                 drawarea.show()
                 self.map = drawarea
@@ -1352,7 +1357,7 @@ class Controller(XSSerReporter):
         """
         Donate something
         """
-        webbrowser.open("http://03c8.net")
+        webbrowser.open("https://03c8.net")
 
     def generate_command(self):
         command = ["xsser"]
@@ -1392,7 +1397,7 @@ class Controller(XSSerReporter):
                 command.append("-d")
                 command.append(explorer_enter.get_text())
                 command.append("--De")
-                command.append(dork_engine.get_active_text())
+                command.append(dork_engine.get_model().get_value(dork_engine.get_active_iter(),0))
 
         # get crawler test mode (common crawling c=50 Cw=3)
         crawler = self.wTree.get_object('crawler')
@@ -1570,20 +1575,20 @@ class Controller(XSSerReporter):
         else:
             command.append("--discode")
             command.append(target_entry.get_text())
-       # get FOLLOWREDIRECTS
+        # get FOLLOWREDIRECTS
         target_entry = self.wTree.get_object('followredirects')
         if target_entry.get_active() == False:
             pass
         else:
             command.append("--follow-redirects")
-       # get FOLLOW-LIMIT
+        # get FOLLOW-LIMIT
         target_entry = self.wTree.get_object('follow-limit')
         if target_entry.get_value() == 0:
             pass
         else:
             command.append("--follow-limit")
             command.append(str(int(target_entry.get_value())))
-       # get ISALIVE
+        # get ISALIVE
         target_entry = self.wTree.get_object('alive-limit')
         if target_entry.get_value() == 0:
             pass
@@ -1600,7 +1605,7 @@ class Controller(XSSerReporter):
             command.append("--checkaturl")
             command.append(target_entry.get_text())
             command.append("--checkmethod")
-            command.append(check_method.get_active_text())
+            command.append(check_method.get_model().get_value(checkmethod.get_active_iter(),0))
             if check_data.get_text() == "":
                 pass
             else: 
@@ -1960,9 +1965,9 @@ class Controller(XSSerReporter):
         """
         Callback called by xsser when it has output for the user
         """
-        gtk.gdk.threads_enter()
+        gdk.threads_enter()
         self.post_ui(msg)
-        gtk.gdk.threads_leave()
+        gdk.threads_leave()
 
     def post_ui(self, msg):
         """

+ 1 - 1
core/imagexss.py

@@ -58,4 +58,4 @@ class ImageInjections(object):
 
 if __name__ == '__main__':
     image_xss_injection = ImageInjections('')
-    print image_xss_injection.image_xss('ImageXSSpoison.png' , "<script>alert('XSS')</script>")
+    print(image_xss_injection.image_xss('ImageXSSpoison.png' , "<script>alert('XSS')</script>"))

File diff suppressed because it is too large
+ 184 - 179
core/main.py


+ 9 - 5
core/mozchecker.py

@@ -19,9 +19,14 @@ You should have received a copy of the GNU General Public License along
 with xsser; if not, write to the Free Software Foundation, Inc., 51
 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 """
-import gtk
+import gi
+gi.require_version('Gtk', '3.0')
+gi.require_version('Gdk', '3.0')
+from gi.repository import Gtk as gtk
+from gi.repository import Gdk as gdk
+gdk.threads_init()
 import sys
-import gobject
+from gi.repository import GObject as gobject
 import subprocess
 from threading import Thread
 try:
@@ -30,7 +35,6 @@ except:
     MozEmbed = None
     import webbrowser
 
-
 class CheckerThread(Thread):
     def __init__(self, parent, url):
         Thread.__init__(self)
@@ -105,9 +109,9 @@ class MozChecker(object):
         print("net_state", widget, flags, status)
 
     def on_net_stop(self, widget=None):
-        gtk.gdk.threads_enter()
+        gdk.threads_enter()
         gobject.timeout_add(0, self.process_next)
-        gtk.gdk.threads_leave()
+        gdk.threads_leave()
 
     def process_next(self):
         if self._urlqueue and self._armed:

+ 23 - 22
core/options.py

@@ -30,7 +30,7 @@ class XSSerOptions(optparse.OptionParser):
         optparse.OptionParser.__init__(self, 
                            description='Cross Site "Scripter" is an automatic -framework- to detect, exploit and\nreport XSS vulnerabilities in web-based applications.',
                            prog='XSSer.py',
-			   version='\nXSSer v1.8[1]: "The Hive!" - (https://xsser.03c8.net) - 2010/2019 -> by psy\n',
+			   version='\nXSSer v1.8[2]: "The Hiv3!" - (https://xsser.03c8.net) - 2010/2019 -> by psy\n',
                            usage= '\n\nxsser [OPTIONS] [--all <url> |-u <url> |-i <file> |-d <dork> (options)|-l ] [-g <get> |-p <post> |-c <crawl> (options)]\n[Request(s)] [Checker(s)] [Vector(s)] [Anti-antiXSS/IDS] [Bypasser(s)] [Technique(s)] [Final Injection(s)] [Reporting] {Miscellaneous}')
         self.set_defaults(verbose=False, threads=5, retries=1, delay=0, timeout=30,
                           silent=False)
@@ -134,6 +134,7 @@ class XSSerOptions(optparse.OptionParser):
         group13.add_option("--Barracuda", action="store_true", dest="barracuda", help="Barracuda WAF [ALL]")
         group13.add_option("--Modsec", action="store_true", dest="modsec", help="Mod-Security [ALL]")
         group13.add_option("--Quickdefense", action="store_true", dest="quickdefense", help="QuickDefense [Chrome]")
+        group13.add_option("--Sucuri", action="store_true", dest="sucuri", help="SucuriWAF [ALL]")
         group13.add_option("--Firefox", action="store_true", dest="firefox", help="Firefox 12 [& below]")
         group13.add_option("--Chrome", action="store_true", dest="chrome", help="Chrome 19 & Firefox 12 [& below]")
         group13.add_option("--Opera", action="store_true", dest="opera", help="Opera 10.5 [& below]")
@@ -193,26 +194,26 @@ class XSSerOptions(optparse.OptionParser):
     def get_options(self, user_args=None):
         (options, args) = self.parse_args(user_args)
         if (not options.url and not options.readfile and not options.dork and not options.dork_file and not options.imx and not options.flash and not options.update and not options.xsser_gtk and not options.wizard and not options.xst and not options.target and not options.checktor):
-            print "\n", '='*75
-            print self.version
-            print "-----------", "\n"
-            print self.description, "\n"
-            print '='*75
-            print ""
-            print "                                \\ \\   LulZzzz!    /\                          "
-            print "Project site:","                && \\ \\            /\())\          %  %        "
-            print "https://xsser.03c8.net       &&&& \\_\\          (())\\))  %   %        %       " 
-            print "                              \/ ( \033[1;31m@\033[1;m.\033[1;31m@\033[1;m)      * //\\//\\%                 %  %"
-            print "                              || == < ==   * * \\//))//)  BBzzzzz!              "
-            print "Forum:                        ||]~~/ \~~[ *    (())//))                         "
-            print "irc.freenode.net -> #xsser    ||   (')          \/())/                          "
-            print "                              ||  /  /            \/                            "
-            print ""
-            print '='*75
-            print "Total vectors:", self.total_vectors + " = XSS: " + str(self.vectors_fuzz) + " + DCP: " + str(self.vectors_dcp) + " + DOM: " + str(self.vectors_dom) + " + HTTPsr: " + str(self.vectors_httpsr)
-            print '='*75
-            print "\n-> For HELP use: -h or --help"
-            print "\n-> For GTK interface use: --gtk\n"
-            print '='*55, "\n"
+            print("\n", '='*75)
+            print(self.version)
+            print("-----------", "\n")
+            print(self.description, "\n")
+            print('='*75)
+            print("")
+            print("                                \\ \\   LulZzzz!    /\                          ")
+            print("Project site:","                && \\ \\            /\())\          %  %        ")
+            print("https://xsser.03c8.net       &&&& \\_\\          (())\\))  %   %        %       ") 
+            print("                              \/ ( \033[1;31m@\033[1;m.\033[1;31m@\033[1;m)      * //\\//\\%                 %  %")
+            print("                              || == < ==   * * \\//))//)  BBzzzzz!              ")
+            print("Forum:                        ||]~~/ \~~[ *    (())//))                         ")
+            print("irc.freenode.net -> #xsser    ||   (')          \/())/                          ")
+            print("                              ||  /  /            \/                            ")
+            print("")
+            print('='*75)
+            print("Total vectors:", self.total_vectors + " = XSS: " + str(self.vectors_fuzz) + " + DCP: " + str(self.vectors_dcp) + " + DOM: " + str(self.vectors_dom) + " + HTTPsr: " + str(self.vectors_httpsr))
+            print('='*75)
+            print("\n-> For HELP use: -h or --help")
+            print("\n-> For GTK interface use: --gtk\n")
+            print('='*55, "\n")
             return False
         return options

+ 1 - 1
core/randomip.py

@@ -38,4 +38,4 @@ class RandomIP(object):
 
 if __name__ == "__main__":
     randomip = RandomIP()
-    print randomip._generateip('')
+    print(randomip._generateip(''))

+ 10 - 10
core/threadpool.py

@@ -72,10 +72,10 @@ __license__ = "MIT license"
 import sys
 import threading
 try:
-    import Queue
+    import queue
 except ImportError:
     import queue as Queue
-from Queue import Empty
+from queue import Empty
 import traceback
 
 
@@ -282,8 +282,8 @@ class ThreadPool:
             ``ThreadPool.putRequest()`` and catch ``Queue.Full`` exceptions.
 
         """
-        self._requests_queue = Queue.Queue(q_size)
-        self._results_queue = Queue.Queue(resq_size)
+        self._requests_queue = queue.Queue(q_size)
+        self._results_queue = queue.Queue(resq_size)
         self.workers = []
         self.dismissedWorkers = []
         self.workRequests = {}
@@ -388,7 +388,7 @@ if __name__ == '__main__':
 
     # this will be called each time a result is available
     def print_result(request, result):
-        print("**** Result from request #%s: %r" % (request.requestID, result))
+        print(("**** Result from request #%s: %r" % (request.requestID, result)))
 
     # this will be called when an exception occurs within a thread
     # this example exception handler does little more than the default handler
@@ -398,8 +398,8 @@ if __name__ == '__main__':
             print(request)
             print(exc_info)
             raise SystemExit
-        print("**** Exception occured in request #%s: %s" % \
-          (request.requestID, exc_info))
+        print(("**** Exception occured in request #%s: %s" % \
+          (request.requestID, exc_info)))
 
     # assemble the arguments for each job to a list...
     data = [random.randint(1,10) for i in range(20)]
@@ -425,7 +425,7 @@ if __name__ == '__main__':
     # then we put the work requests in the queue...
     for req in requests:
         main.putRequest(req)
-        print("Work request #%s added." % req.requestID)
+        print(("Work request #%s added." % req.requestID))
     # or shorter:
     # [main.putRequest(req) for req in requests]
 
@@ -440,8 +440,8 @@ if __name__ == '__main__':
         try:
             time.sleep(0.5)
             main.poll()
-            print("Main thread working...",)
-            print("(active worker threads: %i)" % (threading.activeCount()-1, ))
+            print(("Main thread working...",))
+            print(("(active worker threads: %i)" % (threading.activeCount()-1, )))
             if i == 10:
                 print("**** Adding 3 more worker threads...")
                 main.createWorkers(3)

+ 1 - 1
core/tokenhub.py

@@ -86,7 +86,7 @@ class HubThread(Thread):
                 conn, addr = s.accept()
             except socket.timeout:
                 pass
-            except socket.error, e:
+            except socket.error as e:
                 if self.ready == False:
                     return
                 else:

+ 16 - 16
core/twsupport.py

@@ -29,14 +29,14 @@ import traceback
 try:
     from orbited.start import main as orbited_main
 except:
-    print "no orbited so not enabling rt swarm port"
+    print("no orbited so not enabling rt swarm port")
     orbited_main = None
     traceback.print_exc()
 
-print "\nXSSer v1.7b: The Mosquito 'Zika Swarm'\n"
-print "Daemon(s): ready!", "//" , "Interfaz: ready!\n"
-print "Connect to http://127.0.0.1:19084/static/ via Web or Telnet to manage your swarm\n"
-print "Listening..."
+print("\nXSSer v1.7b: The Mosquito 'Zika Swarm'\n")
+print("Daemon(s): ready!", "//" , "Interfaz: ready!\n")
+print("Connect to http://127.0.0.1:19084/static/ via Web or Telnet to manage your swarm\n")
+print("Listening...")
 
 from twisted.web import resource, error, script, server
 from orbited import __version__ as version
@@ -59,9 +59,9 @@ class XSSerCheckerResource(resource.Resource):
         self.name = str(name)
         self.parent = parent
     def render_GET(self, request):
-        print "SUCCESS!!", request
+        print("SUCCESS!!", request)
         self.parent.xsser.final_attack_callback(request)
-        response = "thx for use XSSer (http://xsser.03c8.net) !!"
+        response = "thx for use XSSer (https://xsser.03c8.net) !!"
         return response
     def render_POST(self, request):
         return self.render_GET(request)
@@ -89,9 +89,9 @@ class XSSerMainResource(script.ResourceScriptDirectory):
     def do_success(self, request):
         response = "not implemented!"
         if False:
-            print "SUCCESS!!", data.split('HTTP')[0].split('/')[-1]
+            print("SUCCESS!!", data.split('HTTP')[0].split('/')[-1])
             self.factory.xsser.final_attack_callback(data.split('HTTP')[0].split('/')[-1].strip())
-            self.sendHTTP("thx for use XSSer (http://xsser.03c8.net) !!\n")
+            self.sendHTTP("thx for use XSSer (https://xsser.03c8.net) !!\n")
         return response
     def do_evangelion(self, request):
         response = "Start Swarm Attack"
@@ -105,7 +105,7 @@ class XSSerProtocol(Protocol):
     factory = None
     def connectionMade(self):
         self.factory._clients.append(self)
-        print "new client connected..."
+        print("new client connected...")
     def connectionLost(self, reason):
         self.factory._clients.remove(self)
     def sendHTTP(self, data):
@@ -113,16 +113,16 @@ class XSSerProtocol(Protocol):
         self.transport.write("Content-Type: text/html; charset=UTF-8\n\n")
         self.transport.write(data)
     def dataReceived(self, data):
-        print "Mosquito network ready ;)",data
+        print("Mosquito network ready ;)",data)
         if (data.startswith("GET") and "evangelion" in data) or "evangelion" in data:
-            print "EVAngelion swarm mode!\n"
+            print("EVAngelion swarm mode!\n")
             self.sendHTTP("Start Swarm Attack\n")
             app = xsser()
             app.set_reporter(self.factory)
             self.factory.xsser = app
             data = data.split('\n')[0]
             options = data.replace('GET ', '').split()[1:]
-            print 'OPTIONS',options
+            print('OPTIONS',options)
             if len(options) > 1:
                 reactor.callInThread(self.factory.xsser.run, options)
             else:
@@ -131,9 +131,9 @@ class XSSerProtocol(Protocol):
             self.sendHTTP("Start Swarm Attack\n")
             reactor.callInThread(self.factory.xsser.run)
         elif data.startswith("GET /success"):
-            print "SUCCESS!!", data.split('HTTP')[0].split('/')[-1]
+            print("SUCCESS!!", data.split('HTTP')[0].split('/')[-1])
             self.factory.xsser.final_attack_callback(data.split('HTTP')[0].split('/')[-1].strip())
-            self.sendHTTP("thx for use XSSer (http://xsser.03c8.net) !!\n")
+            self.sendHTTP("thx for use XSSer (https://xsser.03c8.net) !!\n")
             self.transport.loseConnection()
         elif data.startswith("GET"):
             self.sendHTTP("XSSer Web Interface <a href='evangelion'>Try it!</a>\n")
@@ -153,7 +153,7 @@ class ServerFactory(Factory):
 
 if __name__ == '__main__':
     if orbited_main:
-        print "orbited!"
+        print("orbited!")
         root = orbited_main()
         import orbited.transports.base
         from orbited import cometsession

+ 9 - 9
core/update.py

@@ -32,16 +32,16 @@ class Updater(object):
         GIT_REPOSITORY2 = "https://github.com/epsylon/xsser"
         rootDir = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', ''))
         if not os.path.exists(os.path.join(rootDir, ".git")):
-            print "[Error] Not any .git repository found!\n"
-            print "="*30
-            print "\nTo have working this feature, you should clone XSSer with:\n"
-            print "$ git clone %s" % GIT_REPOSITORY
-            print "\nAlso you can try this other mirror:\n"
-            print "$ git clone %s" % GIT_REPOSITORY2 + "\n"
+            print("[Error] Not any .git repository found!\n")
+            print("="*30)
+            print("\nTo have working this feature, you should clone XSSer with:\n")
+            print("$ git clone %s" % GIT_REPOSITORY)
+            print("\nAlso you can try this other mirror:\n")
+            print("$ git clone %s" % GIT_REPOSITORY2 + "\n")
         else:
             checkout = execute("git checkout . && git pull", shell=True, stdout=PIPE, stderr=PIPE).communicate()[0]
-            print checkout
+            print(checkout)
             if not "Already up-to-date" in checkout:
-                print "Congratulations!! XSSer has been updated... ;-)\n"
+                print("Congratulations!! XSSer has been updated... ;-)\n")
             else:
-                print "Your XSSer doesn't need to be updated... ;-)\n"
+                print("Your XSSer doesn't need to be updated... ;-)\n")

+ 2 - 1
doc/AUTHOR

@@ -10,7 +10,8 @@
 
  code:
 
-  https://code.03c8.net/epsylon
+ - https://code.03c8.net/epsylon
+ - https://github.com/epsylon
 
 =======================
 

+ 13 - 1
doc/CHANGELOG

@@ -1,8 +1,20 @@
 ================================================================
-Changelog: XSSer v1.8.1 (https://xsser.03c8.net)
+Changelog: XSSer v1.8.2 (https://xsser.03c8.net)
 ==============================
 
 =================
+November 16, 2019:
+=================
+
+- Ported to: Python3.x
+- Bugfixing
+- Added: Anti-antiXSS Firewall rules (Bypassers provided: SucuriWAF)
+- Modified/Updated GTK+
+- Added Requirements
+- Updated Documentation
+- Updated Website
+
+=================
 September 20, 2019:
 =================
 

+ 14 - 9
doc/INSTALL

@@ -8,7 +8,7 @@ Cross Site "Scripter" is an automatic -framework- to detect, exploit and report
 Current Version:
 ==============================
 
-XSSer v1.8[1]: "The Hive!" (2010/2019) // [https://xsser.03c8.net]
+XSSer v1.8[2]: "The Hiv3!" (2010/2019) // [https://xsser.03c8.net]
 
 ================================================================
 + INSTALL: AUTO
@@ -20,27 +20,32 @@ XSSer v1.8[1]: "The Hive!" (2010/2019) // [https://xsser.03c8.net]
 + INSTALL: MANUAL
 ===================
 
-XSSer runs on many platforms. It requires Python and the following libraries:
+XSSer runs on many platforms. It requires Python (3.x) and the following libraries:
 
-    - python-pycurl - Python bindings to libcurl
-    - python-xmlbuilder - create xml/(x)html files - Python 2.x
-    - python-beautifulsoup - error-tolerant HTML parser for Python
-    - python-geoip - Python bindings for the GeoIP IP-to-country resolver library
+    - python3-pycurl - Python bindings to libcurl (Python 3)
+    - python3-bs4 - error-tolerant HTML parser for Python 3
+    - python3-geoip - Python3 bindings for the GeoIP IP-to-country resolver library
+    - python3-geoip2 - Python geoip2 API for web services and databases - Python 3.x
+    - python3-gi - Python 3 bindings for gobject-introspection libraries
+    - python3-cairocffi - cffi-based cairo bindings for Python (Python3)
 
 On Debian-based systems (ex: Ubuntu), run: 
 
-    sudo apt-get install python-pycurl python-xmlbuilder python-beautifulsoup python-geoip
+    sudo apt-get install python3-pycurl python3-bs4 python3-geoip python3-geoip2 python3-cairocffi
 
 On other systems such as: Kali, Ubuntu, ArchLinux, ParrotSec, Fedora, etc... also run:
 
-    pip install geoip 
+    sudo pip3 install pycurl bs4 geoip2 gobject cairocffi
 
 ####  Source libs:
 
        * Python: https://www.python.org/downloads/
        * PyCurl: http://pycurl.sourceforge.net/
-       * PyBeautifulSoup: https://pypi.python.org/pypi/BeautifulSoup
+       * PyBeautifulSoup4: https://pypi.org/project/beautifulsoup4/
        * PyGeoIP: https://pypi.python.org/pypi/GeoIP
+       * PyGeoIP2: https://pypi.org/project/geoip2/
+       * PyGObject: https://pypi.org/project/gobject/
+       * PyCairocffi: https://pypi.org/project/cairocffi/
 
 ================================================================
 

+ 2 - 1
doc/README

@@ -8,7 +8,7 @@ Cross Site "Scripter" is an automatic -framework- to detect, exploit and report
 Current Version:
 ==============================
 
-XSSer v1.8[1]: "The Hive!" (2010/2019) // [https://xsser.03c8.net]
+XSSer v1.8[2]: "The Hiv3!" (2010/2019) // [https://xsser.03c8.net]
 
 ================================================================
 Options and features:
@@ -128,6 +128,7 @@ Options:
     --Barracuda         Barracuda WAF [ALL]
     --Modsec            Mod-Security [ALL]
     --Quickdefense      QuickDefense [Chrome]
+    --Sucuri            SucuriWAF [ALL]
     --Firefox           Firefox 12 [& below]
     --Chrome            Chrome 19 & Firefox 12 [& below]
     --Opera             Opera 10.5 [& below]

+ 5 - 5
doc/requirements.txt

@@ -1,5 +1,5 @@
-python-xmlbuilder==1.0-1
-beautifulsoup==3.2.1-1
-pycurl==7.19.5.1
-GeoIP==1.3.2
-pygeoip==0.3.2
+beautifulsoup4==4.8.1
+pycurl==7.43.0.3
+geoip2==2.9.0
+gobject==0.1.0
+