├── .gitignore ├── LICENSE ├── README.md ├── __init__.py ├── _gtkentry.py ├── handler_api.py ├── handlers.py ├── layout.py ├── model.py ├── opts_wx.py ├── profiler.sh ├── screenshots ├── sqlmap-wx1.png ├── sqlmap-wx2.png ├── sqlmap-wx3.png ├── sqlmap-wx4.png ├── sqlmap-wx5.png ├── sqlmap-wx6.png ├── sqlmap-wx7.png ├── sqlmap-wx8.png └── sqlmap-wx9.png ├── session.py ├── sqlmap_wx.py ├── static └── title.ico ├── tamper └── tamper_list ├── tooltips.py └── widgets.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | local_settings.py 60 | db.sqlite3 61 | db.sqlite3-journal 62 | 63 | # Flask stuff: 64 | instance/ 65 | .webassets-cache 66 | 67 | # Scrapy stuff: 68 | .scrapy 69 | 70 | # Sphinx documentation 71 | docs/_build/ 72 | 73 | # PyBuilder 74 | target/ 75 | 76 | # Jupyter Notebook 77 | .ipynb_checkpoints 78 | 79 | # IPython 80 | profile_default/ 81 | ipython_config.py 82 | 83 | # pyenv 84 | .python-version 85 | 86 | # pipenv 87 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 88 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 89 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 90 | # install all needed dependencies. 91 | #Pipfile.lock 92 | 93 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 94 | __pypackages__/ 95 | 96 | # Celery stuff 97 | celerybeat-schedule 98 | celerybeat.pid 99 | 100 | # SageMath parsed files 101 | *.sage.py 102 | 103 | # Environments 104 | .env 105 | .venv 106 | env/ 107 | venv/ 108 | ENV/ 109 | env.bak/ 110 | venv.bak/ 111 | 112 | # Spyder project settings 113 | .spyderproject 114 | .spyproject 115 | 116 | # Rope project settings 117 | .ropeproject 118 | 119 | # mkdocs documentation 120 | /site 121 | 122 | # mypy 123 | .mypy_cache/ 124 | .dmypy.json 125 | dmypy.json 126 | 127 | # Pyre type checker 128 | .pyre/ 129 | 130 | *.lprof 131 | *.tmp 132 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## sqlmap-wx 2 | sqlmap GUI, using wxPython4.0 3 | 4 | 此GUI(wxPython太难控制了~)虽然跨平台, 但主要在win使用. 5 | linux下建议使用[sqlmap-gtk](https://github.com/needle-wang/sqlmap-gtk). 6 | sqlmap已经移植到了python3. 来自sqlmap的FAQ: 7 | "Both Python 2 and 3 are supported from May of 2019" 8 | 9 | #### SCREENSHOT 10 | ![screenshot](https://github.com/needle-wang/sqlmap-wx/blob/master/screenshots/sqlmap-wx1.png) 11 | 12 | #### HOW-TO 13 | 1. **Prerequisites** 14 | - python3.6+ 15 | - [sqlmap](https://github.com/sqlmapproject/sqlmap): (choose one) 16 | - `pip3 install sqlmap`(suggestion) 17 | - `git clone https://github.com/sqlmapproject/sqlmap.git` 18 | - wxPython4.0+: 19 | - windows: `pip3 install wxPython` 20 | - linux: 到[wxPython官方](https://wxpython.org/pages/downloads/index.html)下载, 有的 21 | - requests: `pip3 install requests` 22 | 2. **Download** 23 | - `git clone https://github.com/needle-wang/sqlmap-wx.git` 24 | 3. **Run** 25 | - `./sqlmap_wx.py` 26 | 27 | #### FUNCTION 28 | - all sqlmap(1.4.12.45#dev) options(except --all, 不定时更新sqlmap选项) 29 | - sqlmapapi client 30 | - built-in mini wiki(tooltip and placeholder) 31 | - session: autosave current options before quit, autoload last used options 32 | 33 | #### ABOUT 34 | - V0.3.3.1 35 | 2021-01-31 05:12:52 36 | - use wxPython4 to recode sqlmap-gtk(driven by PyGObject) 37 | - thanks to the idea from sqm 38 | author: [KINGX](https://github.com/kxcode)(sqm UI using python2 + tkinter) 39 | 40 | #### REFERENCE 41 | - wxPython教程: https://wiki.wxpython.org/, http://zetcode.com/wxpython/ 42 | - wxPython API: https://wxpython.org/Phoenix/docs/html/index.html 43 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/needle-wang/sqlmap-wx/747e8170538f48dd1a75c8ed1b05a6a32d81d368/__init__.py -------------------------------------------------------------------------------- /_gtkentry.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # 2019-05-05 17:34:08 4 | 5 | import gi 6 | gi.require_version('Gtk', '3.0') 7 | 8 | from gi.repository import Gtk as g 9 | 10 | win = g.Window() 11 | win.connect('destroy', lambda x: g.main_quit()) 12 | 13 | a = g.Entry() 14 | win.add(a) 15 | 16 | print(a.get_allocation().width, a.get_allocation().height) 17 | win.show_all() 18 | print(a.get_allocation().width, a.get_allocation().height) 19 | 20 | g.main() 21 | -------------------------------------------------------------------------------- /handler_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # 2018-08-29 15:34:10 4 | 5 | import ast 6 | import requests 7 | 8 | from widgets import wx, btn, st, EVT_BUTTON 9 | 10 | 11 | class Api(object): 12 | def __init__(self, topwindow, m): 13 | ''' 14 | topwindow: sqlmap_wx.Window 15 | m: model.Model 16 | ''' 17 | self.w = topwindow 18 | self.m = m 19 | 20 | def task_new(self, event): 21 | ''' 22 | rest api from https://github.com/PyxYuYu/MyBlog/issues/69 23 | @get("/task/new") 创建新任务 24 | ''' 25 | _host = self.get_tc_value(self.m._page4_api_server_entry) 26 | _username = self.get_tc_value(self.m._page4_username_entry) 27 | _password = self.get_tc_value(self.m._page4_password_entry) 28 | if _host: 29 | try: 30 | _resp = requests.get(f'http://{_host}/task/new', 31 | auth = (_username, _password)) 32 | if not _resp: 33 | _resp.raise_for_status() 34 | 35 | _resp = _resp.json() 36 | if _resp['success']: 37 | self.task_view_append('{}: success.'.format(_resp['taskid'])) 38 | except Exception as e: 39 | self.task_view_append(e) 40 | 41 | def admin_list(self, event): 42 | ''' 43 | @get("/admin//list") 查看所有任务,并显示运行状态 44 | ''' 45 | _host = self.get_tc_value(self.m._page4_api_server_entry) 46 | _token = self.get_tc_value(self.m._page4_admin_token_entry) 47 | _username = self.get_tc_value(self.m._page4_username_entry) 48 | _password = self.get_tc_value(self.m._page4_password_entry) 49 | if _host and _token: 50 | try: 51 | _resp = requests.get(f'http://{_host}/admin/{_token}/list', 52 | auth = (_username, _password)) 53 | if not _resp: 54 | _resp.raise_for_status() 55 | 56 | _resp = _resp.json() 57 | # print(_resp) 58 | if _resp['success']: 59 | # self.task_view_append('总任务数: %s' % _resp['tasks_num']) 60 | p = self.w._api_admin_list_rows 61 | vbox = p.GetSizer() 62 | # 清空之前的任务列表 63 | vbox.Clear(delete_windows = True) 64 | # 填充任务列表 65 | _id = 0 66 | for _taskid, _status in _resp['tasks'].items(): 67 | _a_task_row = wx.BoxSizer() 68 | 69 | _task_del_btn = btn(p, label = '删除', style = wx.BU_EXACTFIT) 70 | _task_del_btn.Bind(EVT_BUTTON, 71 | lambda evt, row = _a_task_row, tid = _taskid: 72 | self.task_delete(row, tid)) 73 | 74 | _scan_kill_btn = btn(p, label = '杀死', style = wx.BU_EXACTFIT) 75 | _scan_kill_btn.Bind(EVT_BUTTON, 76 | lambda evt, tid = _taskid: 77 | self.scan_kill(tid)) 78 | 79 | _scan_stop_btn = btn(p, label = '停止', style = wx.BU_EXACTFIT) 80 | _scan_stop_btn.Bind(EVT_BUTTON, 81 | lambda evt, tid = _taskid: 82 | self.scan_stop(tid)) 83 | 84 | _scan_start_btn = btn(p, label = '启动', style = wx.BU_EXACTFIT) 85 | _scan_start_btn.Bind(EVT_BUTTON, 86 | lambda evt, tid = _taskid: 87 | self.scan_start(tid)) 88 | 89 | _scan_data_btn = btn(p, label = 'data', style = wx.BU_EXACTFIT) 90 | _scan_data_btn.Bind(EVT_BUTTON, 91 | lambda evt, tid = _taskid: 92 | self.scan_data(tid)) 93 | 94 | _scan_log_btn = btn(p, label = 'log', style = wx.BU_EXACTFIT) 95 | _scan_log_btn.Bind(EVT_BUTTON, 96 | lambda evt, tid = _taskid: 97 | self.scan_log(tid)) 98 | 99 | _option_list_btn = btn(p, label = '所有选项', style = wx.BU_EXACTFIT) 100 | _option_list_btn.Bind(EVT_BUTTON, 101 | lambda evt, tid = _taskid: 102 | self.option_list(tid)) 103 | 104 | _option_get_btn = btn(p, label = '选项:', style = wx.BU_EXACTFIT) 105 | _option_get_btn.Bind(EVT_BUTTON, 106 | lambda evt, tid = _taskid: 107 | self.option_get(tid)) 108 | 109 | _option_set_btn = btn(p, label = '设置:', style = wx.BU_EXACTFIT) 110 | _option_set_btn.Bind(EVT_BUTTON, 111 | lambda evt, tid = _taskid: 112 | self.option_set(tid)) 113 | 114 | _id += 1 115 | _a_task_row.Add(st(p, label = f'{_id}. {_taskid}'), flag = wx.ALIGN_CENTER) 116 | _a_task_row.Add(st(p, label = f'({_status})'), flag = wx.ALIGN_CENTER) 117 | _a_task_row.Add(_task_del_btn, flag = wx.EXPAND) 118 | _a_task_row.Add(_scan_kill_btn, flag = wx.EXPAND) 119 | _a_task_row.Add(_scan_stop_btn, flag = wx.EXPAND) 120 | _a_task_row.Add(_scan_start_btn, flag = wx.EXPAND) 121 | _a_task_row.Add(st(p, label = '查看:('), flag = wx.ALIGN_CENTER) 122 | _a_task_row.Add(_scan_data_btn, flag = wx.EXPAND) 123 | _a_task_row.Add(_scan_log_btn, flag = wx.EXPAND) 124 | _a_task_row.Add(_option_list_btn, flag = wx.EXPAND) 125 | _a_task_row.Add(_option_get_btn, flag = wx.EXPAND) 126 | _a_task_row.Add(st(p, label = ')'), flag = wx.ALIGN_CENTER) 127 | _a_task_row.Add(_option_set_btn, flag = wx.EXPAND) 128 | 129 | vbox.Add(_a_task_row, flag = wx.EXPAND) 130 | 131 | vbox.Layout() 132 | p.SetupScrolling() 133 | except Exception as e: 134 | self.task_view_append(e) 135 | else: 136 | self.task_view_append('need API server and admin token.') 137 | 138 | def option_list(self, taskid): 139 | ''' 140 | @get("/option//list") 获取指定任务的options 141 | ''' 142 | _host = self.get_tc_value(self.m._page4_api_server_entry) 143 | _username = self.get_tc_value(self.m._page4_username_entry) 144 | _password = self.get_tc_value(self.m._page4_password_entry) 145 | if _host: 146 | try: 147 | _resp = requests.get('http://%s/option/%s/list' % (_host, taskid), 148 | auth = (_username, _password)) 149 | if not _resp: 150 | _resp.raise_for_status() 151 | 152 | _resp = _resp.json() 153 | if _resp['success']: 154 | for _key, _value in _resp['options'].items(): 155 | if _value: 156 | self.task_view_append(f'{_key}: {_value}') 157 | except Exception as e: 158 | self.task_view_append(e) 159 | 160 | def option_get(self, taskid): 161 | ''' 162 | @post("/option//get") 获取指定任务的option(s) 163 | ''' 164 | _host = self.get_tc_value(self.m._page4_api_server_entry) 165 | _opts_text = self.get_tc_value(self.m._page4_option_get_entry) 166 | _username = self.get_tc_value(self.m._page4_username_entry) 167 | _password = self.get_tc_value(self.m._page4_password_entry) 168 | _options = {} 169 | for _tmp in _opts_text.split(): 170 | _options[_tmp] = None 171 | if _host and _options: 172 | _mesg = f'{taskid}:\n' 173 | try: 174 | _headers = {'Content-Type': 'application/json'} 175 | _resp = requests.post('http://%s/option/%s/get' % (_host, taskid), 176 | json = _options, 177 | headers = _headers, 178 | auth = (_username, _password)) 179 | if not _resp: 180 | _resp.raise_for_status() 181 | 182 | _resp = _resp.json() 183 | if _resp['success']: 184 | if _resp['options'].items(): 185 | for _key, _value in _resp['options'].items(): 186 | _mesg += '%s: %s, ' % (_key, _value) 187 | else: 188 | _mesg += 'None' 189 | else: 190 | _mesg += _resp['message'] 191 | except Exception as e: 192 | _mesg += str(e) 193 | self.task_view_append(_mesg.strip()) 194 | 195 | def option_set(self, taskid): 196 | ''' 197 | @post("/option//set") 设置指定任务的option(s) 198 | Warning: any option can be set, even a invalid option which 199 | is unable to remove, except deleting the task. 200 | ''' 201 | _host = self.get_tc_value(self.m._page4_api_server_entry) 202 | _buffer_text = self.get_tc_value(self.m._page4_option_set_view) 203 | _username = self.get_tc_value(self.m._page4_username_entry) 204 | _password = self.get_tc_value(self.m._page4_password_entry) 205 | try: 206 | _json = ast.literal_eval(_buffer_text) 207 | except Exception as e: 208 | _json = str(e) 209 | 210 | _mesg = f'{taskid}: ' 211 | if _json and isinstance(_json, dict): 212 | if _host: 213 | try: 214 | _headers = {'Content-Type': 'application/json'} 215 | # data, json参数都要求是字典类型, 而非字符串 216 | # 另外, 字典的格式比json的宽松(json不能使用单引号, 不能多个逗号) 217 | _resp = requests.post('http://%s/option/%s/set' % (_host, taskid), 218 | json = _json, 219 | headers = _headers, 220 | auth = (_username, _password)) 221 | if not _resp: 222 | _resp.raise_for_status() 223 | 224 | _resp = _resp.json() 225 | if _resp['success']: 226 | _mesg += 'set success.' 227 | except Exception as e: 228 | _mesg += str(e) 229 | else: 230 | _mesg += 'need a valid python dict.' 231 | 232 | self.task_view_append(_mesg) 233 | 234 | def admin_flush(self, event): 235 | ''' 236 | @get("/admin//flush") 删除所有任务 237 | ''' 238 | _host = self.get_tc_value(self.m._page4_api_server_entry) 239 | _token = self.get_tc_value(self.m._page4_admin_token_entry) 240 | _username = self.get_tc_value(self.m._page4_username_entry) 241 | _password = self.get_tc_value(self.m._page4_password_entry) 242 | if _host and _token: 243 | try: 244 | _resp = requests.get('http://%s/admin/%s/flush' % (_host, _token), 245 | auth = (_username, _password)) 246 | if not _resp: 247 | _resp.raise_for_status() 248 | 249 | _resp = _resp.json() 250 | if _resp['success']: 251 | self.w._api_admin_list_rows.GetSizer().Clear(delete_windows = True) 252 | self.task_view_append('flush all tasks: Done.') 253 | except Exception as e: 254 | self.task_view_append(e) 255 | 256 | def task_delete(self, row, taskid): 257 | ''' 258 | @get("/task//delete") 删除指定任务 259 | ''' 260 | _host = self.get_tc_value(self.m._page4_api_server_entry) 261 | _username = self.get_tc_value(self.m._page4_username_entry) 262 | _password = self.get_tc_value(self.m._page4_password_entry) 263 | if _host: 264 | try: 265 | _resp = requests.get('http://%s/task/%s/delete' % (_host, taskid), 266 | auth = (_username, _password)) 267 | if not _resp: 268 | _resp.raise_for_status() 269 | 270 | _resp = _resp.json() 271 | if _resp['success']: 272 | # TODO, 要两步哈! 要查下是否真的成功了! 273 | row.Clear(delete_windows = True) 274 | self.w._api_admin_list_rows.GetSizer().Remove(row) 275 | self.task_view_append('%s: removed' % taskid) 276 | except Exception as e: 277 | self.task_view_append(e) 278 | 279 | def scan_start(self, taskid): 280 | ''' 281 | @post("/scan//start") 指定任务 开始扫描 282 | 要求发送json, 会执行/option//set 283 | ''' 284 | _host = self.get_tc_value(self.m._page4_api_server_entry) 285 | _username = self.get_tc_value(self.m._page4_username_entry) 286 | _password = self.get_tc_value(self.m._page4_password_entry) 287 | if _host: 288 | _mesg = '%s: ' % taskid 289 | try: 290 | _headers = {'Content-Type': 'application/json'} 291 | _resp = requests.post('http://%s/scan/%s/start' % (_host, taskid), 292 | json = {}, 293 | headers = _headers, 294 | auth = (_username, _password)) 295 | if not _resp: 296 | _resp.raise_for_status() 297 | 298 | _resp = _resp.json() 299 | if _resp['success']: 300 | _mesg = '%sengineid: %s' % (_mesg, _resp['engineid']) 301 | else: 302 | _mesg += _resp['message'] 303 | except Exception as e: 304 | _mesg += str(e) 305 | 306 | self.task_view_append(_mesg) 307 | 308 | def scan_stop(self, taskid): 309 | ''' 310 | @get("/scan//stop") 指定任务 停止扫描 311 | ''' 312 | _host = self.get_tc_value(self.m._page4_api_server_entry) 313 | _username = self.get_tc_value(self.m._page4_username_entry) 314 | _password = self.get_tc_value(self.m._page4_password_entry) 315 | if _host: 316 | _mesg = '%s: ' % taskid 317 | try: 318 | _resp = requests.get('http://%s/scan/%s/stop' % (_host, taskid), 319 | auth = (_username, _password)) 320 | if not _resp: 321 | _resp.raise_for_status() 322 | 323 | _resp = _resp.json() 324 | if _resp['success']: 325 | _mesg += 'ok, stoped.' 326 | else: 327 | _mesg += _resp['message'] 328 | except Exception as e: 329 | _mesg += str(e) 330 | self.task_view_append(_mesg) 331 | 332 | def scan_kill(self, taskid): 333 | ''' 334 | @get("/scan//kill") kill -9 指定任务 335 | ''' 336 | _host = self.get_tc_value(self.m._page4_api_server_entry) 337 | _username = self.get_tc_value(self.m._page4_username_entry) 338 | _password = self.get_tc_value(self.m._page4_password_entry) 339 | if _host: 340 | _mesg = f'{taskid}: ' 341 | try: 342 | _resp = requests.get('http://%s/scan/%s/kill' % (_host, taskid), 343 | auth = (_username, _password)) 344 | if not _resp: 345 | _resp.raise_for_status() 346 | 347 | _resp = _resp.json() 348 | if _resp['success']: 349 | _mesg += 'ok, killed.' 350 | else: 351 | _mesg += _resp['message'] 352 | except Exception as e: 353 | _mesg += str(e) 354 | 355 | self.task_view_append(_mesg) 356 | 357 | def scan_data(self, taskid): 358 | ''' 359 | @get("/scan//data") 查看指定任务的扫描数据, 360 | data若有内容说明存在注入 361 | ''' 362 | _host = self.get_tc_value(self.m._page4_api_server_entry) 363 | _username = self.get_tc_value(self.m._page4_username_entry) 364 | _password = self.get_tc_value(self.m._page4_password_entry) 365 | if _host: 366 | _mesg = '%s:\n' % taskid 367 | try: 368 | _resp = requests.get('http://%s/scan/%s/data' % (_host, taskid), 369 | auth = (_username, _password)) 370 | if not _resp: 371 | _resp.raise_for_status() 372 | 373 | _resp = _resp.json() 374 | # print(_resp) # _resp['data'], _resp['error'] are list 375 | if _resp['success']: 376 | del[_resp['success']] 377 | _mesg = f'{_mesg}{_resp}' 378 | except Exception as e: 379 | _mesg += str(e) 380 | self.task_view_append(_mesg) 381 | 382 | def scan_log(self, taskid): 383 | ''' 384 | @get("/scan//log") 查看指定任务的扫描日志 385 | ''' 386 | _host = self.get_tc_value(self.m._page4_api_server_entry) 387 | _username = self.get_tc_value(self.m._page4_username_entry) 388 | _password = self.get_tc_value(self.m._page4_password_entry) 389 | if _host: 390 | _mesg = '%s:\n' % taskid 391 | try: 392 | _resp = requests.get('http://%s/scan/%s/log' % (_host, taskid), 393 | auth = (_username, _password)) 394 | if not _resp: 395 | _resp.raise_for_status() 396 | 397 | _resp = _resp.json() 398 | if _resp['success']: 399 | _logs = '' 400 | for _tmp in _resp['log']: 401 | _log = '%s %s: %s\n' % (_tmp['time'], _tmp['level'], _tmp['message']) 402 | _logs = ''.join((_logs, _log)) 403 | if _logs: 404 | _mesg += _logs.strip() 405 | else: 406 | _mesg += "no log." 407 | else: 408 | _mesg += _resp['message'] 409 | except Exception as e: 410 | _mesg += str(e) 411 | self.task_view_append(_mesg) 412 | 413 | def get_tc_value(self, textctrl): 414 | return textctrl.GetValue().strip() 415 | 416 | def task_view_append(self, output): 417 | _task_view = self.m._page4_task_view 418 | 419 | _task_view.write(f'{output}\n') 420 | 421 | _task_view.SetFocus() 422 | _mark = _task_view.GetInsertionPoint() 423 | wx.CallAfter(_task_view.ShowPosition, _mark) 424 | 425 | -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # 2019-10-13 00:00:33 4 | 5 | from widgets import StaticBox, btn, cb, cbb, ci, nc, sl, sp, st, tc 6 | 7 | 8 | class Model(object): 9 | def __init__(self, full = True): 10 | self._core() 11 | 12 | if full: 13 | self._outer() 14 | 15 | def _outer(self): 16 | # TARGET 17 | self._url_combobox = cbb() 18 | self._burp_logfile = tc() 19 | self._burp_logfile_chooser = btn() 20 | self._request_file = tc() 21 | self._request_file_chooser = btn() 22 | self._bulkfile = tc() 23 | self._bulkfile_chooser = btn() 24 | self._configfile = tc() 25 | self._configfile_chooser = btn() 26 | self._google_dork = tc() 27 | self._direct_connect = tc() 28 | # OPTIONS(1) 29 | # collected options: 30 | self._cmd_entry = tc() 31 | # self._core()... 32 | # EXECUTION(2) 33 | # LOG(3) 34 | self._page3_log_view = tc() 35 | self._page3_read_target_btn = btn() 36 | self._page3_clear_btn = btn() 37 | self._page3_read_log_btn = btn() 38 | # SQLMAPAPI(4) 39 | self._page4_api_server_label = st() 40 | self._page4_api_server_entry = tc() 41 | self._page4_admin_token_label = st() 42 | self._page4_admin_token_entry = tc() 43 | self._page4_task_new_btn = btn() 44 | self._page4_admin_list_btn = btn() 45 | self._page4_admin_flush_btn = btn() 46 | self._page4_clear_task_view_btn = btn() 47 | self._page4_username_label = st() 48 | self._page4_username_entry = tc() 49 | self._page4_password_label = st() 50 | self._page4_password_entry = tc() 51 | self._page4_option_get_entry = tc() 52 | self._page4_option_set_view = tc() 53 | self._page4_task_view = tc() 54 | # HELP(H) 55 | self._page5_manual_view = tc() 56 | # ABOUT 57 | 58 | def _core(self): 59 | pass 60 | # Inject(Q) 61 | self._sqlmap_path_label = st() 62 | self.sqlmap_path_entry = tc() 63 | self._sqlmap_path_chooser = btn() 64 | # Injection 65 | self._inject_area = StaticBox() 66 | self._inject_area_param_ckbtn = cb() 67 | self._inject_area_param_entry = tc() 68 | self._inject_area_param_filter_ckbtn = cb() 69 | self._inject_area_param_filter_combobox = cbb() 70 | self._inject_area_skip_static_ckbtn = cb() 71 | self._inject_area_skip_ckbtn = cb() 72 | self._inject_area_skip_entry = tc() 73 | self._inject_area_param_exclude_ckbtn = cb() 74 | self._inject_area_param_exclude_entry = tc() 75 | self._inject_area_prefix_ckbtn = cb() 76 | self._inject_area_prefix_entry = tc() 77 | self._inject_area_suffix_ckbtn = cb() 78 | self._inject_area_suffix_entry = tc() 79 | self._inject_area_dbms_ckbtn = cb() 80 | self._inject_area_dbms_combobox = cbb() 81 | self._inject_area_dbms_cred_ckbtn = cb() 82 | self._inject_area_dbms_cred_entry = tc() 83 | self._inject_area_os_ckbtn = cb() 84 | self._inject_area_os_entry = tc() 85 | self._inject_area_no_cast_ckbtn = cb() 86 | self._inject_area_no_escape_ckbtn = cb() 87 | self._inject_area_invalid_bignum_ckbtn = cb() 88 | self._inject_area_invalid_logic_ckbtn = cb() 89 | self._inject_area_invalid_string_ckbtn = cb() 90 | # Detection 91 | self._detection_area = StaticBox() 92 | self._detection_area_level_ckbtn = cb() 93 | self._detection_area_level_scale = sl() 94 | self._detection_area_risk_ckbtn = cb() 95 | self._detection_area_risk_scale = sl() 96 | self._detection_area_str_ckbtn = cb() 97 | self._detection_area_str_entry = tc() 98 | self._detection_area_not_str_ckbtn = cb() 99 | self._detection_area_not_str_entry = tc() 100 | self._detection_area_re_ckbtn = cb() 101 | self._detection_area_re_entry = tc() 102 | self._detection_area_code_ckbtn = cb() 103 | self._detection_area_code_entry = nc() 104 | self._detection_area_text_only_ckbtn = cb() 105 | self._detection_area_titles_ckbtn = cb() 106 | self._detection_area_smart_ckbtn = cb() 107 | # Technique 108 | self._tech_area = StaticBox() 109 | self._tech_area_tech_ckbtn = cb() 110 | self._tech_area_tech_entry = tc() 111 | self._tech_area_time_sec_ckbtn = cb() 112 | self._tech_area_time_sec_entry = nc() 113 | self._tech_area_union_col_ckbtn = cb() 114 | self._tech_area_union_col_entry = nc() 115 | self._tech_area_union_char_ckbtn = cb() 116 | self._tech_area_union_char_entry = tc() 117 | self._tech_area_union_from_ckbtn = cb() 118 | self._tech_area_union_from_entry = tc() 119 | self._tech_area_dns_ckbtn = cb() 120 | self._tech_area_dns_entry = tc() 121 | self._tech_area_second_url_ckbtn = cb() 122 | self._tech_area_second_url_entry = tc() 123 | self._tech_area_second_req_ckbtn = cb() 124 | self._tech_area_second_req_entry = tc() 125 | self._tech_area_second_req_chooser = btn() 126 | # Tamper 127 | self._tamper_area = StaticBox() 128 | self._tamper_area_tamper_view = tc() 129 | # Optimize 130 | self._optimize_area = StaticBox() 131 | self._optimize_area_turn_all_ckbtn = cb() 132 | self._optimize_area_thread_num_ckbtn = cb() 133 | self._optimize_area_thread_num_spinbtn = sp() 134 | self._optimize_area_predict_ckbtn = cb() 135 | self._optimize_area_keep_alive_ckbtn = cb() 136 | self._optimize_area_null_connect_ckbtn = cb() 137 | # Offen 138 | self._offen_area = StaticBox() 139 | self._general_area_verbose_ckbtn = cb() 140 | self._general_area_verbose_scale = sl() 141 | self._general_area_finger_ckbtn = cb() 142 | self._general_area_hex_ckbtn = cb() 143 | self._general_area_batch_ckbtn = cb() 144 | self._misc_area_wizard_ckbtn = cb() 145 | # Hidden 146 | self._hidden_area = StaticBox() 147 | self._hidden_area_crack_ckbtn = cb() 148 | self._hidden_area_debug_ckbtn = cb() 149 | self._hidden_area_profile_ckbtn = cb() 150 | self._hidden_area_disable_precon_ckbtn = cb() 151 | self._hidden_area_disable_stats_ckbtn = cb() 152 | self._hidden_area_force_dbms_ckbtn = cb() 153 | self._hidden_area_force_dns_ckbtn = cb() 154 | self._hidden_area_force_pivoting_ckbtn = cb() 155 | self._hidden_area_smoke_test_ckbtn = cb() 156 | self._hidden_area_live_test_ckbtn = cb() 157 | self._hidden_area_vuln_test_ckbtn = cb() 158 | self._hidden_area_murphy_rate_ckbtn = cb() 159 | self._hidden_area_stop_fail_ckbtn = cb() 160 | self._hidden_area_run_case_ckbtn = cb() 161 | self._hidden_area_dummy_ckbtn = cb() 162 | self._hidden_area_api_ckbtn = cb() 163 | self._hidden_area_taskid_ckbtn = cb() 164 | self._hidden_area_database_ckbtn = cb() 165 | # Request(W) 166 | # HTTP header 167 | self._request_header_area = StaticBox() 168 | self._request_area_random_agent_ckbtn = cb() 169 | self._request_area_mobile_ckbtn = cb() 170 | self._request_area_user_agent_ckbtn = cb() 171 | self._request_area_user_agent_entry = tc() 172 | self._request_area_host_ckbtn = cb() 173 | self._request_area_host_entry = tc() 174 | self._request_area_referer_ckbtn = cb() 175 | self._request_area_referer_entry = tc() 176 | self._request_area_header_ckbtn = cb() 177 | self._request_area_header_entry = tc() 178 | self._request_area_headers_ckbtn = cb() 179 | self._request_area_headers_entry = tc() 180 | # HTTP data 181 | self._request_data_area = StaticBox() 182 | self._request_area_method_ckbtn = cb() 183 | self._request_area_method_entry = tc() 184 | self._request_area_param_del_ckbtn = cb() 185 | self._request_area_param_del_entry = tc() 186 | self._request_area_chunked_ckbtn = cb() 187 | self._request_area_post_ckbtn = cb() 188 | self._request_area_post_entry = tc() 189 | self._request_area_cookie_ckbtn = cb() 190 | self._request_area_cookie_entry = tc() 191 | self._request_area_cookie_del_ckbtn = cb() 192 | self._request_area_cookie_del_entry = tc() 193 | self._request_area_drop_set_cookie_ckbtn = cb() 194 | self._request_area_live_cookies_ckbtn = cb() 195 | self._request_area_live_cookies_entry = tc() 196 | self._request_area_live_cookies_chooser = btn() 197 | self._request_area_load_cookies_ckbtn = cb() 198 | self._request_area_load_cookies_entry = tc() 199 | self._request_area_load_cookies_chooser = btn() 200 | self._request_area_auth_type_ckbtn = cb() 201 | self._request_area_auth_type_entry = tc() 202 | self._request_area_auth_cred_ckbtn = cb() 203 | self._request_area_auth_cred_entry = tc() 204 | self._request_area_auth_file_ckbtn = cb() 205 | self._request_area_auth_file_entry = tc() 206 | self._request_area_auth_file_chooser = btn() 207 | self._request_area_csrf_method_ckbtn = cb() 208 | self._request_area_csrf_method_entry = tc() 209 | self._request_area_csrf_retries_ckbtn = cb() 210 | self._request_area_csrf_retries_entry = nc() 211 | self._request_area_csrf_token_ckbtn = cb() 212 | self._request_area_csrf_token_entry = tc() 213 | self._request_area_csrf_url_ckbtn = cb() 214 | self._request_area_csrf_url_entry = tc() 215 | # Request custom 216 | self._request_custom_area = StaticBox() 217 | self._request_area_ignore_timeouts_ckbtn = cb() 218 | self._request_area_ignore_redirects_ckbtn = cb() 219 | self._request_area_ignore_code_ckbtn = cb() 220 | self._request_area_ignore_code_entry = tc() 221 | self._request_area_skip_urlencode_ckbtn = cb() 222 | self._request_area_force_ssl_ckbtn = cb() 223 | self._request_area_hpp_ckbtn = cb() 224 | self._request_area_delay_ckbtn = cb() 225 | self._request_area_delay_entry = nc() 226 | self._request_area_timeout_ckbtn = cb() 227 | self._request_area_timeout_entry = nc() 228 | self._request_area_retries_ckbtn = cb() 229 | self._request_area_retries_entry = nc() 230 | self._request_area_randomize_ckbtn = cb() 231 | self._request_area_randomize_entry = tc() 232 | self._request_area_eval_ckbtn = cb() 233 | self._request_area_eval_entry = tc() 234 | # Anonymous/Proxy 235 | self._request_proxy_area = StaticBox() 236 | self._request_area_safe_url_ckbtn = cb() 237 | self._request_area_safe_url_entry = tc() 238 | self._request_area_safe_post_ckbtn = cb() 239 | self._request_area_safe_post_entry = tc() 240 | self._request_area_safe_req_ckbtn = cb() 241 | self._request_area_safe_req_entry = tc() 242 | self._request_area_safe_req_chooser = btn() 243 | self._request_area_safe_freq_ckbtn = cb() 244 | self._request_area_safe_freq_entry = tc() 245 | self._request_area_ignore_proxy_ckbtn = cb() 246 | self._request_area_proxy_freq_ckbtn = cb() 247 | self._request_area_proxy_freq_entry = nc() 248 | self._request_area_proxy_file_ckbtn = cb() 249 | self._request_area_proxy_file_entry = tc() 250 | self._request_area_proxy_file_chooser = btn() 251 | self._request_area_proxy_ckbtn = cb() 252 | self._request_area_proxy_ip_label = st() 253 | self._request_area_proxy_ip_entry = tc() 254 | self._request_area_proxy_port_label = st() 255 | self._request_area_proxy_port_entry = nc() 256 | self._request_area_proxy_username_label = st() 257 | self._request_area_proxy_username_entry = tc() 258 | self._request_area_proxy_password_label = st() 259 | self._request_area_proxy_password_entry = tc() 260 | self._request_area_tor_ckbtn = cb() 261 | self._request_area_tor_port_ckbtn = cb() 262 | self._request_area_tor_port_entry = nc() 263 | self._request_area_tor_type_ckbtn = cb() 264 | self._request_area_tor_type_entry = tc() 265 | self._request_area_check_tor_ckbtn = cb() 266 | # Enumerate(E) 267 | # Enumeration 268 | self._enum_area = StaticBox() 269 | # 要求要与_enum_area_enum_labels的结构一致! 270 | self._enum_area_opts_ckbtns = [[cb() for _ in range(5)] for _r in range(3)] 271 | # Dump 272 | self._dump_area = StaticBox() 273 | self._dump_area_dump_ckbtn = cb() 274 | self._dump_area_repair_ckbtn = cb() 275 | self._dump_area_statements_ckbtn = cb() 276 | self._dump_area_search_ckbtn = cb() 277 | self._dump_area_no_sys_db_ckbtn = cb() 278 | self._dump_area_dump_all_ckbtn = cb() 279 | # Limit(when dump) 280 | self._limit_area = StaticBox() 281 | self._limit_area_start_ckbtn = cb() 282 | self._limit_area_start_entry = nc() 283 | self._limit_area_stop_ckbtn = cb() 284 | self._limit_area_stop_entry = nc() 285 | # Blind inject options 286 | self._blind_area = StaticBox() 287 | self._blind_area_first_ckbtn = cb() 288 | self._blind_area_first_entry = nc() 289 | self._blind_area_last_ckbtn = cb() 290 | self._blind_area_last_entry = nc() 291 | # DB, Table, Column name... 292 | self._meta_area = StaticBox() 293 | self._meta_area_D_ckbtn = cb() 294 | self._meta_area_D_entry = tc() 295 | self._meta_area_T_ckbtn = cb() 296 | self._meta_area_T_entry = tc() 297 | self._meta_area_C_ckbtn = cb() 298 | self._meta_area_C_entry = tc() 299 | self._meta_area_U_ckbtn = cb() 300 | self._meta_area_U_entry = tc() 301 | self._meta_area_X_ckbtn = cb() 302 | self._meta_area_X_entry = tc() 303 | self._meta_area_pivot_ckbtn = cb() 304 | self._meta_area_pivot_entry = tc() 305 | self._meta_area_where_ckbtn = cb() 306 | self._meta_area_where_entry = tc() 307 | # Execute SQL 308 | self._runsql_area = StaticBox() 309 | self._runsql_area_sql_query_ckbtn = cb() 310 | self._runsql_area_sql_query_entry = tc() 311 | self._runsql_area_sql_shell_ckbtn = cb() 312 | self._runsql_area_sql_file_ckbtn = cb() 313 | self._runsql_area_sql_file_entry = tc() 314 | self._runsql_area_sql_file_chooser = btn() 315 | # Brute force 316 | self._brute_force_area = StaticBox() 317 | self._brute_force_area_common_tables_ckbtn = cb() 318 | self._brute_force_area_common_columns_ckbtn = cb() 319 | self._brute_force_area_common_files_ckbtn = cb() 320 | # File(R) 321 | # Read remote file 322 | self._file_read_area = StaticBox() 323 | self._file_read_area_file_read_ckbtn = cb() 324 | self._file_read_area_file_read_entry = tc() 325 | self._file_read_area_file_read_btn = btn() 326 | # Upload local file 327 | self._file_write_area = StaticBox() 328 | self._file_write_area_udf_ckbtn = cb() 329 | self._file_write_area_shared_lib_ckbtn = cb() 330 | self._file_write_area_shared_lib_entry = tc() 331 | self._file_write_area_shared_lib_chooser = btn() 332 | self._file_write_area_file_write_ckbtn = cb() 333 | self._file_write_area_file_write_entry = tc() 334 | self._file_write_area_file_write_chooser = btn() 335 | self._file_write_area_file_dest_ckbtn = cb() 336 | self._file_write_area_file_dest_entry = tc() 337 | # Access to the OS behind the DBMS 338 | self._os_access_area = StaticBox() 339 | self._os_access_area_os_cmd_ckbtn = cb() 340 | self._os_access_area_os_cmd_entry = tc() 341 | self._os_access_area_os_shell_ckbtn = cb() 342 | self._os_access_area_os_pwn_ckbtn = cb() 343 | self._os_access_area_os_smbrelay_ckbtn = cb() 344 | self._os_access_area_os_bof_ckbtn = cb() 345 | self._os_access_area_priv_esc_ckbtn = cb() 346 | self._os_access_area_msf_path_ckbtn = cb() 347 | self._os_access_area_msf_path_entry = tc() 348 | self._os_access_area_msf_path_chooser = btn() 349 | self._os_access_area_tmp_path_ckbtn = cb() 350 | self._os_access_area_tmp_path_entry = tc() 351 | # Access to register in remote WIN 352 | self._registry_area = StaticBox() 353 | self._registry_area_reg_ckbtn = cb() 354 | self._registry_area_reg_choice = ci() 355 | self._registry_area_reg_key_label = st() 356 | self._registry_area_reg_key_entry = tc() 357 | self._registry_area_reg_value_label = st() 358 | self._registry_area_reg_value_entry = tc() 359 | self._registry_area_reg_data_label = st() 360 | self._registry_area_reg_data_entry = tc() 361 | self._registry_area_reg_type_label = st() 362 | self._registry_area_reg_type_entry = tc() 363 | # Other(T) 364 | # General 365 | self._general_area = StaticBox() 366 | self._general_area_check_internet_ckbtn = cb() 367 | self._general_area_fresh_queries_ckbtn = cb() 368 | self._general_area_forms_ckbtn = cb() 369 | self._general_area_parse_errors_ckbtn = cb() 370 | self._misc_area_cleanup_ckbtn = cb() 371 | self._general_area_base64_ckbtn = cb() 372 | self._general_area_base64_entry = tc() 373 | self._general_area_base64_safe_ckbtn = cb() 374 | self._general_area_table_prefix_ckbtn = cb() 375 | self._general_area_table_prefix_entry = tc() 376 | self._general_area_binary_fields_ckbtn = cb() 377 | self._general_area_binary_fields_entry = tc() 378 | self._general_area_preprocess_ckbtn = cb() 379 | self._general_area_preprocess_entry = tc() 380 | self._general_area_preprocess_chooser = btn() 381 | self._general_area_postprocess_ckbtn = cb() 382 | self._general_area_postprocess_entry = tc() 383 | self._general_area_postprocess_chooser = btn() 384 | self._general_area_charset_ckbtn = cb() 385 | self._general_area_charset_entry = tc() 386 | self._general_area_encoding_ckbtn = cb() 387 | self._general_area_encoding_entry = tc() 388 | self._general_area_web_root_ckbtn = cb() 389 | self._general_area_web_root_entry = tc() 390 | self._general_area_scope_ckbtn = cb() 391 | self._general_area_scope_entry = tc() 392 | self._general_area_scope_chooser = btn() 393 | self._general_area_test_filter_ckbtn = cb() 394 | self._general_area_test_filter_entry = tc() 395 | self._general_area_test_skip_ckbtn = cb() 396 | self._general_area_test_skip_entry = tc() 397 | self._general_area_crawl_ckbtn = cb() 398 | self._general_area_crawl_entry = nc() 399 | self._general_area_crawl_exclude_ckbtn = cb() 400 | self._general_area_crawl_exclude_entry = tc() 401 | self._general_area_traffic_file_ckbtn = cb() 402 | self._general_area_traffic_file_entry = tc() 403 | self._general_area_traffic_file_chooser = btn() 404 | self._general_area_har_ckbtn = cb() 405 | self._general_area_har_entry = tc() 406 | self._general_area_har_chooser = btn() 407 | self._general_area_flush_session_ckbtn = cb() 408 | self._general_area_dump_format_ckbtn = cb() 409 | self._general_area_dump_format_entry = tc() 410 | self._general_area_csv_del_ckbtn = cb() 411 | self._general_area_csv_del_entry = tc() 412 | self._general_area_save_ckbtn = cb() 413 | self._general_area_save_entry = tc() 414 | self._general_area_save_chooser = btn() 415 | self._general_area_session_file_ckbtn = cb() 416 | self._general_area_session_file_entry = tc() 417 | self._general_area_session_file_chooser = btn() 418 | self._general_area_output_dir_ckbtn = cb() 419 | self._general_area_output_dir_entry = tc() 420 | self._general_area_output_dir_chooser = btn() 421 | # Misc 422 | self._misc_area = StaticBox() 423 | self._misc_area_skip_heuristics_ckbtn = cb() 424 | self._misc_area_skip_waf_ckbtn = cb() 425 | self._misc_area_unstable_ckbtn = cb() 426 | self._misc_area_list_tampers_ckbtn = cb() 427 | self._misc_area_sqlmap_shell_ckbtn = cb() 428 | self._misc_area_disable_color_ckbtn = cb() 429 | self._general_area_eta_ckbtn = cb() 430 | self._misc_area_gpage_ckbtn = cb() 431 | self._misc_area_gpage_spinbtn = sp() 432 | self._misc_area_beep_ckbtn = cb() 433 | self._misc_area_offline_ckbtn = cb() 434 | self._misc_area_purge_ckbtn = cb() 435 | self._misc_area_dependencies_ckbtn = cb() 436 | self._misc_area_update_ckbtn = cb() 437 | self._misc_area_alert_ckbtn = cb() 438 | self._misc_area_alert_entry = tc() 439 | self._misc_area_tmp_dir_ckbtn = cb() 440 | self._misc_area_tmp_dir_entry = tc() 441 | self._misc_area_tmp_dir_chooser = btn() 442 | self._misc_area_answers_ckbtn = cb() 443 | self._misc_area_answers_entry = tc() 444 | self._misc_area_z_ckbtn = cb() 445 | self._misc_area_z_entry = tc() 446 | self._misc_area_results_file_ckbtn = cb() 447 | self._misc_area_results_file_entry = tc() 448 | self._misc_area_results_file_chooser = btn() 449 | 450 | 451 | def main(): 452 | pass 453 | 454 | 455 | if __name__ == '__main__': 456 | main() 457 | -------------------------------------------------------------------------------- /opts_wx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # 2019-05-05 20:43:40 4 | 5 | from widgets import wx, Panel, Scroll, nb, st, btn 6 | from widgets import EVT_BUTTON, EVT_CHECKBOX 7 | from layout import Layout_opts 8 | 9 | 10 | class Notebook(nb): 11 | def __init__(self, parent, model, handlers): 12 | ''' 13 | m: model.Model 14 | 最大的宽应该是由最长的 request定制的第一行 决定 15 | 16 | 以"Other"标签的height作为标准高, 17 | 高于此height的标签页使用ScrolledPanel, 显示滚动条 18 | ''' 19 | super().__init__(parent) 20 | self.m = model 21 | layout = Layout_opts(self, model) 22 | 23 | self._handlers = handlers 24 | # OPTIONS - Inject, Request, Enumerate, File, Other, Tamper 25 | page1_setting = self.build_page1_setting(layout) 26 | page1_request = self.build_page1_request(layout) 27 | page1_enumeration = self.build_page1_enumeration(layout) 28 | page1_file = self.build_page1_file(layout) 29 | page1_other = self.build_page1_other(layout) 30 | page1_tamper = self.build_page1_tamper(layout) 31 | 32 | self.AddPage(page1_setting, '测试(Q)') 33 | self.AddPage(page1_request, '请求(W)') 34 | self.AddPage(page1_enumeration, '枚举(E)') 35 | self.AddPage(page1_file, '文件(R)') 36 | self.AddPage(page1_other, '其他(T)') 37 | self.AddPage(page1_tamper, 'Tamper(Y)') 38 | 39 | def cb_single(self, event, checkbox): 40 | cb = event.GetEventObject() 41 | if cb.IsChecked(): 42 | checkbox.SetValue(False) 43 | # 这是最后一个Bind, 要skip哈! 不然改不了颜色 44 | event.Skip() 45 | 46 | def optimize_area_controller(self, event): 47 | if self.m._optimize_area_turn_all_ckbtn.IsChecked(): 48 | self.m._optimize_area_predict_ckbtn.SetValue(False) 49 | self.m._optimize_area_keep_alive_ckbtn.SetValue(False) 50 | self.m._optimize_area_null_connect_ckbtn.SetValue(False) 51 | 52 | self.m._optimize_area_predict_ckbtn.Disable() 53 | self.m._optimize_area_keep_alive_ckbtn.Disable() 54 | self.m._optimize_area_null_connect_ckbtn.Disable() 55 | else: 56 | self.m._optimize_area_predict_ckbtn.Enable() 57 | self.m._optimize_area_keep_alive_ckbtn.Enable() 58 | self.m._optimize_area_null_connect_ckbtn.Enable() 59 | # 这是最后一个Bind, 要skip哈! 不然改不了颜色 60 | event.Skip() 61 | 62 | def build_page1_setting(self, layout): 63 | p = Scroll(self) 64 | m = self.m 65 | 66 | m._sqlmap_path_label.Create(p, label = '指定sqlmap路径:') 67 | m.sqlmap_path_entry.Create(p, value = 'sqlmap') 68 | m._sqlmap_path_chooser.Create(p, label = '打开') 69 | m._sqlmap_path_chooser.Bind( 70 | EVT_BUTTON, 71 | lambda evt, data = [m.sqlmap_path_entry]: 72 | self._handlers.set_file_entry_text(evt, data)) 73 | 74 | self.build_page1_setting_inject(p, m) 75 | self.build_page1_setting_detection(p, m) 76 | self.build_page1_setting_tech(p, m) 77 | self.build_page1_setting_tamper(p, m) 78 | self.build_page1_setting_optimize(p, m) 79 | self.build_page1_setting_offen(p, m) 80 | self.build_page1_setting_hidden(p, m) 81 | 82 | vbox = layout.setting_sizer() 83 | # 不能用SetSizerAndFit, Fit会自适应的, 从而没有滚动条 84 | # p.SetSizerAndFit(vbox) 85 | p.SetSizer(vbox) 86 | p.SetupScrolling(scroll_x = False, scrollIntoView = False) 87 | return p 88 | 89 | def build_page1_setting_inject(self, panel, m): 90 | _sb = m._inject_area 91 | _sb.Create(panel, label = '注入选项') 92 | 93 | _choices = ['GET', 'POST', 'URI', 'Cookie', 'User-Agent' 94 | 'Referer', 'Host', '(custom) POST', '(custom HEADER)'] 95 | 96 | m._inject_area_param_ckbtn.Create(_sb, label = '仅测参数') 97 | m._inject_area_param_entry.Create(_sb) 98 | m._inject_area_param_filter_ckbtn.Create(_sb, label = '仅测范围') 99 | m._inject_area_param_filter_combobox.Create(_sb, choices = _choices) 100 | m._inject_area_skip_static_ckbtn.Create(_sb, label = '跳过不像是动态的参数') 101 | m._inject_area_skip_static_ckbtn.SetValue(True) 102 | m._inject_area_skip_ckbtn.Create(_sb, label = '忽略参数') 103 | m._inject_area_skip_entry.Create(_sb) 104 | m._inject_area_param_exclude_ckbtn.Create(_sb, label = '忽略参数(正则)') 105 | m._inject_area_param_exclude_entry.Create(_sb) 106 | m._inject_area_prefix_ckbtn.Create(_sb, label = 'payload前缀') 107 | m._inject_area_prefix_entry.Create(_sb) 108 | m._inject_area_suffix_ckbtn.Create(_sb, label = 'payload后缀') 109 | m._inject_area_suffix_entry.Create(_sb) 110 | m._inject_area_dbms_ckbtn.Create(_sb, label = '固定DBMS为') 111 | m._inject_area_dbms_combobox.Create(_sb, choices = ['mysql', 'sqlite', 'sqlserver']) 112 | m._inject_area_dbms_cred_ckbtn.Create(_sb, label = 'DB认证') 113 | m._inject_area_dbms_cred_entry.Create(_sb) 114 | m._inject_area_os_ckbtn.Create(_sb, label = '固定OS为') 115 | m._inject_area_os_entry.Create(_sb) 116 | m._inject_area_no_cast_ckbtn.Create(_sb, label = '关闭数据类型转换') 117 | m._inject_area_no_escape_ckbtn.Create(_sb, label = '关掉string转义') 118 | self._inject_area_invalid_label = st(_sb, label = 'payload\'s invalid value:') 119 | self._inject_area_invalid_label.SetToolTip('默认情况下, 要使原参数值无效时会改成相反数\n' 120 | '真: id=13 假: id=-13') 121 | m._inject_area_invalid_bignum_ckbtn.Create(_sb, label = '使用大数') 122 | m._inject_area_invalid_logic_ckbtn.Create(_sb, label = '使用布尔运算') 123 | m._inject_area_invalid_string_ckbtn.Create(_sb, label = '使用随机字串') 124 | 125 | def build_page1_setting_detection(self, panel, m): 126 | _sb = m._detection_area 127 | _sb.Create(panel, label = '探测选项') 128 | 129 | m._detection_area_level_ckbtn.Create(_sb, label = '探测等级(范围)') 130 | m._detection_area_level_scale.Create(_sb, 131 | value = 1, 132 | minValue = 1, 133 | maxValue = 5, 134 | style = wx.SL_VALUE_LABEL) 135 | m._detection_area_risk_ckbtn.Create(_sb, label = 'payload危险等级') 136 | m._detection_area_risk_scale.Create(_sb, 137 | value = 1, 138 | minValue = 1, 139 | maxValue = 3, 140 | style = wx.SL_VALUE_LABEL) 141 | m._detection_area_str_ckbtn.Create(_sb, label = '指定True时的字符串') 142 | m._detection_area_str_entry.Create(_sb) 143 | m._detection_area_not_str_ckbtn.Create(_sb, label = '指定False时的字符串') 144 | m._detection_area_not_str_entry.Create(_sb) 145 | m._detection_area_re_ckbtn.Create(_sb, label = '指定正则') 146 | m._detection_area_re_entry.Create(_sb) 147 | m._detection_area_code_ckbtn.Create(_sb, label = '指定http状态码') 148 | m._detection_area_code_entry.Create(_sb) 149 | m._detection_area_text_only_ckbtn.Create(_sb, label = '仅对比文本') 150 | m._detection_area_text_only_ckbtn.Bind( 151 | EVT_CHECKBOX, 152 | lambda evt, cbtmp = m._detection_area_titles_ckbtn: 153 | self.cb_single(evt, cbtmp)) 154 | 155 | m._detection_area_titles_ckbtn.Create(_sb, label = '仅对比title') 156 | m._detection_area_titles_ckbtn.Bind( 157 | EVT_CHECKBOX, 158 | lambda evt, cbtmp = m._detection_area_text_only_ckbtn: 159 | self.cb_single(evt, cbtmp)) 160 | 161 | m._detection_area_smart_ckbtn.Create(_sb, label = '寻找明显目标并测试') 162 | self._detection_area_hr = wx.StaticLine(_sb) 163 | self._detection_area_level_note = st(_sb, 164 | label = 'Level 1(默认): 所有GET, POST参数\n' 165 | 'Level 2 追加: Cookie\n' 166 | 'Level 3 追加: User-Agent/Referer\n' 167 | 'Level 4 追加: 啥?\n' 168 | 'Level 5 追加: Host报头') 169 | self._detection_area_risk_note = st(_sb, 170 | label = 'Risk 1(默认): 基本无风险\n' 171 | 'Risk 2 追加: 大量时间型盲注\n' 172 | 'Risk 3 追加: OR型布尔盲注') 173 | 174 | def build_page1_setting_tech(self, panel, m): 175 | _sb = m._tech_area 176 | _sb.Create(panel, label = '各注入技术的选项') 177 | 178 | m._tech_area_tech_ckbtn.Create(_sb, label = '注入技术') 179 | m._tech_area_tech_entry.Create(_sb) 180 | m._tech_area_tech_entry.SetInitialSize( 181 | m._tech_area_tech_entry.GetSizeFromTextSize( 182 | m._tech_area_tech_entry.GetTextExtent("a" * 15).x)) 183 | m._tech_area_time_sec_ckbtn.Create(_sb, label = '指定DB延迟几秒响应') 184 | m._tech_area_time_sec_entry.Create(_sb) 185 | m._tech_area_union_col_ckbtn.Create(_sb, label = '指定最大union列数') 186 | m._tech_area_union_col_entry.Create(_sb) 187 | m._tech_area_union_char_ckbtn.Create(_sb, label = '指定枚举列数时所用字符') 188 | m._tech_area_union_char_entry.Create(_sb) 189 | m._tech_area_union_from_ckbtn.Create(_sb, label = '指定枚举列数时from的表名') 190 | m._tech_area_union_from_entry.Create(_sb) 191 | m._tech_area_dns_ckbtn.Create(_sb, label = '指定DNS') 192 | m._tech_area_dns_entry.Create(_sb) 193 | m._tech_area_second_url_ckbtn.Create(_sb, label = '指定二阶响应的url') 194 | m._tech_area_second_url_entry.Create(_sb) 195 | m._tech_area_second_req_ckbtn.Create(_sb, label = '使用含二阶HTTP请求的文件:') 196 | m._tech_area_second_req_entry.Create(_sb) 197 | m._tech_area_second_req_chooser.Create(_sb, label = '打开') 198 | m._tech_area_second_req_chooser.Bind( 199 | EVT_BUTTON, 200 | lambda evt, data = [m._tech_area_second_req_entry]: 201 | self._handlers.set_file_entry_text(evt, data)) 202 | 203 | def build_page1_setting_tamper(self, panel, m): 204 | _sb = m._tamper_area 205 | _sb.Create(panel, label = 'tamper脚本') 206 | 207 | # 多行文本框的默认size太小了 208 | m._tamper_area_tamper_view.Create(_sb, 209 | size = (300, -1), 210 | style = wx.TE_MULTILINE) 211 | 212 | def build_page1_setting_optimize(self, panel, m): 213 | _sb = m._optimize_area 214 | _sb.Create(panel, label = '性能优化') 215 | 216 | m._optimize_area_turn_all_ckbtn.Create(_sb, label = '启用所有优化选项') 217 | m._optimize_area_thread_num_ckbtn.Create(_sb, label = '使用线程数:') 218 | m._optimize_area_thread_num_spinbtn.Create(_sb, value = '2', min = 2, max = 10000) 219 | m._optimize_area_predict_ckbtn.Create(_sb, label = '预测通常的查询结果') 220 | m._optimize_area_keep_alive_ckbtn.Create(_sb, label = 'http连接使用keep-alive') 221 | m._optimize_area_null_connect_ckbtn.Create(_sb, label = '只比较响应大小报头, 不获取响应主体') 222 | 223 | m._optimize_area_turn_all_ckbtn.Bind(EVT_CHECKBOX, self.optimize_area_controller) 224 | 225 | def build_page1_setting_offen(self, panel, m): 226 | _sb = m._offen_area 227 | _sb.Create(panel, label = '常用选项') 228 | 229 | m._general_area_verbose_ckbtn.Create(_sb, label = '输出详细程度') 230 | m._general_area_verbose_scale.Create(_sb, 231 | value = 1, 232 | minValue = 0, 233 | maxValue = 6, 234 | style = wx.SL_VALUE_LABEL) 235 | m._general_area_finger_ckbtn.Create(_sb, label = '精确检测DB等版本信息') 236 | m._general_area_hex_ckbtn.Create(_sb, label = '响应使用hex转换') 237 | m._general_area_batch_ckbtn.Create(_sb, label = '非交互模式, 一切皆默认') 238 | m._misc_area_wizard_ckbtn.Create(_sb, label = '新手向导') 239 | 240 | def build_page1_setting_hidden(self, panel, m): 241 | _sb = m._hidden_area 242 | _sb.Create(panel, label = 'Hidden') 243 | 244 | m._hidden_area_crack_ckbtn.Create(_sb, label = '--crack') 245 | m._hidden_area_debug_ckbtn.Create(_sb, label = '--debug') 246 | m._hidden_area_profile_ckbtn.Create(_sb, label = '--profile') 247 | m._hidden_area_disable_precon_ckbtn.Create(_sb, label = '--disable-precon') 248 | m._hidden_area_disable_stats_ckbtn.Create(_sb, label = '--disable-stats') 249 | m._hidden_area_force_dbms_ckbtn.Create(_sb, label = '--force-dbms') 250 | m._hidden_area_force_dns_ckbtn.Create(_sb, label = '--force-dns') 251 | m._hidden_area_force_pivoting_ckbtn.Create(_sb, label = '--force-pivoting') 252 | m._hidden_area_smoke_test_ckbtn.Create(_sb, label = '--smoke-test') 253 | m._hidden_area_live_test_ckbtn.Create(_sb, label = '--live-test') 254 | m._hidden_area_vuln_test_ckbtn.Create(_sb, label = '--vuln-test') 255 | m._hidden_area_murphy_rate_ckbtn.Create(_sb, label = '--murphy-rate') 256 | m._hidden_area_stop_fail_ckbtn.Create(_sb, label = '--stop-fail') 257 | m._hidden_area_run_case_ckbtn.Create(_sb, label = '--run-case') 258 | m._hidden_area_dummy_ckbtn.Create(_sb, label = '--dummy') 259 | m._hidden_area_api_ckbtn.Create(_sb, label = '--api') 260 | m._hidden_area_taskid_ckbtn.Create(_sb, label = '--taskid') 261 | m._hidden_area_database_ckbtn.Create(_sb, label = '--database') 262 | 263 | def build_page1_request(self, layout): 264 | p = Scroll(self, style = wx.BORDER_THEME) 265 | m = self.m 266 | 267 | self.build_page1_request_header(p, m) 268 | self.build_page1_request_data(p, m) 269 | self.build_page1_request_custom(p, m) 270 | self.build_page1_request_proxy(p, m) 271 | 272 | vbox = layout.request_sizer() 273 | # 不能用SetSizerAndFit, Fit会自适应的, 从而没有滚动条 274 | # p.SetSizerAndFit(vbox) 275 | p.SetSizer(vbox) 276 | p.SetupScrolling(scroll_x = False, scrollIntoView = False) 277 | return p 278 | 279 | def build_page1_request_header(self, panel, m): 280 | _sb = m._request_header_area 281 | _sb.Create(panel, label = 'HTTP header') 282 | 283 | m._request_area_random_agent_ckbtn.Create(_sb, label = '随机User-Agent头') 284 | m._request_area_random_agent_ckbtn.SetValue(True) 285 | m._request_area_mobile_ckbtn.Create(_sb, label = '模拟手机请求') 286 | m._request_area_user_agent_ckbtn.Create(_sb, label = '指定User-Agent头') 287 | m._request_area_user_agent_entry.Create(_sb) 288 | m._request_area_host_ckbtn.Create(_sb, label = 'Host头') 289 | m._request_area_host_entry.Create(_sb) 290 | m._request_area_referer_ckbtn.Create(_sb, label = 'referer头') 291 | m._request_area_referer_entry.Create(_sb) 292 | m._request_area_header_ckbtn.Create(_sb, label = '--header(-H)') 293 | m._request_area_header_entry.Create(_sb) 294 | m._request_area_headers_ckbtn.Create(_sb, label = '额外的headers') 295 | m._request_area_headers_entry.Create(_sb) 296 | 297 | def build_page1_request_data(self, panel, m): 298 | _sb = m._request_data_area 299 | _sb.Create(panel, label = 'HTTP data') 300 | 301 | m._request_area_method_ckbtn.Create(_sb, label = 'HTTP请求方式') 302 | m._request_area_method_entry.Create(_sb) 303 | m._request_area_param_del_ckbtn.Create(_sb, label = '指定--data=中的参数分隔符') 304 | m._request_area_param_del_entry.Create(_sb) 305 | m._request_area_chunked_ckbtn.Create(_sb, label = '"分块传输"发送POST请求') 306 | m._request_area_post_ckbtn.Create(_sb, label = '通过POST提交data:') 307 | self._request_data_hr1 = wx.StaticLine(_sb) 308 | m._request_area_post_entry.Create(_sb) 309 | m._request_area_cookie_ckbtn.Create(_sb, label = '要包含的Cookie:') 310 | m._request_area_cookie_entry.Create(_sb) 311 | m._request_area_cookie_del_ckbtn.Create(_sb, label = '指定cookie分隔符') 312 | m._request_area_cookie_del_entry.Create(_sb) 313 | m._request_area_drop_set_cookie_ckbtn.Create(_sb, label = '丢弃Set-Cookie头') 314 | m._request_area_live_cookies_ckbtn.Create(_sb, label = 'live_cookies') 315 | m._request_area_live_cookies_entry.Create(_sb) 316 | m._request_area_live_cookies_chooser.Create(_sb, label = '打开') 317 | m._request_area_live_cookies_chooser.Bind( 318 | EVT_BUTTON, 319 | lambda evt, data = [m._request_area_live_cookies_entry]: 320 | self._handlers.set_file_entry_text(evt, data)) 321 | 322 | m._request_area_load_cookies_ckbtn.Create(_sb, label = '本地Cookie文件') 323 | m._request_area_load_cookies_entry.Create(_sb) 324 | m._request_area_load_cookies_chooser.Create(_sb, label = '打开') 325 | m._request_area_load_cookies_chooser.Bind( 326 | EVT_BUTTON, 327 | lambda evt, data = [m._request_area_load_cookies_entry]: 328 | self._handlers.set_file_entry_text(evt, data)) 329 | 330 | self._request_data_hr2 = wx.StaticLine(_sb) 331 | m._request_area_auth_type_ckbtn.Create(_sb, label = 'http认证类型') 332 | m._request_area_auth_type_entry.Create(_sb) 333 | m._request_area_auth_cred_ckbtn.Create(_sb, label = 'http认证账密') 334 | m._request_area_auth_cred_entry.Create(_sb) 335 | m._request_area_auth_file_ckbtn.Create(_sb, label = 'http认证文件') 336 | m._request_area_auth_file_entry.Create(_sb) 337 | m._request_area_auth_file_chooser.Create(_sb, label = '打开') 338 | m._request_area_auth_file_chooser.Bind( 339 | EVT_BUTTON, 340 | lambda evt, data = [m._request_area_auth_file_entry]: 341 | self._handlers.set_file_entry_text(evt, data)) 342 | 343 | m._request_area_csrf_method_ckbtn.Create(_sb, label = 'csrf_method') 344 | m._request_area_csrf_method_entry.Create(_sb) 345 | m._request_area_csrf_retries_ckbtn.Create(_sb, label = 'csrf_retries') 346 | m._request_area_csrf_retries_entry.Create(_sb) 347 | m._request_area_csrf_token_ckbtn.Create(_sb, label = 'csrf_token') 348 | m._request_area_csrf_token_entry.Create(_sb) 349 | m._request_area_csrf_url_ckbtn.Create(_sb, label = '获取csrf_token的url') 350 | m._request_area_csrf_url_entry.Create(_sb) 351 | 352 | def build_page1_request_custom(self, panel, m): 353 | _sb = m._request_custom_area 354 | _sb.Create(panel, label = 'request定制') 355 | 356 | m._request_area_ignore_timeouts_ckbtn.Create(_sb, label = '忽略连接超时') 357 | m._request_area_ignore_redirects_ckbtn.Create(_sb, label = '忽略重定向') 358 | m._request_area_ignore_code_ckbtn.Create(_sb, label = '忽略错误型状态码:') 359 | m._request_area_ignore_code_entry.Create(_sb, value = '401') 360 | m._request_area_ignore_code_entry.SetInitialSize( 361 | m._request_area_ignore_code_entry.GetSizeFromTextSize( 362 | m._request_area_ignore_code_entry.GetTextExtent("a" * 20).x)) 363 | m._request_area_skip_urlencode_ckbtn.Create(_sb, label = 'payload不使用url编码') 364 | m._request_area_force_ssl_ckbtn.Create(_sb, label = '强制使用HTTPS') 365 | m._request_area_hpp_ckbtn.Create(_sb, label = 'HTTP参数污染') 366 | m._request_area_delay_ckbtn.Create(_sb, label = '请求间隔(秒)') 367 | m._request_area_delay_entry.Create(_sb) 368 | m._request_area_timeout_ckbtn.Create(_sb, label = '超时前等几秒') 369 | m._request_area_timeout_entry.Create(_sb, value = '30') 370 | m._request_area_retries_ckbtn.Create(_sb, label = '超时重试次数') 371 | m._request_area_retries_entry.Create(_sb, value = '3') 372 | m._request_area_randomize_ckbtn.Create(_sb, label = '指定要随机改变值的参数') 373 | m._request_area_randomize_entry.Create(_sb) 374 | m._request_area_eval_ckbtn.Create(_sb, label = '--eval=') 375 | m._request_area_eval_entry.Create(_sb) 376 | 377 | def build_page1_request_proxy(self, panel, m): 378 | _sb = m._request_proxy_area 379 | _sb.Create(panel, label = '隐匿/代理') 380 | 381 | m._request_area_safe_url_ckbtn.Create(_sb, label = '顺便掺杂地访问一个安全url') 382 | m._request_area_safe_url_entry.Create(_sb) 383 | m._request_area_safe_post_ckbtn.Create(_sb, label = '提交到安全url的post数据') 384 | m._request_area_safe_post_entry.Create(_sb) 385 | m._request_area_safe_req_ckbtn.Create(_sb, label = '从文件载入safe HTTP请求') 386 | m._request_area_safe_req_entry.Create(_sb) 387 | m._request_area_safe_req_chooser.Create(_sb, label = '打开') 388 | m._request_area_safe_req_chooser.Bind( 389 | EVT_BUTTON, 390 | lambda evt, data = [m._request_area_safe_req_entry]: 391 | self._handlers.set_file_entry_text(evt, data)) 392 | 393 | m._request_area_safe_freq_ckbtn.Create(_sb, label = '访问安全url的频率') 394 | m._request_area_safe_freq_entry.Create(_sb) 395 | self._request_proxy_hr = wx.StaticLine(_sb) 396 | m._request_area_ignore_proxy_ckbtn.Create(_sb, label = '忽略系统默认代理') 397 | m._request_area_proxy_freq_ckbtn.Create(_sb, label = '--proxy-freq') 398 | m._request_area_proxy_freq_entry.Create(_sb) 399 | m._request_area_proxy_file_ckbtn.Create(_sb, label = '代理列表文件') 400 | m._request_area_proxy_file_entry.Create(_sb) 401 | m._request_area_proxy_file_chooser.Create(_sb, label = '打开') 402 | m._request_area_proxy_file_chooser.Bind( 403 | EVT_BUTTON, 404 | lambda evt, data = [m._request_area_proxy_file_entry]: 405 | self._handlers.set_file_entry_text(evt, data)) 406 | 407 | m._request_area_proxy_ckbtn.Create(_sb, label = '使用代理') 408 | m._request_area_proxy_ip_label.Create(_sb, label = 'IP:') 409 | m._request_area_proxy_ip_entry.Create(_sb) 410 | m._request_area_proxy_port_label.Create(_sb, label = 'PORT:') 411 | m._request_area_proxy_port_entry.Create(_sb) 412 | m._request_area_proxy_username_label.Create(_sb, label = 'username:') 413 | m._request_area_proxy_username_entry.Create(_sb) 414 | m._request_area_proxy_password_label.Create(_sb, label = 'passwd:') 415 | m._request_area_proxy_password_entry.Create(_sb) 416 | m._request_area_tor_ckbtn.Create(_sb, label = '使用Tor匿名网络') 417 | m._request_area_tor_port_ckbtn.Create(_sb, label = 'Tor端口:') 418 | m._request_area_tor_port_entry.Create(_sb) 419 | m._request_area_tor_type_ckbtn.Create(_sb, label = 'Tor代理类型') 420 | m._request_area_tor_type_entry.Create(_sb) 421 | m._request_area_check_tor_ckbtn.Create(_sb, label = '检查Tor连接') 422 | 423 | def build_page1_enumeration(self, layout): 424 | p = Panel(self) 425 | m = self.m 426 | 427 | self.build_page1_enumeration_enum(p, m) 428 | self.build_page1_enumeration_dump(p, m) 429 | self.build_page1_enumeration_limit(p, m) 430 | self.build_page1_enumeration_blind(p, m) 431 | self.build_page1_enumeration_meta(p, m) 432 | self.build_page1_enumeration_runsql(p, m) 433 | self.build_page1_enumeration_brute_force(p, m) 434 | 435 | vbox = layout.enumeration_sizer() 436 | p.SetSizer(vbox) 437 | return p 438 | 439 | def build_page1_enumeration_enum(self, panel, m): 440 | _sb = m._enum_area 441 | _sb.Create(panel, label = '枚举') 442 | # 要与_enum_area_opts_ckbtns的结构一致! 443 | _enum_area_enum_labels = ( 444 | ('DB banner', '当前用户', '当前数据库', '主机名', '是否为DBA'), 445 | ('用户', '密码', '权限', '角色', '库名'), 446 | ('表名', '列名', '架构', '行数', '备注')) 447 | for _i, _l in enumerate(m._enum_area_opts_ckbtns): # 三列 448 | for _j, _cb in enumerate(_l): 449 | _cb.Create(_sb, label = _enum_area_enum_labels[_i][_j]) 450 | 451 | def build_page1_enumeration_dump(self, panel, m): 452 | _sb = m._dump_area 453 | _sb.Create(panel, label = 'Dump(转储)') 454 | 455 | m._dump_area_dump_ckbtn.Create(_sb, label = 'dump(某库某表的条目)') 456 | m._dump_area_repair_ckbtn.Create(_sb, label = '重新获取有未知符号(?)的条目') 457 | m._dump_area_statements_ckbtn.Create(_sb, label = '获取正在运行的sql语句') 458 | m._dump_area_search_ckbtn.Create(_sb, label = '搜索') 459 | m._dump_area_no_sys_db_ckbtn.Create(_sb, label = '排除系统库') 460 | m._dump_area_dump_all_ckbtn.Create(_sb, label = '全部dump(拖库)') 461 | 462 | def build_page1_enumeration_limit(self, panel, m): 463 | _sb = m._limit_area 464 | _sb.Create(panel, label = 'limit(dump时的限制)') 465 | 466 | m._limit_area_start_ckbtn.Create(_sb, label = '始于第几条') 467 | m._limit_area_start_entry.Create(_sb) 468 | m._limit_area_start_entry.SetInitialSize( 469 | m._limit_area_start_entry.GetSizeFromTextSize( 470 | m._limit_area_start_entry.GetTextExtent("a" * 15).x)) 471 | # self._limit_area_start_label = st(_sb, label = '行') 472 | m._limit_area_stop_ckbtn.Create(_sb, label = '止于第几条') 473 | m._limit_area_stop_entry.Create(_sb) 474 | m._limit_area_stop_entry.SetInitialSize( 475 | m._limit_area_stop_entry.GetSizeFromTextSize( 476 | m._limit_area_stop_entry.GetTextExtent("a" * 15).x)) 477 | # self._limit_area_stop_label = st(_sb, label = '行') 478 | 479 | def build_page1_enumeration_blind(self, panel, m): 480 | _sb = m._blind_area 481 | _sb.Create(panel, label = '盲注选项') 482 | 483 | m._blind_area_first_ckbtn.Create(_sb, label = '从第几个字符') 484 | m._blind_area_first_entry.Create(_sb) 485 | # self._blind_area_first_label = st(_sb, label = '个字符') 486 | m._blind_area_last_ckbtn.Create(_sb, label = '到第几个字符') 487 | m._blind_area_last_entry.Create(_sb) 488 | # self._blind_area_last_label = st(_sb, label = '个字符') 489 | # self._blind_area_note_label = st(_sb, label = '只适用于盲注,\n因为报错,union注入要求列数相同') 490 | 491 | def build_page1_enumeration_meta(self, panel, m): 492 | _sb = m._meta_area 493 | _sb.Create(panel, label = '数据库名, 表名, 列名...') 494 | 495 | m._meta_area_D_ckbtn.Create(_sb, label = '指定库名') 496 | m._meta_area_D_entry.Create(_sb) 497 | m._meta_area_T_ckbtn.Create(_sb, label = '指定表名') 498 | m._meta_area_T_entry.Create(_sb) 499 | m._meta_area_C_ckbtn.Create(_sb, label = '指定列名') 500 | m._meta_area_C_entry.Create(_sb) 501 | m._meta_area_U_ckbtn.Create(_sb, label = '指定用户') 502 | m._meta_area_U_entry.Create(_sb) 503 | m._meta_area_X_ckbtn.Create(_sb, label = '排除标志符') 504 | m._meta_area_X_entry.Create(_sb) 505 | m._meta_area_pivot_ckbtn.Create(_sb, label = '指定Pivot列名') 506 | m._meta_area_pivot_entry.Create(_sb) 507 | m._meta_area_where_ckbtn.Create(_sb, label = 'where子句') 508 | m._meta_area_where_entry.Create(_sb) 509 | 510 | def build_page1_enumeration_runsql(self, panel, m): 511 | _sb = m._runsql_area 512 | _sb.Create(panel, label = '执行SQL语句') 513 | 514 | m._runsql_area_sql_query_ckbtn.Create(_sb, label = 'SQL语句:') 515 | m._runsql_area_sql_query_entry.Create(_sb) 516 | m._runsql_area_sql_shell_ckbtn.Create(_sb, label = '打开一个SQL交互shell') 517 | m._runsql_area_sql_file_ckbtn.Create(_sb, label = '本地SQL文件:') 518 | m._runsql_area_sql_file_entry.Create(_sb) 519 | m._runsql_area_sql_file_chooser.Create(_sb, label = '打开') 520 | m._runsql_area_sql_file_chooser.Bind( 521 | EVT_BUTTON, 522 | lambda evt, data = [m._runsql_area_sql_file_entry]: 523 | self._handlers.set_file_entry_text(evt, data)) 524 | 525 | def build_page1_enumeration_brute_force(self, panel, m): 526 | _sb = m._brute_force_area 527 | _sb.Create(panel, label = '暴破表名/列名') 528 | 529 | self._brute_force_area_label = st(_sb, label = 'check existence of:') 530 | m._brute_force_area_common_tables_ckbtn.Create(_sb, label = '常用表名') 531 | m._brute_force_area_common_columns_ckbtn.Create(_sb, label = '常用列名') 532 | m._brute_force_area_common_files_ckbtn.Create(_sb, label = '常用文件') 533 | 534 | def build_page1_file(self, layout): 535 | p = Panel(self) 536 | m = self.m 537 | 538 | self._page1_file_note_label = st(p, 539 | label = 'Note: only if stacked query(堆查询注入) worked, ' 540 | 'these functions below can be used except udf!') 541 | self.build_page1_file_read(p, m) 542 | self.build_page1_file_write(p, m) 543 | self.build_page1_file_os_access(p, m) 544 | self.build_page1_file_registry(p, m) 545 | 546 | vbox = layout.file_sizer() 547 | p.SetSizer(vbox) 548 | return p 549 | 550 | def build_page1_file_read(self, panel, m): 551 | _sb = m._file_read_area 552 | _sb.Create(panel, label = '读取远程文件') 553 | 554 | m._file_read_area_file_read_ckbtn.Create(_sb, label = '远程文件路径(--file-read=)') 555 | m._file_read_area_file_read_entry.Create(_sb, value = '/etc/passwd') 556 | m._file_read_area_file_read_btn.Create(_sb, label = '查看') 557 | 558 | m._file_read_area_file_read_btn.Bind(EVT_BUTTON, self._handlers.read_dumped_file) 559 | 560 | def build_page1_file_write(self, panel, m): 561 | _sb = m._file_write_area 562 | _sb.Create(panel, label = '文件上传') 563 | 564 | m._file_write_area_udf_ckbtn.Create(_sb, label = '注入UDF(仅限MySQL和PostgreSQL)') 565 | m._file_write_area_shared_lib_ckbtn.Create(_sb, label = '本地共享库路径(--shared-lib=)') 566 | m._file_write_area_shared_lib_entry.Create(_sb) 567 | m._file_write_area_shared_lib_chooser.Create(_sb, label = '打开') 568 | m._file_write_area_shared_lib_chooser.Bind( 569 | EVT_BUTTON, 570 | lambda evt, data = [m._file_write_area_shared_lib_entry]: 571 | self._handlers.set_file_entry_text(evt, data)) 572 | 573 | m._file_write_area_file_write_ckbtn.Create(_sb, label = '本地文件路径(--file-write=)') 574 | m._file_write_area_file_write_entry.Create(_sb) 575 | m._file_write_area_file_write_chooser.Create(_sb, label = '打开') 576 | m._file_write_area_file_write_chooser.Bind( 577 | EVT_BUTTON, 578 | lambda evt, data = [m._file_write_area_file_write_entry]: 579 | self._handlers.set_file_entry_text(evt, data)) 580 | 581 | m._file_write_area_file_dest_ckbtn.Create(_sb, label = '远程文件路径(--file-dest=)') 582 | m._file_write_area_file_dest_entry.Create(_sb) 583 | 584 | def build_page1_file_os_access(self, panel, m): 585 | _sb = m._os_access_area 586 | _sb.Create(panel, label = '访问后端OS') 587 | 588 | m._os_access_area_os_cmd_ckbtn.Create(_sb, label = '执行CLI命令') 589 | m._os_access_area_os_cmd_entry.Create(_sb) 590 | m._os_access_area_os_shell_ckbtn.Create(_sb, label = '获取交互shell') 591 | self._os_access_area_for_msf_label = st(_sb, label = 'Meterpreter相关(TCP连接):') 592 | m._os_access_area_os_pwn_ckbtn.Create(_sb, label = '--os-pwn') 593 | m._os_access_area_os_smbrelay_ckbtn.Create(_sb, label = '--os-smbrelay') 594 | m._os_access_area_os_bof_ckbtn.Create(_sb, label = '--os-bof') 595 | m._os_access_area_priv_esc_ckbtn.Create(_sb, label = '--priv-esc') 596 | m._os_access_area_msf_path_ckbtn.Create(_sb, label = '本地Metasploit安装路径') 597 | m._os_access_area_msf_path_entry.Create(_sb) 598 | m._os_access_area_msf_path_chooser.Create(_sb, label = '打开') 599 | m._os_access_area_msf_path_chooser.Bind( 600 | EVT_BUTTON, 601 | lambda evt, data = [m._os_access_area_msf_path_entry, '选择 本地Metasploit安装目录']: 602 | self._handlers.set_file_entry_text(evt, data)) 603 | 604 | m._os_access_area_tmp_path_ckbtn.Create(_sb, label = '远程临时目录(绝对路径)') 605 | m._os_access_area_tmp_path_entry.Create(_sb) 606 | 607 | def build_page1_file_registry(self, panel, m): 608 | _sb = m._registry_area 609 | _sb.Create(panel, label = '访问WIN下注册表') 610 | 611 | m._registry_area_reg_ckbtn.Create(_sb, label = '键值操作:') 612 | m._registry_area_reg_choice.Create(_sb, choices = ['--reg-read', '--reg-add', '--reg-del']) 613 | m._registry_area_reg_choice.SetSelection(0) 614 | m._registry_area_reg_key_label.Create(_sb, label = '键路径') 615 | m._registry_area_reg_key_entry.Create(_sb) 616 | m._registry_area_reg_value_label.Create(_sb, label = '键名') 617 | m._registry_area_reg_value_entry.Create(_sb) 618 | m._registry_area_reg_data_label.Create(_sb, label = '键值') 619 | m._registry_area_reg_data_entry.Create(_sb) 620 | m._registry_area_reg_type_label.Create(_sb, label = '键值类型') 621 | m._registry_area_reg_type_entry.Create(_sb) 622 | 623 | def build_page1_other(self, layout): 624 | p = Panel(self) 625 | # p = Scroll(self) # 总有一个标签会被掩盖widget, 只能使用_dummy 626 | m = self.m 627 | 628 | self.build_page1_other_general(p, m) 629 | self.build_page1_other_misc(p, m) 630 | 631 | vbox = layout.other_sizer() 632 | # p.SetSizerAndFit(vbox), 没用~, 最后一个widget还是会被掩盖 633 | p.SetSizer(vbox) 634 | # p.SetupScrolling(scroll_x = False) 635 | return p 636 | 637 | def build_page1_other_general(self, panel, m): 638 | _sb = m._general_area 639 | _sb.Create(panel, label = '通用项') 640 | 641 | m._general_area_check_internet_ckbtn.Create(_sb, label = '检查与目标的网络连接') 642 | m._general_area_fresh_queries_ckbtn.Create(_sb, label = '刷新此次查询') 643 | m._general_area_forms_ckbtn.Create(_sb, label = '获取form表单参数并测试') 644 | m._general_area_parse_errors_ckbtn.Create(_sb, label = '解析并显示响应中的错误信息') 645 | m._misc_area_cleanup_ckbtn.Create(_sb, label = '清理DBMS中的入侵痕迹!') 646 | m._general_area_base64_ckbtn.Create(_sb, label = '--base64') 647 | m._general_area_base64_entry.Create(_sb) 648 | m._general_area_base64_safe_ckbtn.Create(_sb, label = '--base64-safe') 649 | m._general_area_table_prefix_ckbtn.Create(_sb, label = '临时表前缀') 650 | m._general_area_table_prefix_entry.Create(_sb) 651 | # size = ()是以px为单位的, 如果想设成以字符长度为宽, 蛋疼如下~~: 652 | m._general_area_table_prefix_entry.SetInitialSize( 653 | m._general_area_table_prefix_entry.GetSizeFromTextSize( 654 | m._general_area_table_prefix_entry.GetTextExtent("a" * 16).x)) 655 | m._general_area_binary_fields_ckbtn.Create(_sb, label = '有二进制值的字段') 656 | m._general_area_binary_fields_entry.Create(_sb) 657 | m._general_area_binary_fields_entry.SetInitialSize( 658 | m._general_area_binary_fields_entry.GetSizeFromTextSize( 659 | m._general_area_binary_fields_entry.GetTextExtent("a" * 16).x)) 660 | m._general_area_preprocess_ckbtn.Create(_sb, label = '处理请求的脚本') 661 | m._general_area_preprocess_entry.Create(_sb) 662 | m._general_area_preprocess_chooser.Create(_sb, label = '打开') 663 | m._general_area_preprocess_chooser.Bind( 664 | EVT_BUTTON, 665 | lambda evt, data = [m._general_area_preprocess_entry]: 666 | self._handlers.set_file_entry_text(evt, data)) 667 | m._general_area_postprocess_ckbtn.Create(_sb, label = '处理响应的脚本') 668 | m._general_area_postprocess_entry.Create(_sb) 669 | m._general_area_postprocess_chooser.Create(_sb, label = '打开') 670 | m._general_area_postprocess_chooser.Bind( 671 | EVT_BUTTON, 672 | lambda evt, data = [m._general_area_postprocess_entry]: 673 | self._handlers.set_file_entry_text(evt, data)) 674 | 675 | m._general_area_charset_ckbtn.Create(_sb, label = '盲注所用的字符集合') 676 | m._general_area_charset_entry.Create(_sb, value = '0123456789abcdef') 677 | m._general_area_encoding_ckbtn.Create(_sb, label = '字符编码(用于数据获取)') 678 | m._general_area_encoding_entry.Create(_sb, value = 'GBK') 679 | m._general_area_web_root_ckbtn.Create(_sb, label = '远程web的根目录') 680 | m._general_area_web_root_entry.Create(_sb) 681 | m._general_area_scope_ckbtn.Create(_sb, label = '从代理日志过滤出目标(正则)') 682 | m._general_area_scope_entry.Create(_sb) 683 | m._general_area_scope_chooser.Create(_sb, label = '打开') 684 | m._general_area_scope_chooser.Bind( 685 | EVT_BUTTON, 686 | lambda evt, data = [m._general_area_scope_entry]: 687 | self._handlers.set_file_entry_text(evt, data)) 688 | 689 | m._general_area_test_filter_ckbtn.Create(_sb, label = '测试过滤器(从payload/title选择)') 690 | m._general_area_test_filter_entry.Create(_sb) 691 | m._general_area_test_skip_ckbtn.Create(_sb, label = '测试跳过(从payload/title选择)') 692 | m._general_area_test_skip_entry.Create(_sb) 693 | 694 | m._general_area_crawl_ckbtn.Create(_sb, label = '爬网站(的层级/深度)') 695 | m._general_area_crawl_entry.Create(_sb) 696 | m._general_area_crawl_exclude_ckbtn.Create(_sb, label = '爬站时排除(正则)页面') 697 | m._general_area_crawl_exclude_entry.Create(_sb) 698 | self._general_area_hr = wx.StaticLine(_sb) 699 | m._general_area_traffic_file_ckbtn.Create(_sb, label = '转存所有http流量到文本') 700 | m._general_area_traffic_file_entry.Create(_sb) 701 | m._general_area_traffic_file_chooser.Create(_sb, label = '打开') 702 | m._general_area_traffic_file_chooser.Bind( 703 | EVT_BUTTON, 704 | lambda evt, data = [m._general_area_traffic_file_entry]: 705 | self._handlers.set_file_entry_text(evt, data)) 706 | 707 | m._general_area_har_ckbtn.Create(_sb, label = '转存至HAR文件') 708 | m._general_area_har_entry.Create(_sb) 709 | m._general_area_har_chooser.Create(_sb, label = '打开') 710 | m._general_area_har_chooser.Bind( 711 | EVT_BUTTON, 712 | lambda evt, data = [m._general_area_har_entry]: 713 | self._handlers.set_file_entry_text(evt, data)) 714 | 715 | m._general_area_flush_session_ckbtn.Create(_sb, label = '清空目标的会话文件') 716 | m._general_area_dump_format_ckbtn.Create(_sb, label = 'dump结果的文件格式') 717 | m._general_area_dump_format_entry.Create(_sb) 718 | m._general_area_csv_del_ckbtn.Create(_sb, label = '(csv文件的)分隔符') 719 | m._general_area_csv_del_entry.Create(_sb, value = ',') 720 | m._general_area_save_ckbtn.Create(_sb, label = '保存选项至INI文件') 721 | m._general_area_save_entry.Create(_sb) 722 | m._general_area_save_chooser.Create(_sb, label = '打开') 723 | m._general_area_save_chooser.Bind( 724 | EVT_BUTTON, 725 | lambda evt, data = [m._general_area_save_entry]: 726 | self._handlers.set_file_entry_text(evt, data)) 727 | 728 | m._general_area_session_file_ckbtn.Create(_sb, label = '载入会话文件') 729 | m._general_area_session_file_entry.Create(_sb) 730 | m._general_area_session_file_chooser.Create(_sb, label = '打开') 731 | m._general_area_session_file_chooser.Bind( 732 | EVT_BUTTON, 733 | lambda evt, data = [m._general_area_session_file_entry]: 734 | self._handlers.set_file_entry_text(evt, data)) 735 | 736 | m._general_area_output_dir_ckbtn.Create(_sb, label = '指定output目录') 737 | m._general_area_output_dir_entry.Create(_sb) 738 | m._general_area_output_dir_chooser.Create(_sb, label = '打开') 739 | m._general_area_output_dir_chooser.Bind( 740 | EVT_BUTTON, 741 | lambda evt, data = [m._general_area_output_dir_entry, '选择 结果保存在哪']: 742 | self._handlers.set_file_entry_text(evt, data)) 743 | 744 | def build_page1_other_misc(self, panel, m): 745 | _sb = m._misc_area 746 | _sb.Create(panel, label = '杂项') 747 | 748 | m._misc_area_skip_heuristics_ckbtn.Create(_sb, label = '--skip-heuristics') 749 | m._misc_area_skip_waf_ckbtn.Create(_sb, label = '跳过WAF/IPS侦测') 750 | m._misc_area_unstable_ckbtn.Create(_sb, label = '--unstable') 751 | m._misc_area_list_tampers_ckbtn.Create(_sb, label = '列出可用的tamper脚本') 752 | m._misc_area_sqlmap_shell_ckbtn.Create(_sb, label = '打开sqlmap交互shell') 753 | m._misc_area_disable_color_ckbtn.Create(_sb, label = '禁用终端输出的颜色') 754 | m._general_area_eta_ckbtn.Create(_sb, label = '显示剩余时间') 755 | m._misc_area_gpage_ckbtn.Create(_sb, label = 'GOOGLEDORK时的页码') 756 | m._misc_area_gpage_spinbtn.Create(_sb, value = '1', min = 1, max = 100) 757 | m._misc_area_beep_ckbtn.Create(_sb, label = '响铃') 758 | m._misc_area_offline_ckbtn.Create(_sb, label = '离线模式(仅使用本地会话数据)') 759 | m._misc_area_purge_ckbtn.Create(_sb, label = '抹除所有本地记录!') 760 | m._misc_area_dependencies_ckbtn.Create(_sb, label = '检查丢失的(非核心的)sqlmap依赖') 761 | m._misc_area_update_ckbtn.Create(_sb, label = '更新sqlmap') 762 | m._misc_area_alert_ckbtn.Create(_sb, label = '发现注入时运行本地命令:') 763 | m._misc_area_alert_entry.Create(_sb) 764 | m._misc_area_tmp_dir_ckbtn.Create(_sb, label = '本地临时目录') 765 | m._misc_area_tmp_dir_entry.Create(_sb) 766 | m._misc_area_tmp_dir_chooser.Create(_sb, label = '打开') 767 | m._misc_area_tmp_dir_chooser.Bind( 768 | EVT_BUTTON, 769 | lambda evt, data = [m._misc_area_tmp_dir_entry, '选择 本地临时目录']: 770 | self._handlers.set_file_entry_text(evt, data)) 771 | 772 | m._misc_area_answers_ckbtn.Create(_sb, label = '设置交互时的问题答案:') 773 | m._misc_area_answers_entry.Create(_sb, value = 'quit=N,follow=N') 774 | m._misc_area_z_ckbtn.Create(_sb, label = '使用短的助记符') 775 | m._misc_area_z_entry.Create(_sb, value = 'flu,bat,ban,tec=EU...') 776 | m._misc_area_results_file_ckbtn.Create(_sb, label = '--results-file') 777 | m._misc_area_results_file_entry.Create(_sb) 778 | m._misc_area_results_file_chooser.Create(_sb, label = '打开') 779 | m._misc_area_results_file_chooser.Bind( 780 | EVT_BUTTON, 781 | lambda evt, data = [m._misc_area_results_file_entry]: 782 | self._handlers.set_file_entry_text(evt, data)) 783 | # win10里, 最后一行总是会变矮~, 添加一个无用的widget, 抵消一下~ 784 | self._dummy = btn(_sb, 785 | label = '一个无用按钮, 如果报GTK警告, 应该是我没显示出来') 786 | self._dummy.Disable() 787 | 788 | def build_page1_tamper(self, layout): 789 | p = Scroll(self, style = wx.BORDER_THEME) 790 | m = self.m 791 | 792 | # vbox = layout.request_sizer() 793 | # p.SetSizer(vbox) 794 | p.SetupScrolling(scroll_x = False, scrollIntoView = False) 795 | return p 796 | 797 | 798 | def main(): 799 | import time 800 | from widgets import EXPAND, BOTTOM 801 | from model import Model 802 | from handlers import Handler 803 | 804 | start = time.process_time() 805 | app = wx.App() 806 | # -------- 807 | win = wx.Frame(None, title = 'options-wx', size = (800, 600)) 808 | 809 | m = Model(False) 810 | n = Notebook(win, m, Handler(win, m)) 811 | 812 | box = wx.BoxSizer() 813 | box.Add(n, proportion = 1, flag = EXPAND | BOTTOM, border = 5) 814 | win.SetSizerAndFit(box) 815 | 816 | win.Centre() 817 | win.Show() 818 | # -------- 819 | end = time.process_time() 820 | print('loading cost: %.3f Seconds' % (end - start)) 821 | app.MainLoop() 822 | 823 | 824 | if __name__ == '__main__': 825 | main() 826 | -------------------------------------------------------------------------------- /profiler.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash - 2 | # 3 | # 2018-11-01 04:18:20 4 | 5 | kernprof -l -v sqlmap_wx.py 6 | 7 | -------------------------------------------------------------------------------- /screenshots/sqlmap-wx1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/needle-wang/sqlmap-wx/747e8170538f48dd1a75c8ed1b05a6a32d81d368/screenshots/sqlmap-wx1.png -------------------------------------------------------------------------------- /screenshots/sqlmap-wx2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/needle-wang/sqlmap-wx/747e8170538f48dd1a75c8ed1b05a6a32d81d368/screenshots/sqlmap-wx2.png -------------------------------------------------------------------------------- /screenshots/sqlmap-wx3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/needle-wang/sqlmap-wx/747e8170538f48dd1a75c8ed1b05a6a32d81d368/screenshots/sqlmap-wx3.png -------------------------------------------------------------------------------- /screenshots/sqlmap-wx4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/needle-wang/sqlmap-wx/747e8170538f48dd1a75c8ed1b05a6a32d81d368/screenshots/sqlmap-wx4.png -------------------------------------------------------------------------------- /screenshots/sqlmap-wx5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/needle-wang/sqlmap-wx/747e8170538f48dd1a75c8ed1b05a6a32d81d368/screenshots/sqlmap-wx5.png -------------------------------------------------------------------------------- /screenshots/sqlmap-wx6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/needle-wang/sqlmap-wx/747e8170538f48dd1a75c8ed1b05a6a32d81d368/screenshots/sqlmap-wx6.png -------------------------------------------------------------------------------- /screenshots/sqlmap-wx7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/needle-wang/sqlmap-wx/747e8170538f48dd1a75c8ed1b05a6a32d81d368/screenshots/sqlmap-wx7.png -------------------------------------------------------------------------------- /screenshots/sqlmap-wx8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/needle-wang/sqlmap-wx/747e8170538f48dd1a75c8ed1b05a6a32d81d368/screenshots/sqlmap-wx8.png -------------------------------------------------------------------------------- /screenshots/sqlmap-wx9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/needle-wang/sqlmap-wx/747e8170538f48dd1a75c8ed1b05a6a32d81d368/screenshots/sqlmap-wx9.png -------------------------------------------------------------------------------- /session.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # 2018-11-09 15:06:50 4 | 5 | from configparser import ConfigParser 6 | from widgets import cb, tc 7 | 8 | LAST_TMP = 'static/last.tmp' 9 | 10 | 11 | class Session(object): 12 | def __init__(self, m): 13 | ''' 14 | m: model.Model 15 | ''' 16 | self.m = m 17 | 18 | self._cfg = ConfigParser() 19 | # https://stackoverflow.com/questions/19359556/configparser-reads-capital-keys-and-make-them-lower-case 20 | # 所有选项的key, 都会传给optionxform(), 该方法会将key转成小写! 21 | # 将optionxform替换成str, 表示不做转换 22 | self._cfg.optionxform = str 23 | 24 | def save_to_tmp(self): 25 | self._save_to_tmp_target() 26 | self._save_to_tmp_ckbtn() 27 | self._save_to_tmp_entry() 28 | 29 | with open(LAST_TMP, 'w') as f: 30 | self._cfg.write(f) 31 | 32 | def load_from_tmp(self): 33 | # 如果文件不存在, 不会报错 34 | self._cfg.read(LAST_TMP, 'utf8') 35 | 36 | self._load_from_tmp_target() 37 | self._load_from_tmp_ckbtn() 38 | self._load_from_tmp_entry() 39 | 40 | def _save_to_tmp_target(self): 41 | if self._cfg.has_section('Target'): 42 | self._cfg.remove_section('Target') 43 | 44 | self._cfg.add_section('Target') 45 | 46 | _tmp_url = self.m._url_combobox.GetValue().strip() 47 | 48 | if _tmp_url: 49 | self._cfg['Target']['_url_combobox'] = _tmp_url 50 | 51 | def _save_to_tmp_ckbtn(self): 52 | if self._cfg.has_section('CheckButton'): 53 | self._cfg.remove_section('CheckButton') 54 | 55 | self._cfg.add_section('CheckButton') 56 | 57 | _checked = [] 58 | for _i in dir(self.m): 59 | if _i.endswith('ckbtn'): 60 | _tmp_ckbtn = getattr(self.m, _i) 61 | 62 | if isinstance(_tmp_ckbtn, cb) and _tmp_ckbtn.IsChecked(): 63 | _checked.append(_i) 64 | 65 | self._cfg['CheckButton']['checked'] = ','.join(_checked) 66 | 67 | def _save_to_tmp_entry(self): 68 | if self._cfg.has_section('Entry'): 69 | self._cfg.remove_section('Entry') 70 | 71 | self._cfg.add_section('Entry') 72 | 73 | for _i in dir(self.m): 74 | if _i.endswith('entry'): 75 | _tmp_entry = getattr(self.m, _i) 76 | _v = _tmp_entry.GetValue().strip() 77 | if isinstance(_tmp_entry, tc) and _v: 78 | self._cfg['Entry'][_i] = _v 79 | 80 | def _load_from_tmp_target(self): 81 | if not self._cfg.has_section('Target'): 82 | self._cfg.add_section('Target') 83 | 84 | for _i in self._cfg.options('Target'): 85 | if _i == '_url_combobox': 86 | # 不去手动改LAST_TMP, self.m就肯定有_i属性了 87 | _tmp_url = self.m._url_combobox 88 | 89 | if self._cfg['Target'][_i]: 90 | _tmp_url.SetValue(self._cfg['Target'][_i]) 91 | 92 | break 93 | 94 | def _load_from_tmp_ckbtn(self): 95 | if not self._cfg.has_section('CheckButton'): 96 | self._cfg.add_section('CheckButton') 97 | 98 | try: 99 | _checked = self._cfg['CheckButton']['checked'].split(',') 100 | for _i in _checked: 101 | try: 102 | if _i: # _i could be '' 103 | if _i.endswith('_ckbtn'): 104 | _tmp_ckbtn = getattr(self.m, _i) 105 | _tmp_ckbtn.SetValue(True) 106 | # if _i.startswith('tamper_'): 107 | # _tampers[int(_i[len('tamper_'):])].set_active(True) 108 | else: # if _checked = [''], then use default 109 | pass 110 | except AttributeError: 111 | pass 112 | except KeyError: 113 | # if no checked button, then pass 114 | pass 115 | 116 | def _load_from_tmp_entry(self): 117 | if not self._cfg.has_section('Entry'): 118 | self._cfg.add_section('Entry') 119 | 120 | for _i in self._cfg.options('Entry'): 121 | try: 122 | _tmp_entry = getattr(self.m, _i) 123 | 124 | if isinstance(_tmp_entry, tc) and self._cfg['Entry'][_i]: 125 | # print(type(self._cfg['Entry'][_i])) 126 | _tmp_entry.SetValue(self._cfg['Entry'][_i]) 127 | except AttributeError: 128 | pass 129 | 130 | 131 | def main(): 132 | pass 133 | 134 | 135 | if __name__ == '__main__': 136 | main() 137 | -------------------------------------------------------------------------------- /sqlmap_wx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # 2019-05-05 14:50:15 4 | 5 | from subprocess import Popen, PIPE, STDOUT 6 | from threading import Thread 7 | 8 | from widgets import wx, Panel, Scroll, SplitterWindow, btn, cb, nb, st, tc 9 | from widgets import BoxSizer, GridSizer, StaticBoxSizer, SizerFlags, EVT_BUTTON 10 | from widgets import VERTICAL, EXPAND, ALL, TOP, BOTTOM, LEFT, RIGHT, ALIGN_CENTER 11 | 12 | from model import Model 13 | from opts_wx import Notebook 14 | from handlers import Handler, IS_POSIX 15 | from session import Session 16 | from tooltips import Widget_Mesg as INIT_MESG 17 | 18 | 19 | class Window(wx.Frame): 20 | def __init__(self, parent): 21 | super().__init__(parent, title = 'sqlmap-wx') 22 | self.SetIcon(wx.Icon('static/title.ico')) 23 | 24 | self.m = Model() 25 | self._handlers = Handler(self, self.m) # 需要先设置handler, Bind需要它 26 | self.initUI() 27 | self.make_accelerators() # 要先初始化完成后, 才能设全局键 28 | # add tooltips, placeholders 29 | INIT_MESG(self.m) 30 | 31 | self.session = Session(self.m) 32 | self.session.load_from_tmp() 33 | 34 | # @profile 35 | def initUI(self): 36 | p = Panel(self) 37 | 38 | self._target_notebook = nb(p) 39 | self.build_target_notebook(self._target_notebook) 40 | 41 | self.main_notebook = nb(p) 42 | page1 = self.build_page1(self.main_notebook) 43 | page2 = self.build_page2(self.main_notebook) 44 | page3 = self.build_page3(self.main_notebook) 45 | page4 = self.build_page4(self.main_notebook) 46 | page5 = self.build_page5(self.main_notebook) 47 | page6 = self.build_page6(self.main_notebook) 48 | 49 | self.main_notebook.AddPage(page1, '选项区(1)') 50 | self.main_notebook.AddPage(page2, '输出区(2)') 51 | self.main_notebook.AddPage(page3, '日志区(3)') 52 | self.main_notebook.AddPage(page4, 'API区(4)') 53 | self.main_notebook.AddPage(page5, '帮助(H)') 54 | self.main_notebook.AddPage(page6, '关于') 55 | 56 | vbox = BoxSizer(VERTICAL) 57 | vbox.Add(self._target_notebook, flag = EXPAND) 58 | vbox.Add(self.main_notebook, proportion = 1, flag = EXPAND) 59 | p.SetSizer(vbox) 60 | 61 | _frame_sz = BoxSizer() 62 | _frame_sz.Add(p, proportion = 1, flag = EXPAND) 63 | # 使用SetSizerAndFit方法使frame拥有最小size 64 | self.SetSizerAndFit(_frame_sz) 65 | 66 | def make_accelerators(self): 67 | ''' 68 | https://www.blog.pythonlibrary.org/2017/09/28/wxpython-all-about-accelerators/ 69 | 只有最后一次的SetAcceleratorTable会生效 70 | ''' 71 | self.Bind(wx.EVT_CLOSE, self.onExit) 72 | self.Bind(wx.EVT_MENU, self.onCloseByAccel, id = wx.ID_EXIT) 73 | self.accel_entries = [(wx.ACCEL_CTRL, ord('Q'), wx.ID_EXIT), 74 | (wx.ACCEL_CTRL, ord('W'), wx.ID_EXIT)] 75 | 76 | main_note_ks = list('1234H') 77 | for i in range(len(main_note_ks)): 78 | pageid = self.main_notebook.GetPage(i).GetId() 79 | 80 | self.accel_entries.append((wx.ACCEL_ALT, ord(main_note_ks[i]), pageid)) 81 | self.Bind( 82 | wx.EVT_MENU, 83 | lambda evt, page = i: self.main_notebook.SetSelection(page), 84 | id = pageid) 85 | 86 | _note_keys = list('QWERTY') 87 | for i in range(len(_note_keys)): 88 | pageid = self._notebook.GetPage(i).GetId() 89 | 90 | self.accel_entries.append((wx.ACCEL_ALT, ord(_note_keys[i]), pageid)) 91 | self.Bind( 92 | wx.EVT_MENU, 93 | lambda evt, page = i: 94 | self._notebook.SetSelection(page) 95 | if self.main_notebook.GetSelection() == 0 else evt.Skip(), 96 | id = pageid) 97 | # win下, 若焦点没按钮上, 则不响应mnemonic, 只能在这里实现了 98 | _btn_keys = list('ASDF') 99 | btns = self.btn_grid.GetChildren() 100 | for i in range(len(btns)): 101 | btn = btns[i].GetWindow() 102 | btnid = btn.GetId() 103 | 104 | self.accel_entries.append((wx.ACCEL_ALT, ord(_btn_keys[i]), btnid)) 105 | self.Bind( 106 | wx.EVT_MENU, 107 | lambda evt, _btn = btn: # 防止闭包: btn这个变量名跟lambda绑定成一体 108 | self.make_btn_accel(_btn) 109 | if self.main_notebook.GetSelection() == 0 else evt.Skip(), 110 | id = btnid) 111 | 112 | accel_tbl = wx.AcceleratorTable(self.accel_entries) 113 | self.SetAcceleratorTable(accel_tbl) 114 | 115 | def make_btn_accel(self, btn): 116 | ''' 117 | https://stackoverflow.com/questions/12786471/invoking-a-wxpython-evt-button-event-programmatically 118 | https://stackoverflow.com/questions/9765718/wxpython-trigger-checkbox-event-while-setting-its-value-in-the-code 119 | ''' 120 | # 手动emit事件 121 | # evt = wx.CommandEvent(wx.EVT_CHECKBOX.typeId) 122 | # evt.SetEventObject(cb) # 将该evt绑定给cb 123 | # wx.PostEvent(cb, evt) 124 | evt = wx.PyCommandEvent(EVT_BUTTON.typeId, btn.GetId()) 125 | # print(evt) 126 | wx.PostEvent(btn, evt) 127 | 128 | def clear_all_entry(self, event): 129 | m = self.m 130 | for _i in dir(m): 131 | if _i.endswith('entry'): 132 | _tmp_entry = getattr(m, _i) 133 | if isinstance(_tmp_entry, tc) and _tmp_entry is not m.sqlmap_path_entry: 134 | _tmp_entry.SetValue('') 135 | 136 | self._notebook.SetFocus() 137 | 138 | def unselect_all_ckbtn(self, event): 139 | m = self.m 140 | for _i in dir(m): 141 | if _i.endswith('ckbtn'): 142 | _tmp_ckbtn = getattr(m, _i) 143 | if isinstance(_tmp_ckbtn, cb) and _tmp_ckbtn.IsChecked(): 144 | _tmp_ckbtn.SetValue(False) 145 | for _i in m._enum_area_opts_ckbtns: 146 | for _j in _i: 147 | if _j.IsChecked(): 148 | _j.SetValue(False) 149 | 150 | self._notebook.SetFocus() 151 | 152 | def onCloseByAccel(self, event): 153 | ''' 154 | https://stackoverflow.com/questions/49454737/how-can-i-exit-out-of-a-wxpython-application-cleanly 155 | ''' 156 | # print('by accelerator.') 157 | wx.CallAfter(self.Close) 158 | 159 | def onExit(self, event): 160 | ''' 161 | https://www.daniweb.com/programming/software-development/code/216760/verify-exit-dialog-wxpython 162 | ''' 163 | # print('by ALT- or click close button.') 164 | try: 165 | self.session.save_to_tmp() 166 | except Exception as e: 167 | raise e 168 | finally: 169 | event.Skip() 170 | 171 | def build_target_notebook(self, parent): 172 | m = self.m 173 | 174 | m._url_combobox.Create(parent, choices = ['http://www.site.com/vuln.php?id=1']) # style = wx.CB_DROPDOWN 175 | 176 | p2 = Panel(parent) 177 | hbox2 = BoxSizer() 178 | m._burp_logfile.Create(p2) 179 | m._burp_logfile_chooser.Create(p2, label = '打开') 180 | m._burp_logfile_chooser.Bind( 181 | EVT_BUTTON, 182 | lambda evt, data = [m._burp_logfile]: 183 | self._handlers.set_file_entry_text(evt, data)) 184 | 185 | hbox2.Add(m._burp_logfile, proportion = 1, flag = EXPAND) 186 | hbox2.Add(m._burp_logfile_chooser, flag = EXPAND) 187 | p2.SetSizer(hbox2) 188 | 189 | p3 = Panel(parent) 190 | hbox3 = BoxSizer() 191 | m._request_file.Create(p3) 192 | m._request_file_chooser.Create(p3, label = '打开') 193 | m._request_file_chooser.Bind( 194 | EVT_BUTTON, 195 | lambda evt, data = [m._request_file]: 196 | self._handlers.set_file_entry_text(evt, data)) 197 | 198 | hbox3.Add(m._request_file, proportion = 1, flag = EXPAND) 199 | hbox3.Add(m._request_file_chooser, flag = EXPAND) 200 | p3.SetSizer(hbox3) 201 | 202 | p4 = Panel(parent) 203 | hbox4 = BoxSizer() 204 | m._bulkfile.Create(p4) 205 | m._bulkfile_chooser.Create(p4, label = '打开') 206 | m._bulkfile_chooser.Bind( 207 | EVT_BUTTON, 208 | lambda evt, data = [m._bulkfile]: 209 | self._handlers.set_file_entry_text(evt, data)) 210 | 211 | hbox4.Add(m._bulkfile, proportion = 1, flag = EXPAND) 212 | hbox4.Add(m._bulkfile_chooser, flag = EXPAND) 213 | p4.SetSizer(hbox4) 214 | 215 | p5 = Panel(parent) 216 | hbox5 = BoxSizer() 217 | m._configfile.Create(p5) 218 | m._configfile_chooser.Create(p5, label = '打开') 219 | m._configfile_chooser.Bind( 220 | EVT_BUTTON, 221 | lambda evt, data = [m._configfile]: 222 | self._handlers.set_file_entry_text(evt, data)) 223 | 224 | hbox5.Add(m._configfile, proportion = 1, flag = EXPAND) 225 | hbox5.Add(m._configfile_chooser, flag = EXPAND) 226 | p5.SetSizer(hbox5) 227 | 228 | m._google_dork.Create(parent) 229 | m._direct_connect.Create(parent, 230 | value = 'mysql://USER:PASSWORD@DBMS_IP:DBMS_PORT/DATABASE_NAME or ' 231 | 'access://DATABASE_FILEPATH') 232 | 233 | parent.AddPage(m._url_combobox, '目标url') 234 | parent.AddPage(p2, 'burp日志') 235 | parent.AddPage(p3, 'HTTP请求') 236 | parent.AddPage(p4, 'BULKFILE') 237 | parent.AddPage(p5, 'ini文件') 238 | parent.AddPage(m._google_dork, 'GOOGLEDORK') 239 | parent.AddPage(m._direct_connect, '-d DIRECT') 240 | 241 | def build_page1(self, parent): 242 | p = Panel(parent) 243 | m = self.m 244 | 245 | # sqlmap命令语句 246 | cmd_area = StaticBoxSizer(VERTICAL, p, 'A.收集选项 的结果显示在这:') 247 | _cmd_area = cmd_area.GetStaticBox() 248 | 249 | m._cmd_entry.Create(_cmd_area) 250 | 251 | cmd_area.Add(m._cmd_entry, flag = EXPAND) 252 | 253 | # 主构造区 254 | self._notebook = Notebook(p, m, self._handlers) 255 | 256 | # 构造与执行 257 | self.btn_grid = GridSizer(1, 4, 0, 0) 258 | 259 | _build_button = btn(p, label = 'A.收集选项(A)') 260 | _unselect_all_btn = btn(p, label = '反选所有复选框(S)') 261 | _clear_all_entry = btn(p, label = '清空所有输入框(D)') 262 | 263 | _build_button.Bind(EVT_BUTTON, self._handlers.build_all) 264 | _unselect_all_btn.Bind(EVT_BUTTON, self.unselect_all_ckbtn) 265 | _clear_all_entry.Bind(EVT_BUTTON, self.clear_all_entry) 266 | 267 | _run_button = btn(p, label = 'B.开始(F)') 268 | _run_button.Bind(EVT_BUTTON, self._handlers.run_cmdline) 269 | 270 | self.btn_grid.Add(_build_button, flag = ALIGN_CENTER) 271 | self.btn_grid.Add(_unselect_all_btn, flag = ALIGN_CENTER) 272 | self.btn_grid.Add(_clear_all_entry, flag = ALIGN_CENTER) 273 | self.btn_grid.Add(_run_button, flag = ALIGN_CENTER) 274 | 275 | vbox = BoxSizer(VERTICAL) 276 | vbox.Add(cmd_area, flag = EXPAND) 277 | vbox.Add(self._notebook, proportion = 1, flag = EXPAND) 278 | vbox.Add(self.btn_grid, flag = EXPAND) 279 | p.SetSizerAndFit(vbox) 280 | return p 281 | 282 | def build_page2(self, parent): 283 | p = Panel(parent) 284 | st(p, label = 'TODO') 285 | return p 286 | 287 | def build_page3(self, parent): 288 | p = Panel(parent) 289 | m = self.m 290 | 291 | # 多行文本框的默认size太小了 292 | # 默认高度太低, 不指定个高度, 会报 滚动条相关的size 警告 293 | m._page3_log_view.Create(p, 294 | size = (-1, 300), 295 | style = wx.TE_MULTILINE | wx.TE_READONLY) 296 | self._handlers.clear_log_view_buffer(None) 297 | 298 | grid = GridSizer(1, 3, 0, 0) 299 | m._page3_read_target_btn.Create(p, label = '查看target文件') 300 | m._page3_clear_btn.Create(p, label = '清空(&C)') 301 | m._page3_read_log_btn.Create(p, label = '查看log文件') 302 | 303 | m._page3_read_target_btn.Bind(EVT_BUTTON, self._handlers.read_target_file) 304 | m._page3_clear_btn.Bind(EVT_BUTTON, self._handlers.clear_log_view_buffer) 305 | m._page3_read_log_btn.Bind(EVT_BUTTON, self._handlers.read_log_file) 306 | 307 | grid.Add(m._page3_read_target_btn, flag = ALIGN_CENTER) 308 | grid.Add(m._page3_clear_btn, flag = ALIGN_CENTER) 309 | grid.Add(m._page3_read_log_btn, flag = ALIGN_CENTER) 310 | 311 | vbox = BoxSizer(VERTICAL) 312 | vbox.Add(m._page3_log_view, proportion = 1, flag = EXPAND | ALL, border = 10) 313 | vbox.Add(grid, flag = EXPAND) 314 | p.SetSizerAndFit(vbox) 315 | return p 316 | 317 | def build_page4(self, parent): 318 | p = Panel(parent) 319 | m = self.m 320 | 321 | border = SizerFlags().Border(LEFT | RIGHT, 5).Align(ALIGN_CENTER) 322 | proportion_border = SizerFlags(1).Border(LEFT | RIGHT, 5).Align(ALIGN_CENTER) 323 | 324 | row1, row2 = (BoxSizer() for _ in range(2)) 325 | m._page4_api_server_label.Create(p, label = 'REST-JSON API server:') 326 | m._page4_api_server_entry.Create(p, value = '127.0.0.1:8775') 327 | m._page4_admin_token_label.Create(p, label = 'Admin (secret) token:') 328 | m._page4_admin_token_entry.Create(p) 329 | m._page4_admin_token_entry.SetMaxLength(32) 330 | row1.Add(m._page4_api_server_label, border) 331 | row1.Add(m._page4_api_server_entry, proportion_border) 332 | row1.Add(m._page4_admin_token_label, border) 333 | row1.Add(m._page4_admin_token_entry, proportion_border) 334 | 335 | m._page4_task_new_btn.Create(p, label = '创建任务') 336 | m._page4_admin_list_btn.Create(p, label = '显示任务') 337 | m._page4_admin_flush_btn.Create(p, label = '删除所有任务') 338 | m._page4_clear_task_view_btn.Create(p, label = '清空反馈的结果') 339 | m._page4_username_label.Create(p, label = '用户名:') 340 | m._page4_username_entry.Create(p) 341 | m._page4_password_label.Create(p, label = '密码:') 342 | m._page4_password_entry.Create(p) 343 | 344 | _arrow_down = wx.ArtProvider.GetBitmap(wx.ART_GO_DOWN, wx.ART_BUTTON) 345 | m._page4_admin_list_btn.SetBitmap(_arrow_down, dir = RIGHT) 346 | 347 | m._page4_task_new_btn.Bind(EVT_BUTTON, self._handlers.api.task_new) 348 | m._page4_admin_list_btn.Bind(EVT_BUTTON, self._handlers.api.admin_list) 349 | m._page4_admin_flush_btn.Bind(EVT_BUTTON, self._handlers.api.admin_flush) 350 | m._page4_clear_task_view_btn.Bind(EVT_BUTTON, self._handlers.clear_task_view_buffer) 351 | 352 | row2.Add(m._page4_task_new_btn, border) 353 | row2.Add(m._page4_admin_list_btn, border) 354 | row2.Add(m._page4_admin_flush_btn, border) 355 | row2.Add(m._page4_clear_task_view_btn, border) 356 | row2.Add(m._page4_username_label, flag = ALIGN_CENTER | LEFT, border = 200) 357 | row2.Add(m._page4_username_entry, proportion_border) 358 | row2.Add(m._page4_password_label, border) 359 | row2.Add(m._page4_password_entry, proportion_border) 360 | 361 | row3 = SplitterWindow(p, style = wx.SP_LIVE_UPDATE | wx.BORDER_SUNKEN) 362 | # 不能放在SplitVertically后面, 不然gravity会无效 363 | # row3.SetSashGravity(0.5) 364 | row3.SetMinimumPaneSize(400) 365 | 366 | lpane = Scroll(row3) 367 | self._api_admin_list_rows = lpane 368 | 369 | lpane.SetSizer(BoxSizer(VERTICAL)) 370 | 371 | rpane = Panel(row3) 372 | _rbox = BoxSizer(VERTICAL) 373 | 374 | m._page4_option_get_entry.Create(rpane, value = 'url risk level') 375 | _page4_option_set_view_tip = st(rpane, label = 'check optiondict.py of sqlmap about options.') 376 | _options_example = ("{\n" 377 | " 'url': 'http://www.site.com/vuln.php?id=1',\n" 378 | " 'level': 1, 'risk': 1,\n\n" 379 | "}\n") 380 | m._page4_option_set_view.Create(rpane, 381 | value = _options_example, 382 | style = wx.TE_MULTILINE) 383 | _rbox.Add(m._page4_option_get_entry, flag = EXPAND | ALL, border = 2) 384 | _rbox.Add(_page4_option_set_view_tip, flag = ALL, border = 2) 385 | _rbox.Add(m._page4_option_set_view, proportion = 1, flag = EXPAND | ALL, border = 2) 386 | rpane.SetSizer(_rbox) 387 | 388 | row3.SplitVertically(lpane, rpane) 389 | # win下, lpane是灰色的, 将row3设下颜色, 又是兼容代码... 390 | row3.SetBackgroundColour(m._page4_option_set_view.GetBackgroundColour()) 391 | row3.SetSashPosition(lpane.GetMinWidth()) 392 | 393 | m._page4_task_view.Create(p, value = 'response result:\n', style = wx.TE_MULTILINE | wx.TE_READONLY) 394 | 395 | vbox = BoxSizer(VERTICAL) 396 | vbox.Add(row1, flag = EXPAND | ALL, border = 5) 397 | vbox.Add(row2, flag = EXPAND | ALL, border = 5) 398 | vbox.Add(row3, proportion = 1, flag = EXPAND | LEFT | RIGHT, border = 10) 399 | vbox.Add(m._page4_task_view, proportion = 1, flag = EXPAND | ALL, border = 10) 400 | p.SetSizerAndFit(vbox) 401 | return p 402 | 403 | def build_page5(self, parent): 404 | p = Panel(parent) 405 | m = self.m 406 | 407 | self._get_sqlmap_path_btn = btn(p, label = 'sqlmap -hh') 408 | self._get_sqlmap_path_btn.Disable() 409 | # 多行文本框的默认size太小了 410 | # 默认高度太低, 不指定个高度, gtk会报 滚动条相关的size 警告 411 | m._page5_manual_view.Create(p, 412 | size = (-1, 300), 413 | style = wx.TE_MULTILINE | wx.TE_READONLY) 414 | 415 | self._get_sqlmap_path_btn.Bind( 416 | EVT_BUTTON, lambda evt, view = m._page5_manual_view: 417 | self._make_help_thread(evt, view)) 418 | 419 | self._make_help_thread(None, m._page5_manual_view) 420 | 421 | vbox = BoxSizer(VERTICAL) 422 | vbox.Add(self._get_sqlmap_path_btn, flag = TOP | LEFT | BOTTOM, border = 10) 423 | vbox.Add(m._page5_manual_view, proportion = 1, flag = EXPAND | LEFT | RIGHT, border = 10) 424 | p.SetSizerAndFit(vbox) 425 | return p 426 | 427 | def _make_help_thread(self, event, view): 428 | isClick = True if event else False 429 | # 使用线程 填充 帮助标签, 加快启动速度 430 | t = Thread(target = self._set_manual_view, 431 | args = (view, isClick)) 432 | t.daemon = True # 主线程退出了, 当然守护进程也要退出 433 | t.start() 434 | 435 | def _set_manual_view(self, view, isClick): 436 | ''' 437 | 不用多线程能行嘛? 想要获得输出结果就一定会有阻塞的可能! 438 | https://www.jianshu.com/p/11090e197648 439 | https://wiki.gnome.org/Projects/PyGObject/Threading 440 | needle注: 操作的共享对象有两个: _get_sqlmap_path_btn, view 441 | 原则一样, 所有对共用对象的操作都要用CallAfter 442 | 这样写是不是很丑? 443 | 另外, 如果没运行完, 主线程就退出了, 会卡住哦, 属于正常 444 | ''' 445 | if isClick: 446 | wx.CallAfter(self._get_sqlmap_path_btn.Disable) 447 | wx.CallAfter(view.SetValue, '') 448 | 449 | byte_coding = 'utf8' if IS_POSIX else 'gbk' 450 | 451 | # _manual_hh = '/home/needle/bin/output_interval.sh' 452 | # win下的sqlmap -hh有Enter阻塞 453 | _manual_hh = 'echo y|%s -hh' % self._handlers.get_sqlmap_path() 454 | try: 455 | _subp = Popen(_manual_hh, stdout=PIPE, stderr=STDOUT, shell = True) 456 | 457 | for _an_bytes_line_tmp in iter(_subp.stdout.readline, b''): 458 | wx.CallAfter(view.write, 459 | _an_bytes_line_tmp.decode(byte_coding)) 460 | 461 | _subp.wait() 462 | _subp.stdout.close() 463 | except FileNotFoundError as e: 464 | wx.CallAfter(view.write, str(e)) 465 | except Exception as e: 466 | print(e) # 如果主线程结束太快, 会: AssertionError: No wx.App created yet 467 | finally: 468 | wx.CallAfter(self._get_sqlmap_path_btn.Enable) 469 | 470 | if isClick: 471 | # 用gtk时, 如果view不在屏幕上可见, ShowPosition会报错 472 | wx.CallAfter(view.ShowPosition, 0) 473 | wx.CallAfter(self._get_sqlmap_path_btn.SetFocus) 474 | 475 | def build_page6(self, parent): 476 | p = Panel(parent) 477 | 478 | _version = '0.3.3.1' 479 | _timestamp = '2021-01-31 05:12:52' 480 | 481 | _url_self = 'https://github.com/needle-wang/sqlmap-wx' 482 | _url_tutorial1 = 'https://wiki.wxpython.org/' 483 | _url_tutorial2 = 'http://zetcode.com/wxpython/' 484 | _url_api = 'https://wxpython.org/Phoenix/docs/html/index.html' 485 | _url_idea = 'https://github.com/kxcode' 486 | _about_str = f''' 487 | 1. Website: {_url_self} 488 | VERSION: {_version} 489 | {_timestamp} 490 | required: python3.6+, wxPython4.0+, 491 | requests, sqlmap\n 492 | 2. use wxPython4 to recode sqlmap-gtk(driven by PyGObject) 493 | 3. thanks to the idea from sqm(by python2 + tkinter), 494 | author: KINGX, {_url_idea}\n 495 | 4. wxPython tutorial: {_url_tutorial1} 496 | {_url_tutorial2} 497 | 5. wxPython API: {_url_api} 498 | ''' 499 | hbox = BoxSizer() 500 | _page6_about = st(p, label = _about_str) 501 | # 完全居中! 502 | hbox.Add(_page6_about, flag = ALIGN_CENTER) 503 | 504 | vbox = BoxSizer(VERTICAL) 505 | vbox.Add(hbox, proportion = 1, flag = ALIGN_CENTER) 506 | p.SetSizerAndFit(vbox) 507 | return p 508 | 509 | 510 | def main(): 511 | import time 512 | # import wx.lib.mixins.inspection as wit 513 | # app = wit.InspectableApp() 514 | start = time.process_time() 515 | app = wx.App() 516 | # -------- 517 | win = Window(None) 518 | win.Centre() 519 | win.Show() 520 | # -------- 521 | end = time.process_time() 522 | print('loading cost: %.3f Seconds' % (end - start)) 523 | app.MainLoop() 524 | 525 | 526 | if __name__ == '__main__': 527 | main() 528 | -------------------------------------------------------------------------------- /static/title.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/needle-wang/sqlmap-wx/747e8170538f48dd1a75c8ed1b05a6a32d81d368/static/title.ico -------------------------------------------------------------------------------- /tamper/tamper_list: -------------------------------------------------------------------------------- 1 | 0eunion.pyReplaces instances of UNION with e0UNION 2 | apostrophemask.pyReplaces apostrophe character (') with its UTF-8 full width counterpart (e.g. ' -> %EF%BC%87) 3 | apostrophenullencode.pyReplaces apostrophe character (') with its illegal double unicode counterpart (e.g. ' -> %00%27) 4 | appendnullbyte.pyAppends (Access) NULL byte character (%00) at the end of payload 5 | base64encode.pyBase64-encodes all characters in a given payload 6 | between.pyReplaces greater than operator ('>') with 'NOT BETWEEN 0 AND #' and equals operator ('=') with 'BETWEEN # AND #' 7 | binary.pyInjects keyword binary where possible 8 | bluecoat.pyReplaces space character after SQL statement with a valid random blank character. Afterwards replace character '=' with operator LIKE 9 | chardoubleencode.pyDouble URL-encodes all characters in a given payload (not processing already encoded) (e.g. SELECT -> %2553%2545%254C%2545%2543%2554) 10 | charencode.pyURL-encodes all characters in a given payload (not processing already encoded) (e.g. SELECT -> %53%45%4C%45%43%54) 11 | charunicodeencode.pyUnicode-URL-encodes all characters in a given payload (not processing already encoded) (e.g. SELECT -> %u0053%u0045%u004C%u0045%u0043%u0054) 12 | charunicodeescape.pyUnicode-escapes non-encoded characters in a given payload (not processing already encoded) (e.g. SELECT -> \u0053\u0045\u004C\u0045\u0043\u0054) 13 | commalesslimit.pyReplaces (MySQL) instances like 'LIMIT M, N' with 'LIMIT N OFFSET M' counterpart 14 | commalessmid.pyReplaces (MySQL) instances like 'MID(A, B, C)' with 'MID(A FROM B FOR C)' counterpart 15 | commentbeforeparentheses.pyPrepends (inline) comment before parentheses (e.g. ( -> /**/() 16 | concat2concatws.pyReplaces (MySQL) instances like 'CONCAT(A, B)' with 'CONCAT_WS(MID(CHAR(0), 0, 0), A, B)' counterpart 17 | dunion.pyReplaces instances of UNION with DUNION 18 | equaltolike.pyReplaces all occurrences of operator equal ('=') with 'LIKE' counterpart 19 | equaltorlike.pyReplaces all occurrences of operator equal ('=') with 'RLIKE' counterpart 20 | escapequotes.pySlash escape single and double quotes (e.g. ' -> \') 21 | greatest.pyReplaces greater than operator ('>') with 'GREATEST' counterpart 22 | halfversionedmorekeywords.pyAdds (MySQL) versioned comment before each keyword 23 | hex2char.pyReplaces each (MySQL) 0x encoded string with equivalent CONCAT(CHAR(),...) counterpart 24 | htmlencode.pyHTML encode (using code points) all non-alphanumeric characters (e.g. ' -> ') 25 | ifnull2casewhenisnull.pyReplaces instances like 'IFNULL(A, B)' with 'CASE WHEN ISNULL(A) THEN (B) ELSE (A) END' counterpart 26 | ifnull2ifisnull.pyReplaces instances like 'IFNULL(A, B)' with 'IF(ISNULL(A), B, A)' counterpart 27 | informationschemacomment.pyAdd an inline comment (/**/) to the end of all occurrences of (MySQL) "information_schema" identifier 28 | least.pyReplaces greater than operator ('>') with 'LEAST' counterpart 29 | lowercase.pyReplaces each keyword character with lower case value (e.g. SELECT -> select) 30 | luanginx.pyLUA-Nginx WAFs Bypass (e.g. Cloudflare) 31 | misunion.pyReplaces instances of UNION with -.1UNION 32 | modsecurityversioned.pyEmbraces complete query with (MySQL) versioned comment 33 | modsecurityzeroversioned.pyEmbraces complete query with (MySQL) zero-versioned comment 34 | multiplespaces.pyAdds multiple spaces (' ') around SQL keywords 35 | overlongutf8.pyConverts all (non-alphanum) characters in a given payload to overlong UTF8 (not processing already encoded) (e.g. ' -> %C0%A7) 36 | overlongutf8more.pyConverts all characters in a given payload to overlong UTF8 (not processing already encoded) (e.g. SELECT -> %C1%93%C1%85%C1%8C%C1%85%C1%83%C1%94) 37 | percentage.pyAdds a percentage sign ('%') infront of each character (e.g. SELECT -> %S%E%L%E%C%T) 38 | plus2concat.pyReplaces plus operator ('+') with (MsSQL) function CONCAT() counterpart 39 | plus2fnconcat.pyReplaces plus operator ('+') with (MsSQL) ODBC function {fn CONCAT()} counterpart 40 | randomcase.pyReplaces each keyword character with random case value (e.g. SELECT -> SEleCt) 41 | randomcomments.pyAdd random inline comments inside SQL keywords (e.g. SELECT -> S/**/E/**/LECT) 42 | schemasplit.pySplits FROM schema identifiers (e.g. 'testdb.users') with whitespace (e.g. 'testdb 9.e.users') 43 | sleep2getlock.pyReplaces instances like 'SLEEP(5)' with (e.g.) "GET_LOCK('ETgP',5)" 44 | sp_password.pyAppends (MsSQL) function 'sp_password' to the end of the payload for automatic obfuscation from DBMS logs 45 | space2comment.pyReplaces space character (' ') with comments '/**/' 46 | space2dash.pyReplaces space character (' ') with a dash comment ('--') followed by a random string and a new line ('\n') 47 | space2hash.pyReplaces (MySQL) instances of space character (' ') with a pound character ('#') followed by a random string and a new line ('\n') 48 | space2morecomment.pyReplaces (MySQL) instances of space character (' ') with comments '/**_**/' 49 | space2morehash.pyReplaces (MySQL) instances of space character (' ') with a pound character ('#') followed by a random string and a new line ('\n') 50 | space2mssqlblank.pyReplaces (MsSQL) instances of space character (' ') with a random blank character from a valid set of alternate characters 51 | space2mssqlhash.pyReplaces space character (' ') with a pound character ('#') followed by a new line ('\n') 52 | space2mysqlblank.pyReplaces (MySQL) instances of space character (' ') with a random blank character from a valid set of alternate characters 53 | space2mysqldash.pyReplaces space character (' ') with a dash comment ('--') followed by a new line ('\n') 54 | space2plus.pyReplaces space character (' ') with plus ('+') 55 | space2randomblank.pyReplaces space character (' ') with a random blank character from a valid set of alternate characters 56 | substring2leftright.pyReplaces PostgreSQL SUBSTRING with LEFT and RIGHT 57 | symboliclogical.pyReplaces AND and OR logical operators with their symbolic counterparts (&& and ||) 58 | unionalltounion.pyReplaces instances of UNION ALL SELECT with UNION SELECT counterpart 59 | unmagicquotes.pyReplaces quote character (') with a multi-byte combo %BF%27 together with generic comment at the end (to make it work) 60 | uppercase.pyReplaces each keyword character with upper case value (e.g. select -> SELECT) 61 | varnish.pyAppends a HTTP header 'X-originating-IP' to bypass Varnish Firewall 62 | versionedkeywords.pyEncloses each non-function keyword with (MySQL) versioned comment 63 | versionedmorekeywords.pyEncloses each keyword with (MySQL) versioned comment 64 | xforwardedfor.pyAppend a fake HTTP header 'X-Forwarded-For' (and alike) 65 | -------------------------------------------------------------------------------- /tooltips.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # 2018-10-23 05:24:32 4 | 5 | 6 | class Widget_Mesg(object): 7 | def __init__(self, m): 8 | ''' 9 | m: model.Model 10 | ''' 11 | self.set_all_tooltips(m) 12 | self.set_all_placeholders(m) 13 | 14 | def set_all_placeholders(self, m): 15 | # 0.Target 16 | self._set_placeholder('通常是从 目标url/burp日志/HTTP请求... 中任选一项', 17 | m._url_combobox) 18 | self._set_placeholder('-l: Burp或WebScarab代理的日志文件路径(用来解析目标)', 19 | m._burp_logfile) 20 | self._set_placeholder('-r: 包含HTTP请求的的文件路径(如从fiddler中得来的)', 21 | m._request_file) 22 | self._set_placeholder('-m: 给定一个包含多个目标的文本路径', 23 | m._bulkfile) 24 | self._set_placeholder('-c: 从一个本地ini配置文件载入选项', 25 | m._configfile) 26 | self._set_placeholder('-g: 将google dork的结果作为目标url', 27 | m._google_dork) 28 | # OPTIONS(page1) 29 | # 1.Inject(Q) 30 | self._set_placeholder('id,user-agent', 31 | m._inject_area_param_entry) 32 | self._set_placeholder('user-agent,referer', 33 | m._inject_area_skip_entry) 34 | self._set_placeholder('token|session', 35 | m._inject_area_param_exclude_entry) 36 | self._set_placeholder('用于闭合', 37 | m._inject_area_prefix_entry) 38 | self._set_placeholder('user:password', 39 | m._inject_area_dbms_cred_entry) 40 | self._set_placeholder('查询为真时页面出现的字串', 41 | m._detection_area_str_entry) 42 | self._set_placeholder('查询为假时的', 43 | m._detection_area_not_str_entry) 44 | self._set_placeholder('正则匹配查询为真时的字串', 45 | m._detection_area_re_entry) 46 | self._set_placeholder('查询为真时的', 47 | m._detection_area_code_entry) 48 | self._set_placeholder('BEUSTQ', 49 | m._tech_area_tech_entry) 50 | self._set_placeholder('5', 51 | m._tech_area_time_sec_entry) 52 | self._set_placeholder('10', 53 | m._tech_area_union_col_entry) 54 | self._set_placeholder('NULL', 55 | m._tech_area_union_char_entry) 56 | self._set_placeholder('有效表名', 57 | m._tech_area_union_from_entry) 58 | self._set_placeholder('DNS exfiltration', 59 | m._tech_area_dns_entry) 60 | # 2.Request(W) 61 | self._set_placeholder('X-Forwarded-For: 127.0.0.1', 62 | m._request_area_header_entry) 63 | self._set_placeholder('Accept-Language: fr\\nETag: 123', 64 | m._request_area_headers_entry) 65 | self._set_placeholder('post', 66 | m._request_area_method_entry) 67 | self._set_placeholder('&', 68 | m._request_area_param_del_entry) 69 | self._set_placeholder('query=foobar&id=1', 70 | m._request_area_post_entry) 71 | self._set_placeholder('AU=233;SESSIONID=AABBCCDDEEFF;', 72 | m._request_area_cookie_entry) 73 | self._set_placeholder(';', 74 | m._request_area_cookie_del_entry) 75 | self._set_placeholder('Basic, Digest, NTLM or PKI', 76 | m._request_area_auth_type_entry) 77 | self._set_placeholder('name:password', 78 | m._request_area_auth_cred_entry) 79 | self._set_placeholder('PEM cert/private key file', 80 | m._request_area_auth_file_entry) 81 | self._set_placeholder('post', 82 | m._request_area_csrf_method_entry) 83 | self._set_placeholder('token字段名', 84 | m._request_area_csrf_token_entry) 85 | self._set_placeholder('import hashlib;id2=hashlib.md5(id).hexdigest()', 86 | m._request_area_eval_entry) 87 | # 3.Enumerate(E) 88 | self._set_placeholder('不包含该行', 89 | m._limit_area_start_entry) 90 | self._set_placeholder('包含该行', 91 | m._limit_area_stop_entry) 92 | self._set_placeholder('id<3', 93 | m._meta_area_where_entry) 94 | # 4.File(R) 95 | self._set_placeholder('配合 Meterpreter相关 使用', 96 | m._os_access_area_msf_path_entry) 97 | # 5.Other(T) 98 | self._set_placeholder('sqlmap', 99 | m._general_area_table_prefix_entry) 100 | self._set_placeholder('/var/www', 101 | m._general_area_web_root_entry) 102 | self._set_placeholder(r'(www)?\.target\.(com|net|org)', 103 | m._general_area_scope_entry) 104 | self._set_placeholder('ROW', 105 | m._general_area_test_filter_entry) 106 | self._set_placeholder('BENCHMARK', 107 | m._general_area_test_skip_entry) 108 | self._set_placeholder('CSV', 109 | m._general_area_dump_format_entry) 110 | 111 | def set_all_tooltips(self, m): 112 | ''' 113 | m: model.Model 114 | gtk3.24: tooltip of row which contained scale causes flicker.(GTK3's bug?) 115 | ''' 116 | # 0.target 117 | self._set_tooltip('必填项, 从 目标url/burp日志/HTTP请求... 任选一项', 118 | m._url_combobox) 119 | self._set_tooltip('-l: Burp或WebScarab代理的日志文件路径(用来解析目标)', 120 | m._burp_logfile) 121 | self._set_tooltip('-r: 包含HTTP请求的的文件路径(如从fiddler中得来的)', 122 | m._request_file) 123 | self._set_tooltip('-m: 给定一个包含多个目标的文本路径', 124 | m._bulkfile) 125 | self._set_tooltip('-c: 从一个本地ini配置文件载入选项', 126 | m._configfile) 127 | self._set_tooltip('-g: 将google dork的结果作为目标url', 128 | m._google_dork) 129 | # OPTIONS(page1) 130 | # 0._cmd_entry 131 | self._set_tooltip('1.勾选, 填写所需的 选项\n2.点击 收集选项\n3.点击 开始', 132 | m._cmd_entry) 133 | # 1.Inject(Q) 134 | self._set_tooltip('-p\n逗号分隔, 与--level不兼容', 135 | m._inject_area_param_ckbtn, 136 | m._inject_area_param_entry) 137 | self._set_tooltip('--param-filter=P.. Select testable parameter(s) by place (e.g. "POST")', 138 | m._inject_area_param_filter_ckbtn, 139 | m._inject_area_param_filter_combobox) 140 | self._set_tooltip('--skip-static\n' 141 | '另外: sqlmap不会针对(伪)静态网页(/param1/value1/),\n' 142 | '在任意(get/post/header等)可能的注入参数后加*即可', 143 | m._inject_area_skip_static_ckbtn) 144 | self._set_tooltip('--skip=...,...\tSkip testing for given parameter(s)', 145 | m._inject_area_skip_ckbtn, 146 | m._inject_area_skip_entry) 147 | self._set_tooltip('--param-exclude=.. Regexp to exclude parameters from testing', 148 | m._inject_area_param_exclude_ckbtn, 149 | m._inject_area_param_exclude_entry) 150 | self._set_tooltip('--prefix=PREFIX\n' 151 | '当情况复杂(如注入点位于嵌套JOIN查询中)时, 需要手动处理', 152 | m._inject_area_prefix_ckbtn, 153 | m._inject_area_prefix_entry) 154 | self._set_tooltip('--suffix=SUFFIX', 155 | m._inject_area_suffix_ckbtn, 156 | m._inject_area_suffix_entry) 157 | self._set_tooltip('--dbms=DBMS\n很确定是哪种DBMS时使用', 158 | m._inject_area_dbms_ckbtn, 159 | m._inject_area_dbms_combobox) 160 | self._set_tooltip('--dbms-cred=DBMS.. DBMS authentication credentials (user:password)', 161 | m._inject_area_dbms_cred_ckbtn, 162 | m._inject_area_dbms_cred_entry) 163 | self._set_tooltip('--os=OS\n仅在确定知道DBMS所在OS名称时使用', 164 | m._inject_area_os_ckbtn, 165 | m._inject_area_os_entry) 166 | self._set_tooltip('--no-cast\n' 167 | '检索结果时, 默认会将条目cast为字符串类型(优化检索),\n' 168 | '若数据检索有问题(如某些老版本mysql), 才勾选', 169 | m._inject_area_no_cast_ckbtn) 170 | self._set_tooltip('--no-escape\n' 171 | '注: 默认 select \'foobar\'会变成 select char(102)+char(111)...\n' 172 | ' 优点: 转义引号, 绕过; 缺点: 长度变长', 173 | m._inject_area_no_escape_ckbtn) 174 | self._set_tooltip('--invalid-bignum\n' 175 | '真: id=13 假: id=99999999', 176 | m._inject_area_invalid_bignum_ckbtn) 177 | self._set_tooltip('--invalid-logical\n' 178 | '真: id=13 假: id=13 AND 18=19', 179 | m._inject_area_invalid_logic_ckbtn) 180 | self._set_tooltip('--invalid-string\n' 181 | '真: id=13 假: id=akewmc', 182 | m._inject_area_invalid_string_ckbtn) 183 | self._set_tooltip('--string=STRING', 184 | m._detection_area_str_ckbtn, 185 | m._detection_area_str_entry) 186 | self._set_tooltip('--not-string=NOT..', 187 | m._detection_area_not_str_ckbtn, 188 | m._detection_area_not_str_entry) 189 | self._set_tooltip('--regexp=', 190 | m._detection_area_re_ckbtn, 191 | m._detection_area_re_entry) 192 | self._set_tooltip('--code=', 193 | m._detection_area_code_ckbtn, 194 | m._detection_area_code_entry) 195 | self._set_tooltip('--text-only\n' 196 | '有的响应正文包含大量其他内容(如js脚本)\n' 197 | '勾选, 可让sqlmap只关注text文件', 198 | m._detection_area_text_only_ckbtn) 199 | self._set_tooltip('--titles', 200 | m._detection_area_titles_ckbtn) 201 | self._set_tooltip('--smart\n' 202 | '用于批量扫描(如-m时), 快速粗略地寻找明显目标,\n' 203 | '再对 可引发DBMS错误的参数 进一步扫描', 204 | m._detection_area_smart_ckbtn) 205 | self._set_tooltip('--technique=B: Boolean-based blind\n' 206 | ' E: Error-based\n' 207 | ' U: Union query-based\n' 208 | ' S: Stacked queries\n' 209 | ' T: Time-based blind\n' 210 | ' Q: Inline queries', 211 | m._tech_area_tech_ckbtn, 212 | m._tech_area_tech_entry) 213 | self._set_tooltip('--time-sec=默认5秒\n时间盲注时', 214 | m._tech_area_time_sec_ckbtn, 215 | m._tech_area_time_sec_entry) 216 | self._set_tooltip('--union-cols=默认10列\nunion查询时\n' 217 | '提高level, 可增加至50列;\n' 218 | '填12-16表示使用12到16列', 219 | m._tech_area_union_col_ckbtn, 220 | m._tech_area_union_col_entry) 221 | self._set_tooltip('--union-char=默认使用NULL\nunion查询时\n' 222 | '提高level, 会使用随机数\n' 223 | '如--union-char=001', 224 | m._tech_area_union_char_ckbtn, 225 | m._tech_area_union_char_entry) 226 | self._set_tooltip('--union-from=\nunion查询时', 227 | m._tech_area_union_from_ckbtn, 228 | m._tech_area_union_from_entry) 229 | self._set_tooltip('--dns-domain=\n' 230 | '如果控制了目标url的DNS服务器, 才可使用此选项\n' 231 | '这样做只是用来加快数据检索', 232 | m._tech_area_dns_ckbtn, 233 | m._tech_area_dns_entry) 234 | self._set_tooltip('--second-url=', 235 | m._tech_area_second_url_ckbtn, 236 | m._tech_area_second_url_entry) 237 | self._set_tooltip('--second-req=', 238 | m._tech_area_second_req_ckbtn, 239 | m._tech_area_second_req_entry) 240 | self._set_tooltip('sqlmap只会对CHAR()字符串进行混淆,\n' 241 | '不会对其他的payload进行任何混淆.\n' 242 | '要绕过IPS设备或Web应用防火墙(WAF)时, 使用此选项\n' 243 | '此处填写要使用的tamper脚本名\n' 244 | '详见: sqlmap --list-tamper\n回车或逗号拼接', 245 | m._tamper_area_tamper_view) 246 | self._set_tooltip('-o, 开启后会默认:\n' 247 | ' --keep-alive\n --null-connection\n --threads=3', 248 | m._optimize_area_turn_all_ckbtn) 249 | self._set_tooltip('--threads=\n默认为1, 最大为10', 250 | m._optimize_area_thread_num_ckbtn) 251 | self._set_tooltip('--predict-output\n' 252 | '此开关与--threads不兼容', 253 | m._optimize_area_predict_ckbtn) 254 | self._set_tooltip('--keep-alive\n' 255 | '此开关与--proxy不兼容', 256 | m._optimize_area_keep_alive_ckbtn) 257 | self._set_tooltip('--null-connection\n' 258 | '有的请求类型可用来获取响应大小而不用获取响应主体\n' 259 | '两种NULL连接技术: Range和HEAD\n' 260 | '此开关与--text-only不兼容', 261 | m._optimize_area_null_connect_ckbtn) 262 | # -v: 263 | # 0: 只显示Python回源(tracebacks), 错误(error)和关键(criticle)信息。 264 | # 1: 同时显示信息(info)和警告信息(warning)(默认为1) 265 | # 2: 同时显示调试信息(debug) 266 | # 3: 同时显示注入的有效载荷(payloads) 267 | # 4: 同时显示http请求 268 | # 5: 同时显示http响应头 269 | # 6: 同时显示http响应内容 270 | # self._set_tooltip('-v 默认为1', 271 | # m._general_area_verbose_ckbtn) 272 | self._set_tooltip('--fingerprint\n' 273 | '默认就会自动指纹DB,\n' 274 | '开启此开关后, 会发送更多请求, 以确定更精确的DB/OS等版本信息', 275 | m._general_area_finger_ckbtn) 276 | self._set_tooltip('--hex\n' 277 | '响应中的非ASCII数据不准确(如乱码)时, 会将其先编码成16进制格式', 278 | m._general_area_hex_ckbtn) 279 | self._set_tooltip('--batch', 280 | m._general_area_batch_ckbtn) 281 | self._set_tooltip('--wizard(其他选项可不选)', 282 | m._misc_area_wizard_ckbtn) 283 | # 2.请求页面 284 | self._set_tooltip('--random-agent\n' 285 | '默认, User-Agent: sqlmap/1.0-dev, 建议开启!', 286 | m._request_area_random_agent_ckbtn) 287 | self._set_tooltip('--mobile', 288 | m._request_area_mobile_ckbtn) 289 | self._set_tooltip('--user-agent=', 290 | m._request_area_user_agent_ckbtn, 291 | m._request_area_user_agent_entry) 292 | self._set_tooltip('--host=', 293 | m._request_area_host_ckbtn, 294 | m._request_area_host_entry) 295 | self._set_tooltip('--referer=\n' 296 | '默认情况下(即不加此参数)不会发送Referer报头', 297 | m._request_area_referer_ckbtn, 298 | m._request_area_referer_entry) 299 | self._set_tooltip('--header=', 300 | m._request_area_header_ckbtn, 301 | m._request_area_header_entry) 302 | self._set_tooltip('--headers=', 303 | m._request_area_headers_ckbtn, 304 | m._request_area_headers_entry) 305 | self._set_tooltip('--method=', 306 | m._request_area_method_ckbtn, 307 | m._request_area_method_entry) 308 | self._set_tooltip('--param-del=', 309 | m._request_area_param_del_ckbtn, 310 | m._request_area_param_del_entry) 311 | self._set_tooltip('--chunked', 312 | m._request_area_chunked_ckbtn) 313 | self._set_tooltip('--data=\n' 314 | '默认情况下sqlmap发送的是GET请求, 若使用此参数, 会将数据post到目标\n' 315 | '比如搜索框, 表单等会通过post方式发送数据', 316 | m._request_area_post_ckbtn, 317 | m._request_area_post_entry) 318 | self._set_tooltip('--cookie=', 319 | m._request_area_cookie_ckbtn, 320 | m._request_area_cookie_entry) 321 | self._set_tooltip('--cookie-del=', 322 | m._request_area_cookie_del_ckbtn, 323 | m._request_area_cookie_del_entry) 324 | self._set_tooltip('--drop-set-cookie=', 325 | m._request_area_drop_set_cookie_ckbtn) 326 | self._set_tooltip('--live-cookies=', 327 | m._request_area_live_cookies_ckbtn, 328 | m._request_area_live_cookies_entry) 329 | self._set_tooltip('--load-cookies=', 330 | m._request_area_load_cookies_ckbtn, 331 | m._request_area_load_cookies_entry) 332 | self._set_tooltip('--auth-type=Basic, Digest, NTLM or PKI', 333 | m._request_area_auth_type_ckbtn, 334 | m._request_area_auth_type_entry) 335 | self._set_tooltip('--auth-cred=', 336 | m._request_area_auth_cred_ckbtn, 337 | m._request_area_auth_cred_entry) 338 | self._set_tooltip('--auth-file=\n' 339 | 'PEM格式的key_file, 包含你的证书和私钥', 340 | m._request_area_auth_file_ckbtn, 341 | m._request_area_auth_file_entry) 342 | self._set_tooltip('--csrf-method=', 343 | m._request_area_csrf_method_ckbtn, 344 | m._request_area_csrf_method_entry) 345 | self._set_tooltip('--csrf-retries=', 346 | m._request_area_csrf_retries_ckbtn, 347 | m._request_area_csrf_retries_entry) 348 | self._set_tooltip('--csrf-token=\n' 349 | '有的表单中含有隐藏的随机token字段, 来防止csrf攻击', 350 | m._request_area_csrf_token_ckbtn, 351 | m._request_area_csrf_token_entry) 352 | self._set_tooltip('--csrf-url=\n' 353 | '若目标url没有token字段, 则指定有token字段的url', 354 | m._request_area_csrf_url_ckbtn, 355 | m._request_area_csrf_url_entry) 356 | self._set_tooltip('--ignore-timeouts', 357 | m._request_area_ignore_timeouts_ckbtn) 358 | self._set_tooltip('--ignore-redirects', 359 | m._request_area_ignore_redirects_ckbtn) 360 | self._set_tooltip('--ignore-code=', 361 | m._request_area_ignore_code_ckbtn, 362 | m._request_area_ignore_code_entry) 363 | self._set_tooltip('--skip-urlencode\n' 364 | '有的server只接受未编码的参数', 365 | m._request_area_skip_urlencode_ckbtn) 366 | self._set_tooltip('--force-ssl', 367 | m._request_area_force_ssl_ckbtn) 368 | self._set_tooltip('--hpp\n' 369 | '绕过WAF/IP/IDS的一种方法, 对ASP/IIS, ASP.NET/IIS特别有效', 370 | m._request_area_hpp_ckbtn) 371 | self._set_tooltip('--delay=隔几秒发送一个HTTP请求', 372 | m._request_area_delay_ckbtn, 373 | m._request_area_delay_entry) 374 | self._set_tooltip('--timeout=', 375 | m._request_area_timeout_ckbtn, 376 | m._request_area_timeout_entry) 377 | self._set_tooltip('--retries=连接超时后的重连次数', 378 | m._request_area_retries_ckbtn, 379 | m._request_area_retries_entry) 380 | self._set_tooltip('--randomize=', 381 | m._request_area_randomize_ckbtn, 382 | m._request_area_randomize_entry) 383 | self._set_tooltip('--eval=发送请求前先进行额外的处理(python code), 如:\n' 384 | 'import hashlib;id2=hashlib.md5(id).hexdigest()', 385 | m._request_area_eval_ckbtn, 386 | m._request_area_eval_entry) 387 | self._set_tooltip('--safe-url=\n' 388 | '避免错误请求过多而被屏蔽', 389 | m._request_area_safe_url_ckbtn, 390 | m._request_area_safe_url_entry) 391 | self._set_tooltip('--safe-post=', 392 | m._request_area_safe_post_ckbtn, 393 | m._request_area_safe_post_entry) 394 | self._set_tooltip('--safe-req=', 395 | m._request_area_safe_req_ckbtn, 396 | m._request_area_safe_req_entry) 397 | self._set_tooltip('--safe-freq=SAFE.. Test requests between two visits to a given safe URL', 398 | m._request_area_safe_freq_ckbtn, 399 | m._request_area_safe_freq_entry) 400 | self._set_tooltip('--ignore-proxy', 401 | m._request_area_ignore_proxy_ckbtn) 402 | self._set_tooltip('--proxy=', 403 | m._request_area_proxy_ckbtn, 404 | m._request_area_proxy_ip_label, 405 | m._request_area_proxy_ip_entry, 406 | m._request_area_proxy_port_label, 407 | m._request_area_proxy_port_entry) 408 | self._set_tooltip('--proxy-freq=', 409 | m._request_area_proxy_freq_ckbtn, 410 | m._request_area_proxy_freq_entry) 411 | self._set_tooltip('--proxy-file=', 412 | m._request_area_proxy_file_ckbtn, 413 | m._request_area_proxy_file_entry) 414 | self._set_tooltip('--proxy-cred=', 415 | m._request_area_proxy_username_label, 416 | m._request_area_proxy_username_entry, 417 | m._request_area_proxy_password_label, 418 | m._request_area_proxy_password_entry) 419 | self._set_tooltip('--tor', 420 | m._request_area_tor_ckbtn) 421 | self._set_tooltip('--tor-port=', 422 | m._request_area_tor_port_ckbtn, 423 | m._request_area_tor_port_entry) 424 | self._set_tooltip('--tor-type=', 425 | m._request_area_tor_type_ckbtn, 426 | m._request_area_tor_type_entry) 427 | self._set_tooltip('--check-tor', 428 | m._request_area_check_tor_ckbtn) 429 | # 3.Enumerate(E) 430 | self._set_tooltip('-b\t获取version()/@@version', 431 | m._enum_area_opts_ckbtns[0][0]) 432 | self._set_tooltip('--current-user', 433 | m._enum_area_opts_ckbtns[0][1]) 434 | self._set_tooltip('--current-db', 435 | m._enum_area_opts_ckbtns[0][2]) 436 | self._set_tooltip('--hostname', 437 | m._enum_area_opts_ckbtns[0][3]) 438 | self._set_tooltip('--is-dba', 439 | m._enum_area_opts_ckbtns[0][4]) 440 | self._set_tooltip('--users', 441 | m._enum_area_opts_ckbtns[1][0]) 442 | self._set_tooltip('--passwords', 443 | m._enum_area_opts_ckbtns[1][1]) 444 | self._set_tooltip('--privileges\n' 445 | 'sql server会显示每个用户是否为dba, 而不是所有用户的权限列表', 446 | m._enum_area_opts_ckbtns[1][2]) 447 | self._set_tooltip('--roles 仅限oracle可用', 448 | m._enum_area_opts_ckbtns[1][3]) 449 | self._set_tooltip('--dbs', 450 | m._enum_area_opts_ckbtns[1][4]) 451 | self._set_tooltip('--tables\n' 452 | '若不指定-D, 会枚举所有库的表名', 453 | m._enum_area_opts_ckbtns[2][0]) 454 | self._set_tooltip('--columns\n' 455 | '所有列及数据类型, 可与-D, -T, -C配合\n' 456 | '若未指定-D, 则默认为当前库\n' 457 | 'PostgreSQL: 需提供 public 或系统库的名称, 因为不可能枚举其他数据库表', 458 | m._enum_area_opts_ckbtns[2][1]) 459 | self._set_tooltip('--schema\n' 460 | '将枚举所有库, 表, 列及其各自类型\n' 461 | '建议配合--exclude-sysdbs, 数据量可能很大!', 462 | m._enum_area_opts_ckbtns[2][2]) 463 | self._set_tooltip('--count\n' 464 | '表的条目数', 465 | m._enum_area_opts_ckbtns[2][3]) 466 | self._set_tooltip('--comments', 467 | m._enum_area_opts_ckbtns[2][4]) 468 | self._set_tooltip('--dump', 469 | m._dump_area_dump_ckbtn) 470 | self._set_tooltip('--repair', 471 | m._dump_area_repair_ckbtn) 472 | self._set_tooltip('--statements', 473 | m._dump_area_statements_ckbtn) 474 | self._set_tooltip('--search 需配合以下选项使用:\n' 475 | ' -C=逗号分隔的列名: 将在所有DB中的所有表中 搜索指定列名\n' 476 | ' -T=逗号分隔的表名: 将在所有DB中 搜索指定表名\n' 477 | ' -D=逗号分隔的数据库名: 将 搜索指定库名\n', 478 | m._dump_area_search_ckbtn) 479 | self._set_tooltip('--exclude-sysdbs\n注: sql server上master库不视为系统库', 480 | m._dump_area_no_sys_db_ckbtn) 481 | self._set_tooltip('--dump-all', 482 | m._dump_area_dump_all_ckbtn) 483 | self._set_tooltip('--start=', 484 | m._limit_area_start_ckbtn, 485 | m._limit_area_start_entry) 486 | self._set_tooltip('--stop=', 487 | m._limit_area_stop_ckbtn, 488 | m._limit_area_stop_entry) 489 | self._set_tooltip('--first=', 490 | m._blind_area_first_ckbtn, 491 | m._blind_area_first_entry) 492 | self._set_tooltip('--last=', 493 | m._blind_area_last_ckbtn, 494 | m._blind_area_last_entry) 495 | self._set_tooltip('-D DB\n' 496 | 'Oracle: 应指定TABLESPACE_NAME', 497 | m._meta_area_D_ckbtn, 498 | m._meta_area_D_entry) 499 | self._set_tooltip('-T TBL', 500 | m._meta_area_T_ckbtn, 501 | m._meta_area_T_entry) 502 | self._set_tooltip('-C COL', 503 | m._meta_area_C_ckbtn, 504 | m._meta_area_C_entry) 505 | self._set_tooltip('-U USER', 506 | m._meta_area_U_ckbtn, 507 | m._meta_area_U_entry) 508 | self._set_tooltip('-X EXCLUDE', 509 | m._meta_area_X_ckbtn, 510 | m._meta_area_X_entry) 511 | self._set_tooltip('--pivot-column=P\n' 512 | '导出表数据时, 会自动选择合适的具有唯一值的列,一般是主键\n' 513 | '当自动选择的privot列不正确时使用此项', 514 | m._meta_area_pivot_ckbtn, 515 | m._meta_area_pivot_entry) 516 | self._set_tooltip('--where=', 517 | m._meta_area_where_ckbtn, 518 | m._meta_area_where_entry) 519 | self._set_tooltip('--sql-query=QUERY\n' 520 | '如果是select语句, 会返回输出;\n' 521 | '如果目标支持多语句查询, 会使用堆查询技术', 522 | m._runsql_area_sql_query_ckbtn, 523 | m._runsql_area_sql_query_entry) 524 | self._set_tooltip('--sql-shell\n支持TAB补全, 历史记录', 525 | m._runsql_area_sql_shell_ckbtn) 526 | self._set_tooltip('--sql-file=SQLFILE', 527 | m._runsql_area_sql_file_ckbtn, 528 | m._runsql_area_sql_file_entry) 529 | self._set_tooltip('--common-tables\n' 530 | '有时--tables会失败, 通常原因如下:\n' 531 | ' 1.MySQL<5.0: information_schema不存在\n' 532 | ' 2.Access: 系统表(MSysObjects)默认不可读\n' 533 | ' 3.--current-user没有 读取系统表的 权限\n' 534 | ' 1和2的情况才能使用此选项(txt/common-tables.txt)', 535 | m._brute_force_area_common_tables_ckbtn) 536 | self._set_tooltip('--common-columns(见--common-tables)', 537 | m._brute_force_area_common_columns_ckbtn) 538 | self._set_tooltip('--common-files', 539 | m._brute_force_area_common_files_ckbtn) 540 | # 4.File(R) 541 | self._set_tooltip('远程DB所在主机上的文件路径\n' 542 | '前提: 1.MySQL, PostgreSQL或Microsoft SQL Server\n' 543 | ' 2.当前用户有 读取文件的 相关权限', 544 | m._file_read_area_file_read_ckbtn, 545 | m._file_read_area_file_read_entry) 546 | self._set_tooltip('只能查看已下载到本地的文件', 547 | m._file_read_area_file_read_btn) 548 | self._set_tooltip('--udf-inject\tUDF即user-defined function\n' 549 | '将共享库上传到DB所在文件系统上, 来创建用户自定义的函数以供使用', 550 | m._file_write_area_udf_ckbtn) 551 | self._set_tooltip('与--udf-inject配套使用, 可选', 552 | m._file_write_area_shared_lib_ckbtn, 553 | m._file_write_area_shared_lib_entry) 554 | self._set_tooltip('若使用此选项, 则--file-dest为必选项\n' 555 | '前提: 1.MySQL, PostgreSQL或Microsoft SQL Server\n' 556 | ' 2.当前用户有 使用特定函数上传文件的 相关权限', 557 | m._file_write_area_file_write_ckbtn, 558 | m._file_write_area_file_write_entry) 559 | self._set_tooltip('上传到DB服务器中的文件名, 要求是绝对路径, 构造后会有引号!\n' 560 | '与本地文件路径配套使用, 单独勾选无意义', 561 | m._file_write_area_file_dest_ckbtn, 562 | m._file_write_area_file_dest_entry) 563 | self._set_tooltip('--os-cmd=\n' 564 | '前提: 1.MySQL, PostgreSQL或Microsoft SQL Server\n' 565 | ' 2.当前用户有相关权限\n' 566 | 'MySQL或PostgreSQL: 上传包含sys_exec和sys_eval函数的共享库\n' 567 | 'SQL Server: 使用xp_cmdshell存储过程, 若被禁用(>=2005), 就启用它;\n' 568 | ' 若不存在, 就从新创建它', 569 | m._os_access_area_os_cmd_ckbtn, 570 | m._os_access_area_os_cmd_entry) 571 | self._set_tooltip('--os-shell\n支持TAB补全, 历史记录\n' 572 | '若不支持堆查询(如asp/php + MySQL), 且是MySQL(库站未分离!):\n' 573 | ' 会使用SELECT子句INTO OUTFILE在可写目录创建一个web后门来执行命令\n' 574 | ' 支持的web后门类型有: ASP, ASP.NET, JSP, PHP', 575 | m._os_access_area_os_shell_ckbtn) 576 | self._set_tooltip('MySQL和PostgreSQL:\n' 577 | ' 1.通过UDF中的sys_bineval函数 执行Metasploit的shellcode\n' 578 | ' 2.通过UDF中的sys_exec函数 上传并执行Metasploit的stand-alone payload stager\n' 579 | 'Microsoft SQL Server:\n' 580 | ' 1.通过xp_cmdshell储存过程 上传并执行Metasploit的stand-alone payload stager\n', 581 | m._os_access_area_os_pwn_ckbtn) 582 | self._set_tooltip('前提: 最高权限(linux: uid=0, windows: Administrator)\n' 583 | ' 且目标 数据库以Windows管理员身份运行时\n' 584 | ' 通过SMB攻击(MS08-068) 执行Metasploit的shellcode', 585 | m._os_access_area_os_smbrelay_ckbtn) 586 | self._set_tooltip('SQL Server 2000, 2005:\n' 587 | ' 通过sp_replwritetovarbin存储过程(MS09-004)溢出漏洞 执行Metasploit的payload\n' 588 | ' sqlmap用自带的exploit自动绕过DEP内存保护来触发漏洞, 但它依赖Metasploit来生成shellcode, 以便在成功利用后执行', 589 | m._os_access_area_os_bof_ckbtn) 590 | self._set_tooltip('使用Metasploit的getsystem命令来提权\n' 591 | '注: windows:\n' 592 | ' MySQL: 默认以SYSTEM身份运行\n' 593 | ' Server 2000: 默认以SYSTEM身份运行\n' 594 | ' Server 2005-2008: 多数以NETWORK SERVICE, 少数以LOCAL SERVICE身份运行\n' 595 | ' PostgreSQL: 默认以低权限的用户postgres运行\n' 596 | ' linux:\n' 597 | ' PostgreSQL: 默认以低权限的用户postgres运行', 598 | m._os_access_area_priv_esc_ckbtn) 599 | self._set_tooltip('--msf-path=', 600 | m._os_access_area_msf_path_ckbtn, 601 | m._os_access_area_msf_path_entry) 602 | self._set_tooltip('--tmp-path=TMPPATH Remote absolute path of temporary files directory', 603 | m._os_access_area_tmp_path_ckbtn, 604 | m._os_access_area_tmp_path_entry) 605 | self._set_tooltip('--reg-key=', 606 | m._registry_area_reg_key_label, 607 | m._registry_area_reg_key_entry) 608 | self._set_tooltip('--reg-value=', 609 | m._registry_area_reg_value_label, 610 | m._registry_area_reg_value_entry) 611 | self._set_tooltip('--reg-data=', 612 | m._registry_area_reg_data_label, 613 | m._registry_area_reg_data_entry) 614 | self._set_tooltip('--reg-type=', 615 | m._registry_area_reg_type_label, 616 | m._registry_area_reg_type_entry) 617 | # 5.Other(T) 618 | self._set_tooltip('--check-internet', 619 | m._general_area_check_internet_ckbtn) 620 | self._set_tooltip('--fresh-queries', 621 | m._general_area_fresh_queries_ckbtn) 622 | self._set_tooltip('--forms\n' 623 | '若想对 form表单参数 测试:\n' 624 | ' 1.通过某些方式得到请求文件或表单参数\n' 625 | ' 2.可用-r读取请求文件或--data指定表单参数\n' 626 | '但--forms开关: 可让sqlmap自行获取url响应中的表单参数 再做测试\n' 627 | '注: 是所有的表单, 及所有表单参数', 628 | m._general_area_forms_ckbtn) 629 | self._set_tooltip('--parse-errors', 630 | m._general_area_parse_errors_ckbtn) 631 | self._set_tooltip('--cleanup\n' 632 | '清理 DBMS(如临时表sqlmapoutput, udf)及文件系统', 633 | m._misc_area_cleanup_ckbtn) 634 | self._set_tooltip('Parameter(s) containing Base64 encoded data', 635 | m._general_area_base64_ckbtn, 636 | m._general_area_base64_entry) 637 | self._set_tooltip('Use URL and filename safe Base64 alphabet (RFC 4648)', 638 | m._general_area_base64_safe_ckbtn) 639 | self._set_tooltip('--table-prefix=', 640 | m._general_area_table_prefix_ckbtn, 641 | m._general_area_table_prefix_entry) 642 | self._set_tooltip('--binary-fields=\n' 643 | '指定有二进制值的列, 获取该列数据时, 会转成16进制输出', 644 | m._general_area_binary_fields_ckbtn, 645 | m._general_area_binary_fields_entry) 646 | self._set_tooltip('--preprocess=', 647 | m._general_area_preprocess_ckbtn, 648 | m._general_area_preprocess_entry) 649 | self._set_tooltip('--postprocess=', 650 | m._general_area_postprocess_ckbtn, 651 | m._general_area_postprocess_entry) 652 | self._set_tooltip('--charset= 如获取SHA1密文时, 请求数可减小30%', 653 | m._general_area_charset_ckbtn, 654 | m._general_area_charset_entry) 655 | self._set_tooltip('--encoding=', 656 | m._general_area_encoding_ckbtn, 657 | m._general_area_encoding_entry) 658 | self._set_tooltip('--web-root=WEBROOT Web server document root directory (e.g. "/var/www")', 659 | m._general_area_web_root_ckbtn, 660 | m._general_area_web_root_entry) 661 | self._set_tooltip('--scope=SCOPE Regexp to filter targets from provided proxy log', 662 | m._general_area_scope_ckbtn, 663 | m._general_area_scope_entry) 664 | self._set_tooltip('--test-filter=TE.. Select tests by payloads and/or titles (e.g. ROW)', 665 | m._general_area_test_filter_ckbtn, 666 | m._general_area_test_filter_entry) 667 | self._set_tooltip('--test-skip=TEST.. Skip tests by payloads and/or titles (e.g. BENCHMARK)', 668 | m._general_area_test_skip_ckbtn, 669 | m._general_area_test_skip_entry) 670 | self._set_tooltip('--crawl= 并且会收集有漏洞url', 671 | m._general_area_crawl_ckbtn, 672 | m._general_area_crawl_entry) 673 | self._set_tooltip('--crawl-exclude=', 674 | m._general_area_crawl_exclude_ckbtn, 675 | m._general_area_crawl_exclude_entry) 676 | self._set_tooltip('-t TRAFFICFILE Log all HTTP traffic into a textual file', 677 | m._general_area_traffic_file_ckbtn, 678 | m._general_area_traffic_file_entry) 679 | self._set_tooltip('--har=HARFILE Log all HTTP traffic into a HAR file', 680 | m._general_area_har_ckbtn, 681 | m._general_area_har_entry) 682 | self._set_tooltip('--flush-session', 683 | m._general_area_flush_session_ckbtn) 684 | self._set_tooltip('--dump-format=\nCSV(默认), HTML or SQLITE', 685 | m._general_area_dump_format_ckbtn, 686 | m._general_area_dump_format_entry) 687 | self._set_tooltip('--csv-del=', 688 | m._general_area_csv_del_ckbtn, 689 | m._general_area_csv_del_entry) 690 | self._set_tooltip('--save=SAVECONFIG Save options to a configuration INI file', 691 | m._general_area_save_ckbtn, 692 | m._general_area_save_entry) 693 | self._set_tooltip('-s SESSIONFILE Load session from a stored (.sqlite) file', 694 | m._general_area_session_file_ckbtn, 695 | m._general_area_session_file_entry) 696 | self._set_tooltip('--output-dir=', 697 | m._general_area_output_dir_ckbtn, 698 | m._general_area_output_dir_entry) 699 | self._set_tooltip('--skip-heuristics', 700 | m._misc_area_skip_heuristics_ckbtn) 701 | self._set_tooltip('--skip-waf\n' 702 | '默认情况, 会发送一个可疑的payload(所以有时明显没有防护还报警告)\n' 703 | '勾选以禁用此默认机制', 704 | m._misc_area_skip_waf_ckbtn) 705 | self._set_tooltip('--unstable', 706 | m._misc_area_unstable_ckbtn) 707 | self._set_tooltip('--list-tampers', 708 | m._misc_area_list_tampers_ckbtn) 709 | self._set_tooltip('--sqlmap-shell', 710 | m._misc_area_sqlmap_shell_ckbtn) 711 | self._set_tooltip('--disable-coloring', 712 | m._misc_area_disable_color_ckbtn) 713 | self._set_tooltip('--eta', 714 | m._general_area_eta_ckbtn) 715 | self._set_tooltip('--gpage=\n' 716 | '默认使用-g时, 会使用google的前100个URLs', 717 | m._misc_area_gpage_ckbtn) 718 | self._set_tooltip('--beep', 719 | m._misc_area_beep_ckbtn) 720 | self._set_tooltip('--offline', 721 | m._misc_area_offline_ckbtn) 722 | self._set_tooltip('--purge 抹除$HOME/.sqlmap目录', 723 | m._misc_area_purge_ckbtn) 724 | self._set_tooltip('--dependencies', 725 | m._misc_area_dependencies_ckbtn) 726 | self._set_tooltip('--update', 727 | m._misc_area_update_ckbtn) 728 | self._set_tooltip('--alert=ALERT Run host OS command(s) when SQL injection is found', 729 | m._misc_area_alert_ckbtn, 730 | m._misc_area_alert_entry) 731 | self._set_tooltip('--tmp-dir=TMPDIR Local directory for storing temporary files', 732 | m._misc_area_tmp_dir_ckbtn, 733 | m._misc_area_tmp_dir_entry) 734 | self._set_tooltip('--answers=ANSWERS Set question answers(e.g. "quit=N,follow=N")', 735 | m._misc_area_answers_ckbtn, 736 | m._misc_area_answers_entry) 737 | self._set_tooltip('-z MNEMONICS Use short mnemonics (e.g. "flu,bat,ban,tec=EU")', 738 | m._misc_area_z_ckbtn, 739 | m._misc_area_z_entry) 740 | self._set_tooltip('--results-file=R.. Location of CSV results file in multiple targets mode', 741 | m._misc_area_results_file_ckbtn, 742 | m._misc_area_results_file_entry) 743 | # LOG(page3) 744 | self._set_tooltip('不会修改文件', 745 | m._page3_clear_btn) 746 | # SQLMAPAPI(page4) 747 | self._set_tooltip('必填项, 不要加http://', 748 | m._page4_api_server_label, 749 | m._page4_api_server_entry) 750 | self._set_tooltip('必填项, 32位的token', 751 | m._page4_admin_token_label, 752 | m._page4_admin_token_entry) 753 | self._set_tooltip('此处填写要查看的选项(空格分隔), 如: url risk level', 754 | m._page4_option_get_entry) 755 | _api_usage = '''sqlampapi使用步骤: 756 | 1. 在本地或远程运行: ./sqlmapapi.py -s 757 | 2. 填写API区第一行的server和token 758 | 3. 点击 创建任务 759 | 4. 点击 显示任务 后, 下方窗格中会显示任务列表 760 | 5. 在本窗格中填写 python dict类型的选项如: 761 | { 762 | 'url': 'http://www.site.com/vuln.php?id=1', 763 | 'level': 1, 'risk': 1, 764 | } 765 | 6. 点击 设置:(会发送 本窗格的选项dict) 766 | 7. 点击 启动 (设置了选项才有意义) 767 | 注: 1.要查看任务的状态, 点击 显示任务 进行刷新 768 | 2.sqlmapapi支持的选项与sqlmap不兼容, 769 | 且其进行选项设置时, 没有检查选项! 770 | 如果设置了无效的选项, 只能删除任务! 771 | ''' 772 | self._set_tooltip(_api_usage, 773 | m._page4_option_set_view) 774 | 775 | def _set_placeholder(self, placeholder, *widgets): 776 | ''' 777 | wx.TextEntry.SetHint 778 | widgets: 应该都是entry吧? 779 | ''' 780 | for _widget in widgets: 781 | _widget.SetHint(placeholder) 782 | 783 | def _set_tooltip(self, tooltip, *widgets): 784 | ''' 785 | wx.Window.SetToolTip 786 | ''' 787 | for _widget in widgets: 788 | _widget.SetToolTip(tooltip) 789 | 790 | 791 | def main(): 792 | pass 793 | 794 | 795 | if __name__ == '__main__': 796 | main() 797 | -------------------------------------------------------------------------------- /widgets.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # 2019-05-05 21:09:49 4 | import string 5 | import wx 6 | import wx.lib.agw.flatnotebook as FNB 7 | from wx.lib.scrolledpanel import ScrolledPanel 8 | 9 | 10 | class Notebook(FNB.FlatNotebook): 11 | def __init__(self, *args, **kwargs): 12 | # emulate the old wx.Notebook style 13 | _bookStyle = FNB.FNB_NO_X_BUTTON | FNB.FNB_NO_NAV_BUTTONS | FNB.FNB_NODRAG 14 | # 标签不能有焦点, 不然win7下ScrolledPanel不响应滚轮, 15 | # ScrolledPanel needs focus inside to response wheel 16 | # use ribbon style 17 | _bookStyle |= FNB.FNB_NO_TAB_FOCUS | FNB.FNB_RIBBON_TABS 18 | super().__init__(*args, agwStyle=_bookStyle, **kwargs) 19 | self.SetBackgroundColour(wx.WHITE) 20 | 21 | 22 | class CheckBox(wx.CheckBox): 23 | def __init__(self, *args, **kwargs): 24 | super().__init__(*args, **kwargs) 25 | # 一步构造, 不能调用Create 26 | if args or kwargs: 27 | self._set_win_color() 28 | 29 | def Create(self, *args, **kwargs): 30 | # Create方法用于两步构造 31 | super().Create(*args, **kwargs) 32 | self._set_win_color() 33 | 34 | def _set_win_color(self): 35 | # only for win, 背景(240, 240, 240, 255)是灰色, 却要重新设一遍前景才能去灰~ 36 | # 侮辱智商! 脑子都搞蒙了 37 | self.SetForegroundColour(self.GetForegroundColour()) 38 | 39 | self.origin_bgcolor = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) 40 | self.Bind(wx.EVT_CHECKBOX, self.set_color) 41 | 42 | def set_color(self, event): 43 | if self.IsChecked(): 44 | # 跟sqlmap-gtk一样: #f6d488 45 | self.SetBackgroundColour(wx.Colour(246, 212, 136)) 46 | else: 47 | self.SetBackgroundColour(self.origin_bgcolor) 48 | # 这里调不调skip无所谓吧~ 49 | if event: 50 | event.Skip() 51 | 52 | def SetValue(self, state): 53 | super().SetValue(state) 54 | self.set_color(None) 55 | 56 | 57 | class NumCtrl(wx.TextCtrl): 58 | ''' 59 | 正整数 60 | https://stackoverflow.com/questions/1369086/is-it-possible-to-limit-textctrl-to-accept-numbers-only-in-wxpython 61 | ''' 62 | def __init__(self, *args, **kwargs): 63 | super().__init__(*args, **kwargs) 64 | self.Bind(wx.EVT_CHAR, self.onChar) 65 | 66 | def onChar(self, event): 67 | keycode = event.GetKeyCode() 68 | obj = event.GetEventObject() 69 | val = self.GetValue() 70 | # filter unicode characters 71 | if keycode == wx.WXK_NONE: 72 | pass 73 | # allow digits 74 | elif chr(keycode) in string.digits: 75 | event.Skip() 76 | # allow special, non-printable keycodes 77 | elif chr(keycode) not in string.printable: 78 | event.Skip() # allow all other special keycode 79 | return 80 | 81 | 82 | class FloatCtrl(wx.TextCtrl): 83 | ''' 84 | https://stackoverflow.com/questions/1369086/is-it-possible-to-limit-textctrl-to-accept-numbers-only-in-wxpython 85 | ''' 86 | def __init__(self, *args, **kwargs): 87 | super().__init__(*args, **kwargs) 88 | self.Bind(wx.EVT_CHAR, self.onChar) 89 | 90 | def onChar(self, event): 91 | keycode = event.GetKeyCode() 92 | obj = event.GetEventObject() 93 | val = super().GetValue() 94 | # filter unicode characters 95 | if keycode == wx.WXK_NONE: 96 | pass 97 | # allow digits 98 | elif chr(keycode) in string.digits: 99 | event.Skip() 100 | # allow special, non-printable keycodes 101 | elif chr(keycode) not in string.printable: 102 | event.Skip() # allow all other special keycode 103 | # allow '-' for negative numbers 104 | elif chr(keycode) == '-': 105 | # 负号只能是开头 106 | if '-' not in val: 107 | obj.SetValue('-' + val) # 如果是首次输入"-", 则放在开头 108 | obj.SetInsertionPointEnd() 109 | else: 110 | obj.SetValue(val[1:]) # 如果已存在"-", 则去掉 111 | obj.SetInsertionPointEnd() 112 | # allow '.' for float numbers 113 | elif chr(keycode) == '.' and '.' not in val: 114 | event.Skip() 115 | return 116 | 117 | def GetValue(self): 118 | try: 119 | return float(super().GetValue()) 120 | except Exception as e: 121 | return 0.0 122 | 123 | 124 | EVT_BUTTON = wx.EVT_BUTTON 125 | EVT_CHECKBOX = wx.EVT_CHECKBOX 126 | 127 | # nb = wx.Notebook # awful widget, don't use 128 | nb = Notebook 129 | Panel = wx.Panel 130 | StaticBox = wx.StaticBox 131 | SplitterWindow = wx.SplitterWindow 132 | Scroll = ScrolledPanel 133 | 134 | btn = wx.Button 135 | cb = CheckBox 136 | cbb = wx.ComboBox 137 | ci = wx.Choice 138 | nc = NumCtrl 139 | sl = wx.Slider 140 | sp = wx.SpinCtrl 141 | st = wx.StaticText 142 | tc = wx.TextCtrl 143 | 144 | VERTICAL = wx.VERTICAL 145 | HORIZONTAL = wx.HORIZONTAL 146 | 147 | BoxSizer = wx.BoxSizer 148 | GridSizer = wx.GridSizer 149 | StaticBoxSizer = wx.StaticBoxSizer 150 | FlexGridSizer = wx.FlexGridSizer 151 | 152 | EXPAND = wx.EXPAND 153 | ALL = wx.ALL 154 | TOP = wx.TOP 155 | BOTTOM = wx.BOTTOM 156 | LEFT = wx.LEFT 157 | RIGHT = wx.RIGHT 158 | ALIGN_RIGHT = wx.ALIGN_RIGHT 159 | ALIGN_CENTER = wx.ALIGN_CENTER 160 | 161 | SizerFlags = wx.SizerFlags 162 | 163 | 164 | def main(): 165 | pass 166 | 167 | 168 | if __name__ == '__main__': 169 | main() 170 | --------------------------------------------------------------------------------